Decompiled source of Plantations v1.0.0

plugins/Plantations.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using ItemManager;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using PieceManager;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: Guid("E74EB49A-461D-48EA-85BC-F462D60C98C4")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyProduct("Plantations")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("Plantations")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyCompany("Radamanto")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: <54ca3906-ef3e-46f6-b77a-2e89598568e3>RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<815be31a-154e-4472-a809-be812271944a>Embedded]
	internal sealed class <815be31a-154e-4472-a809-be812271944a>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<815be31a-154e-4472-a809-be812271944a>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <f3227ed5-460d-44c0-9306-fa369a7eaa99>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <f3227ed5-460d-44c0-9306-fa369a7eaa99>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <f3227ed5-460d-44c0-9306-fa369a7eaa99>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[<815be31a-154e-4472-a809-be812271944a>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[<815be31a-154e-4472-a809-be812271944a>Embedded]
	[CompilerGenerated]
	internal sealed class <54ca3906-ef3e-46f6-b77a-2e89598568e3>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <54ca3906-ef3e-46f6-b77a-2e89598568e3>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LocalizationManager
{
	[PublicAPI]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static BaseUnityPlugin _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		[method: <c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)]
		[field: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		public static event Action OnLocalizationComplete;

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out var value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out var value2))
			{
				text = value2.Aggregate(text, [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null)
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, EventArgs _) =>
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			_ = plugin;
		}

		public static void LoadLocalizationLater(Localization __instance)
		{
			LoadLocalization(Localization.instance, __instance.GetSelectedLanguage());
		}

		public static void SafeCallLocalizeComplete()
		{
			Localizer.OnLocalizationComplete?.Invoke();
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string[] array = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' });
				if (array.Length >= 2)
				{
					string text = array[1];
					if (dictionary.ContainsKey(text))
					{
						Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
					}
					else
					{
						dictionary[text] = item;
					}
				}
			}
			byte[] array2 = LoadTranslationFromAssembly("English");
			if (array2 == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml.");
			}
			string input = Encoding.UTF8.GetString(array2).TrimStart(new char[1] { '\ufeff' });
			Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(input);
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.TryGetValue(language, out var value))
				{
					text2 = File.ReadAllText(value);
				}
				else
				{
					byte[] array3 = LoadTranslationFromAssembly(language);
					if (array3 != null)
					{
						text2 = Encoding.UTF8.GetString(array3);
					}
				}
			}
			if (text2 == null && dictionary.TryGetValue("English", out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			if (text2 != null)
			{
				text2 = text2.TrimStart(new char[1] { '\ufeff' });
				foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string>(2) { ".json", ".yml" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		[return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static byte[] LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)]
		public static byte[] ReadEmbeddedFileBytes([<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(1)] string resourceFileName, Assembly containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
	public static class LocalizationManagerVersion
	{
		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(1)]
		public const string Version = "1.4.1";
	}
}
namespace Plantations
{
	[HarmonyPatch]
	internal static class Code_PlantationsCultivatorRemoveOnly
	{
		private const string CultivatorPrefabName = "Cultivator";

		private const string CloneSuffix = "(Clone)";

		private const float RemoveWindow = 0.2f;

		private const float RemoveRayDistance = 50f;

		private const float TerrainModifierSearchRange = 2.5f;

		private static readonly HashSet<int> AllowedPieceHashes = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("RD_Dandelion"),
			StringExtensionMethods.GetStableHashCode("RD_Mushroom"),
			StringExtensionMethods.GetStableHashCode("RD_Mushroom_yellow"),
			StringExtensionMethods.GetStableHashCode("RD_RaspberryBush"),
			StringExtensionMethods.GetStableHashCode("RD_BlueberryBush"),
			StringExtensionMethods.GetStableHashCode("RD_thistle"),
			StringExtensionMethods.GetStableHashCode("RD_CloudberryBush"),
			StringExtensionMethods.GetStableHashCode("RD_MushroomSmokePuff"),
			StringExtensionMethods.GetStableHashCode("RD_Fiddlehead")
		};

		private static readonly Dictionary<string, int> NameHashCache = new Dictionary<string, int>(32);

		private static readonly FieldRef<Player, float> RemovePressedTimeRef = AccessTools.FieldRefAccess<Player, float>("m_removePressedTime");

		private static readonly FieldRef<Player, float> LastToolUseTimeRef = AccessTools.FieldRefAccess<Player, float>("m_lastToolUseTime");

		private static readonly FieldRef<Player, float> RemoveDelayRef = AccessTools.FieldRefAccess<Player, float>("m_removeDelay");

		private static readonly FieldRef<Player, int> BuildRemoveDebtRef = AccessTools.FieldRefAccess<Player, int>("m_buildRemoveDebt");

		private static readonly Func<Player, bool> RemovePieceMethod = AccessTools.MethodDelegate<Func<Player, bool>>(AccessTools.DeclaredMethod(typeof(Player), "RemovePiece", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Player, float> GetBuildStaminaMethod = AccessTools.MethodDelegate<Func<Player, float>>(AccessTools.DeclaredMethod(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Player, ItemData, float> GetPlaceDurabilityMethod = AccessTools.MethodDelegate<Func<Player, ItemData, float>>(AccessTools.DeclaredMethod(typeof(Player), "GetPlaceDurability", (Type[])null, (Type[])null), (object)null, true);

		private static int GetPrefabNameStableHash(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return 0;
			}
			if (NameHashCache.TryGetValue(name, out var value))
			{
				return value;
			}
			string text = (name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length) : name);
			value = StringExtensionMethods.GetStableHashCode(text);
			NameHashCache[name] = value;
			return value;
		}

		private static bool IsTrackedPlantPiece(Piece piece)
		{
			if (!Object.op_Implicit((Object)(object)piece))
			{
				return false;
			}
			return AllowedPieceHashes.Contains(GetPrefabNameStableHash(((Object)((Component)piece).gameObject).name));
		}

		private static bool IsCultivator(ItemData item)
		{
			if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			return Utils.GetPrefabName(item.m_dropPrefab) == "Cultivator";
		}

		private static bool TryGetRemoveTarget(Player player, out Piece piece)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			piece = null;
			if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null || (Object)(object)((Character)player).m_eye == (Object)null)
			{
				return false;
			}
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 50f, player.m_removeRayMask))
			{
				return false;
			}
			if (Vector3.Distance(((RaycastHit)(ref val)).point, ((Character)player).m_eye.position) >= player.m_maxPlaceDistance)
			{
				return false;
			}
			piece = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>();
			if (!Object.op_Implicit((Object)(object)piece) && Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponent<Heightmap>()))
			{
				piece = TerrainModifier.FindClosestModifierPieceInRange(((RaycastHit)(ref val)).point, 2.5f);
			}
			return (Object)(object)piece != (Object)null;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static void Player_UpdatePlacement_Postfix(Player __instance, bool takeInput)
		{
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || !takeInput || !((Character)__instance).InPlaceMode() || ((Character)__instance).IsDead())
			{
				return;
			}
			ItemData rightItem = ((Humanoid)__instance).GetRightItem();
			if (!IsCultivator(rightItem) || !TryGetRemoveTarget(__instance, out var piece) || !IsTrackedPlantPiece(piece))
			{
				return;
			}
			if (ZInput.GetButtonUp("Remove") || ZInput.GetButtonUp("JoyRemove"))
			{
				RemovePressedTimeRef.Invoke(__instance) = Time.time;
			}
			float num = RemovePressedTimeRef.Invoke(__instance);
			if (Time.time - num >= 0.2f || Time.time - LastToolUseTimeRef.Invoke(__instance) <= RemoveDelayRef.Invoke(__instance))
			{
				return;
			}
			RemovePressedTimeRef.Invoke(__instance) = -9999f;
			if (!((Character)__instance).HaveStamina(rightItem.m_shared.m_attack.m_attackStamina))
			{
				Hud.instance.StaminaBarEmptyFlash();
			}
			else if (RemovePieceMethod(__instance))
			{
				LastToolUseTimeRef.Invoke(__instance) = Time.time;
				((Character)__instance).AddNoise(50f);
				((Character)__instance).UseStamina(GetBuildStaminaMethod(__instance));
				if ((int)__instance.m_buildPieces.m_skill != 0 && BuildRemoveDebtRef.Invoke(__instance) < 20)
				{
					BuildRemoveDebtRef.Invoke(__instance)++;
				}
				if (rightItem.m_shared.m_useDurability)
				{
					rightItem.m_durability -= GetPlaceDurabilityMethod(__instance, rightItem);
				}
				rightItem.m_shared.m_destroyEffect.Create(((Component)piece).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static bool Player_RemovePiece_Prefix(Player __instance, ref bool __result)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (!TryGetRemoveTarget(__instance, out var piece))
			{
				return true;
			}
			if (!IsTrackedPlantPiece(piece))
			{
				return true;
			}
			ItemData rightItem = ((Humanoid)__instance).GetRightItem();
			if (IsCultivator(rightItem))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class Code_PlantationsPickableConfig
	{
		private sealed class PickableProfile
		{
			public string PiecePrefab;

			public string NormalDropPrefab;

			public string ExtraDropPrefab;

			public Func<int> GetDropAmount;

			public Func<int> GetExtraDropAmount;

			public Func<float> GetExtraDropChance;

			public Func<float> GetRespawnTimeMinutes;

			public Func<bool> GetVanillaSeedDropEnabled;
		}

		private const float RespawnUpdateInterval = 10f;

		private const float RespawnInvokeMinDelay = 1f;

		private const float RespawnInvokeMaxDelay = 2f;

		private static readonly Dictionary<string, PickableProfile> ModProfilesByPiece = new Dictionary<string, PickableProfile>(StringComparer.Ordinal)
		{
			["RD_Dandelion"] = new PickableProfile
			{
				PiecePrefab = "RD_Dandelion",
				NormalDropPrefab = "Dandelion",
				ExtraDropPrefab = "RD_seed_dandelion",
				GetDropAmount = () => PlantationsPlugin.CE_RD_Dandelion_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Dandelion_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_Dandelion_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Dandelion_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Dandelion_VanillaSeedDropEnabled.Value
			},
			["RD_Mushroom"] = new PickableProfile
			{
				PiecePrefab = "RD_Mushroom",
				NormalDropPrefab = "Mushroom",
				ExtraDropPrefab = "RD_red_spore",
				GetDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_Mushroom_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Mushroom_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Mushroom_VanillaSeedDropEnabled.Value
			},
			["RD_Mushroom_yellow"] = new PickableProfile
			{
				PiecePrefab = "RD_Mushroom_yellow",
				NormalDropPrefab = "MushroomYellow",
				ExtraDropPrefab = "RD_yellow_spore",
				GetDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_yellow_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_yellow_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_Mushroom_yellow_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Mushroom_yellow_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Mushroom_yellow_VanillaSeedDropEnabled.Value
			},
			["RD_RaspberryBush"] = new PickableProfile
			{
				PiecePrefab = "RD_RaspberryBush",
				NormalDropPrefab = "Raspberry",
				ExtraDropPrefab = "RD_seed_raspberry",
				GetDropAmount = () => PlantationsPlugin.CE_RD_RaspberryBush_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_RaspberryBush_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_RaspberryBush_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_RaspberryBush_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_RaspberryBush_VanillaSeedDropEnabled.Value
			},
			["RD_BlueberryBush"] = new PickableProfile
			{
				PiecePrefab = "RD_BlueberryBush",
				NormalDropPrefab = "Blueberries",
				ExtraDropPrefab = "RD_seed_blueberry",
				GetDropAmount = () => PlantationsPlugin.CE_RD_BlueberryBush_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_BlueberryBush_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_BlueberryBush_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_BlueberryBush_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_BlueberryBush_VanillaSeedDropEnabled.Value
			},
			["RD_thistle"] = new PickableProfile
			{
				PiecePrefab = "RD_thistle",
				NormalDropPrefab = "Thistle",
				ExtraDropPrefab = "RD_seed_thistle",
				GetDropAmount = () => PlantationsPlugin.CE_RD_thistle_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_thistle_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_thistle_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_thistle_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_thistle_VanillaSeedDropEnabled.Value
			},
			["RD_CloudberryBush"] = new PickableProfile
			{
				PiecePrefab = "RD_CloudberryBush",
				NormalDropPrefab = "Cloudberry",
				ExtraDropPrefab = "RD_seed_cloudberry",
				GetDropAmount = () => PlantationsPlugin.CE_RD_CloudberryBush_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_CloudberryBush_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_CloudberryBush_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_CloudberryBush_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_CloudberryBush_VanillaSeedDropEnabled.Value
			},
			["RD_MushroomSmokePuff"] = new PickableProfile
			{
				PiecePrefab = "RD_MushroomSmokePuff",
				NormalDropPrefab = "MushroomSmokePuff",
				ExtraDropPrefab = "RD_seed_smokepuff",
				GetDropAmount = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled.Value
			},
			["RD_Fiddlehead"] = new PickableProfile
			{
				PiecePrefab = "RD_Fiddlehead",
				NormalDropPrefab = "Fiddleheadfern",
				ExtraDropPrefab = "RD_seed_fiddlehead",
				GetDropAmount = () => PlantationsPlugin.CE_RD_Fiddlehead_DropAmount.Value,
				GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Fiddlehead_ExtraDropAmount.Value,
				GetExtraDropChance = () => PlantationsPlugin.CE_RD_Fiddlehead_ExtraDropChance.Value,
				GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Fiddlehead_RespawnTimeMinutes.Value,
				GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Fiddlehead_VanillaSeedDropEnabled.Value
			}
		};

		private static readonly Dictionary<string, PickableProfile> VanillaProfilesByPiece = new Dictionary<string, PickableProfile>(StringComparer.Ordinal)
		{
			["Pickable_Dandelion"] = ModProfilesByPiece["RD_Dandelion"],
			["Pickable_Mushroom"] = ModProfilesByPiece["RD_Mushroom"],
			["Pickable_Mushroom_yellow"] = ModProfilesByPiece["RD_Mushroom_yellow"],
			["RaspberryBush"] = ModProfilesByPiece["RD_RaspberryBush"],
			["BlueberryBush"] = ModProfilesByPiece["RD_BlueberryBush"],
			["Pickable_Thistle"] = ModProfilesByPiece["RD_thistle"],
			["CloudberryBush"] = ModProfilesByPiece["RD_CloudberryBush"],
			["Pickable_SmokePuff"] = ModProfilesByPiece["RD_MushroomSmokePuff"],
			["Pickable_Fiddlehead"] = ModProfilesByPiece["RD_Fiddlehead"]
		};

		private static string GetPieceName(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return string.Empty;
			}
			string prefabName = Utils.GetPrefabName(obj);
			return string.IsNullOrEmpty(prefabName) ? ((Object)obj).name : prefabName;
		}

		private static bool TryGetModProfile(Pickable pickable, out PickableProfile profile)
		{
			profile = null;
			if ((Object)(object)pickable == (Object)null || !Object.op_Implicit((Object)(object)((Component)pickable).gameObject))
			{
				return false;
			}
			return ModProfilesByPiece.TryGetValue(GetPieceName(((Component)pickable).gameObject), out profile);
		}

		private static bool TryGetVanillaProfile(Pickable pickable, out PickableProfile profile)
		{
			profile = null;
			if ((Object)(object)pickable == (Object)null || !Object.op_Implicit((Object)(object)((Component)pickable).gameObject))
			{
				return false;
			}
			return VanillaProfilesByPiece.TryGetValue(GetPieceName(((Component)pickable).gameObject), out profile);
		}

		private static GameObject GetPrefab(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return null;
			}
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(prefabName) : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
			return Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefabName) : null;
		}

		private static DropTable BuildExtraDropTable(PickableProfile profile)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			int num = profile.GetExtraDropAmount();
			if (num <= 0)
			{
				return null;
			}
			float num2 = Mathf.Clamp01(profile.GetExtraDropChance());
			if (num2 <= 0f)
			{
				return null;
			}
			GameObject prefab = GetPrefab(profile.ExtraDropPrefab);
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return null;
			}
			return new DropTable
			{
				m_dropMin = 1,
				m_dropMax = 1,
				m_dropChance = num2,
				m_oneOfEach = false,
				m_drops = new List<DropData>
				{
					new DropData
					{
						m_item = prefab,
						m_stackMin = num,
						m_stackMax = num,
						m_weight = 1f,
						m_dontScale = false
					}
				}
			};
		}

		private static void ApplyExtraDropsOnly(Pickable pickable, PickableProfile profile)
		{
			if (profile.GetVanillaSeedDropEnabled())
			{
				pickable.m_extraDrops = BuildExtraDropTable(profile);
			}
		}

		private static void ApplyFullModConfig(Pickable pickable, PickableProfile profile)
		{
			GameObject prefab = GetPrefab(profile.NormalDropPrefab);
			if (Object.op_Implicit((Object)(object)prefab))
			{
				pickable.m_itemPrefab = prefab;
			}
			int num = profile.GetDropAmount();
			pickable.m_amount = ((num < 1) ? 1 : num);
			float num2 = profile.GetRespawnTimeMinutes();
			pickable.m_respawnTimeMinutes = ((num2 < 0f) ? 0f : num2);
			pickable.m_extraDrops = BuildExtraDropTable(profile);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Pickable), "Awake")]
		private static void Pickable_Awake_Prefix(Pickable __instance)
		{
			PickableProfile profile2;
			if (TryGetModProfile(__instance, out var profile))
			{
				ApplyFullModConfig(__instance, profile);
			}
			else if (TryGetVanillaProfile(__instance, out profile2))
			{
				ApplyExtraDropsOnly(__instance, profile2);
			}
		}

		[HarmonyPatch(typeof(Pickable), "Awake")]
		[HarmonyPostfix]
		private static void Pickable_Awake_Postfix(Pickable __instance)
		{
			if (TryGetModProfile(__instance, out var _) && !(__instance.m_respawnTimeMinutes <= 0f))
			{
				((MonoBehaviour)__instance).CancelInvoke("UpdateRespawn");
				((MonoBehaviour)__instance).InvokeRepeating("UpdateRespawn", Random.Range(1f, 2f), 10f);
			}
		}
	}
	public static class Registry_Effects
	{
		public static void RegistryEffects()
		{
			GameObject val = PrefabManager.RegisterPrefab("rd_plantations", "vfx_Place_smallitem_rd_plantations");
			GameObject val2 = PrefabManager.RegisterPrefab("rd_plantations", "sfx_build_cultivator_rd_plantations");
			GameObject val3 = PrefabManager.RegisterPrefab("rd_plantations", "vfx_bush_destroyed_rd_plantations");
			GameObject val4 = PrefabManager.RegisterPrefab("rd_plantations", "vfx_bush_leaf_puff_rd_plantations");
			GameObject val5 = PrefabManager.RegisterPrefab("rd_plantations", "sfx_bush_hit_rd_plantations");
			GameObject val6 = PrefabManager.RegisterPrefab("rd_plantations", "sfx_pickable_pick_rd_plantations");
			GameObject val7 = PrefabManager.RegisterPrefab("rd_plantations", "vfx_pickable_pick_rd_plantations");
		}
	}
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[BepInPlugin("radamanto.Plantations", "Plantations", "1.0.0")]
	public class PlantationsPlugin : BaseUnityPlugin
	{
		[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			public bool? Browsable = false;
		}

		[CompilerGenerated]
		private sealed class <ReloadConfigAfterQuietPeriod>d__65 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
			private object <>2__current;

			public float quietSeconds;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
			public PlantationsPlugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				[return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				[return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ReloadConfigAfterQuietPeriod>d__65(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if ((DateTime.UtcNow - <>4__this._lastCfgWriteUtc).TotalSeconds < (double)quietSeconds)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				try
				{
					if (<>4__this._configWatcher == null || !<>4__this._watcherReady)
					{
						return false;
					}
					<>4__this._configWatcher.EnableRaisingEvents = false;
					if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
					{
						((BaseUnityPlugin)<>4__this).Config.Reload();
						<>4__this._ignoreEventsUntilUtc = DateTime.UtcNow.AddSeconds(1.0);
						((BaseUnityPlugin)<>4__this).Config.Save();
					}
				}
				catch
				{
				}
				finally
				{
					if (<>4__this._configWatcher != null)
					{
						<>4__this._configWatcher.EnableRaisingEvents = true;
					}
					<>4__this._reloadScheduled = false;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal const string ModGUID = "radamanto.Plantations";

		internal const string ModName = "Plantations";

		internal const string ModVersion = "1.0.0";

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		internal static ManualLogSource Log;

		public static ConfigEntry<bool> CE_VanillaPlantTimerUI_Enabled;

		public static ConfigEntry<int> CE_RD_Dandelion_DropAmount;

		public static ConfigEntry<int> CE_RD_Dandelion_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_Dandelion_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_Dandelion_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_Dandelion_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_Mushroom_DropAmount;

		public static ConfigEntry<int> CE_RD_Mushroom_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_Mushroom_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_Mushroom_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_Mushroom_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_Mushroom_yellow_DropAmount;

		public static ConfigEntry<int> CE_RD_Mushroom_yellow_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_Mushroom_yellow_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_Mushroom_yellow_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_Mushroom_yellow_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_RaspberryBush_DropAmount;

		public static ConfigEntry<int> CE_RD_RaspberryBush_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_RaspberryBush_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_RaspberryBush_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_RaspberryBush_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_BlueberryBush_DropAmount;

		public static ConfigEntry<int> CE_RD_BlueberryBush_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_BlueberryBush_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_BlueberryBush_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_BlueberryBush_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_thistle_DropAmount;

		public static ConfigEntry<int> CE_RD_thistle_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_thistle_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_thistle_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_thistle_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_CloudberryBush_DropAmount;

		public static ConfigEntry<int> CE_RD_CloudberryBush_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_CloudberryBush_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_CloudberryBush_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_CloudberryBush_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_MushroomSmokePuff_DropAmount;

		public static ConfigEntry<int> CE_RD_MushroomSmokePuff_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_MushroomSmokePuff_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_MushroomSmokePuff_RespawnTimeMinutes;

		public static ConfigEntry<int> CE_RD_Fiddlehead_DropAmount;

		public static ConfigEntry<int> CE_RD_Fiddlehead_ExtraDropAmount;

		public static ConfigEntry<float> CE_RD_Fiddlehead_ExtraDropChance;

		public static ConfigEntry<bool> CE_RD_Fiddlehead_VanillaSeedDropEnabled;

		public static ConfigEntry<float> CE_RD_Fiddlehead_RespawnTimeMinutes;

		private Harmony _harmony = null;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		internal static ConfigSync ConfigSync;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static ConfigEntry<bool> _serverConfigLocked;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private FileSystemWatcher _configWatcher;

		private DateTime _lastCfgWriteUtc = DateTime.MinValue;

		private DateTime _ignoreEventsUntilUtc = DateTime.MinValue;

		private bool _reloadScheduled;

		private bool _watcherReady;

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Localizer.Load();
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("radamanto.Plantations");
			SetupServerSyncAndWatcher();
			CE_VanillaPlantTimerUI_Enabled = Cfg("01 - General", "Vanilla Timer UI", defaultValue: true, "If true, all vanilla Plant-based crops also show the growth timer UI.");
			CE_RD_Dandelion_DropAmount = Cfg("02 - Dandelion", "02.01 - Dandelion Drop Amount", 3, "Dandelion drop amount.");
			CE_RD_Dandelion_ExtraDropAmount = Cfg("02 - Dandelion", "02.02 - Dandelion Seed Drop Amount", 1, "Dandelion seed drop amount.");
			CE_RD_Dandelion_ExtraDropChance = Cfg("02 - Dandelion", "02.03 - Dandelion Seed Drop Chance", 0.05f, "Chance for Dandelion seed to drop. 0 = never, 1 = always.");
			CE_RD_Dandelion_VanillaSeedDropEnabled = Cfg("02 - Dandelion", "02.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Dandelion can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_Dandelion_RespawnTimeMinutes = Cfg("02 - Dandelion", "02.05 - Dandelion Respawn Time Minutes", 60f, "Dandelion respawn time in minutes.");
			CE_RD_Mushroom_DropAmount = Cfg("03 - Mushroom", "03.01 - Mushroom Drop Amount", 3, "Mushroom drop amount.");
			CE_RD_Mushroom_ExtraDropAmount = Cfg("03 - Mushroom", "03.02 - Red Mushroom Spore Drop Amount", 1, "Red Mushroom spore drop amount.");
			CE_RD_Mushroom_ExtraDropChance = Cfg("03 - Mushroom", "03.03 - Red Mushroom Spore Drop Chance", 0.05f, "Chance for Red Mushroom spore to drop. 0 = never, 1 = always.");
			CE_RD_Mushroom_VanillaSeedDropEnabled = Cfg("03 - Mushroom", "03.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Mushroom can also drop red spore. If false, another external way to obtain seeds is required.");
			CE_RD_Mushroom_RespawnTimeMinutes = Cfg("03 - Mushroom", "03.05 - Mushroom Respawn Time Minutes", 60f, "Mushroom respawn time in minutes.");
			CE_RD_Mushroom_yellow_DropAmount = Cfg("04 - Yellow Mushroom", "04.01 - Yellow Mushroom Drop Amount", 3, "Yellow Mushroom drop amount.");
			CE_RD_Mushroom_yellow_ExtraDropAmount = Cfg("04 - Yellow Mushroom", "04.02 - Yellow Mushroom Spore Drop Amount", 1, "Yellow Mushroom spore drop amount.");
			CE_RD_Mushroom_yellow_ExtraDropChance = Cfg("04 - Yellow Mushroom", "04.03 - Yellow Mushroom Spore Drop Chance", 0.05f, "Chance for Yellow Mushroom spore to drop. 0 = never, 1 = always.");
			CE_RD_Mushroom_yellow_VanillaSeedDropEnabled = Cfg("04 - Yellow Mushroom", "04.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Yellow Mushroom can also drop spore. If false, another external way to obtain seeds is required.");
			CE_RD_Mushroom_yellow_RespawnTimeMinutes = Cfg("04 - Yellow Mushroom", "04.05 - Yellow Mushroom Respawn Time Minutes", 60f, "Yellow Mushroom respawn time in minutes.");
			CE_RD_RaspberryBush_DropAmount = Cfg("05 - Raspberry", "05.01 - Raspberry Drop Amount", 3, "Raspberry drop amount.");
			CE_RD_RaspberryBush_ExtraDropAmount = Cfg("05 - Raspberry", "05.02 - Raspberry Seed Drop Amount", 1, "Raspberry seed drop amount.");
			CE_RD_RaspberryBush_ExtraDropChance = Cfg("05 - Raspberry", "05.03 - Raspberry Seed Drop Chance", 0.05f, "Chance for Raspberry seed to drop. 0 = never, 1 = always.");
			CE_RD_RaspberryBush_VanillaSeedDropEnabled = Cfg("05 - Raspberry", "05.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla RaspberryBush can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_RaspberryBush_RespawnTimeMinutes = Cfg("05 - Raspberry", "05.05 - Raspberry Respawn Time Minutes", 60f, "Raspberry respawn time in minutes.");
			CE_RD_BlueberryBush_DropAmount = Cfg("06 - Blueberry", "06.01 - Blueberry Drop Amount", 3, "Blueberry drop amount.");
			CE_RD_BlueberryBush_ExtraDropAmount = Cfg("06 - Blueberry", "06.02 - Blueberry Seed Drop Amount", 1, "Blueberry seed drop amount.");
			CE_RD_BlueberryBush_ExtraDropChance = Cfg("06 - Blueberry", "06.03 - Blueberry Seed Drop Chance", 0.05f, "Chance for Blueberry seed to drop. 0 = never, 1 = always.");
			CE_RD_BlueberryBush_VanillaSeedDropEnabled = Cfg("06 - Blueberry", "06.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla BlueberryBush can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_BlueberryBush_RespawnTimeMinutes = Cfg("06 - Blueberry", "06.05 - Blueberry Respawn Time Minutes", 60f, "Blueberry respawn time in minutes.");
			CE_RD_thistle_DropAmount = Cfg("07 - Thistle", "07.01 - Thistle Drop Amount", 3, "Thistle drop amount.");
			CE_RD_thistle_ExtraDropAmount = Cfg("07 - Thistle", "07.02 - Thistle Seed Drop Amount", 1, "Thistle seed drop amount.");
			CE_RD_thistle_ExtraDropChance = Cfg("07 - Thistle", "07.03 - Thistle Seed Drop Chance", 0.05f, "Chance for Thistle seed to drop. 0 = never, 1 = always.");
			CE_RD_thistle_VanillaSeedDropEnabled = Cfg("07 - Thistle", "07.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Thistle can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_thistle_RespawnTimeMinutes = Cfg("07 - Thistle", "07.05 - Thistle Respawn Time Minutes", 60f, "Thistle respawn time in minutes.");
			CE_RD_CloudberryBush_DropAmount = Cfg("08 - Cloudberry", "08.01 - Cloudberry Drop Amount", 3, "Cloudberry drop amount.");
			CE_RD_CloudberryBush_ExtraDropAmount = Cfg("08 - Cloudberry", "08.02 - Cloudberry Seed Drop Amount", 1, "Cloudberry seed drop amount.");
			CE_RD_CloudberryBush_ExtraDropChance = Cfg("08 - Cloudberry", "08.03 - Cloudberry Seed Drop Chance", 0.05f, "Chance for Cloudberry seed to drop. 0 = never, 1 = always.");
			CE_RD_CloudberryBush_VanillaSeedDropEnabled = Cfg("08 - Cloudberry", "08.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla CloudberryBush can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_CloudberryBush_RespawnTimeMinutes = Cfg("08 - Cloudberry", "08.05 - Cloudberry Respawn Time Minutes", 60f, "Cloudberry respawn time in minutes.");
			CE_RD_MushroomSmokePuff_DropAmount = Cfg("09 - Smoke Puff", "09.01 - Smoke Puff Drop Amount", 3, "Smoke Puff drop amount.");
			CE_RD_MushroomSmokePuff_ExtraDropAmount = Cfg("09 - Smoke Puff", "09.02 - Smoke Puff Seed Drop Amount", 1, "Smoke Puff seed drop amount.");
			CE_RD_MushroomSmokePuff_ExtraDropChance = Cfg("09 - Smoke Puff", "09.03 - Smoke Puff Seed Drop Chance", 0.05f, "Chance for Smoke Puff seed to drop. 0 = never, 1 = always.");
			CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled = Cfg("09 - Smoke Puff", "09.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Smoke Puff can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_MushroomSmokePuff_RespawnTimeMinutes = Cfg("09 - Smoke Puff", "09.05 - Smoke Puff Respawn Time Minutes", 60f, "Smoke Puff respawn time in minutes.");
			CE_RD_Fiddlehead_DropAmount = Cfg("10 - Fiddlehead", "10.01 - Fiddlehead Drop Amount", 3, "Fiddlehead drop amount.");
			CE_RD_Fiddlehead_ExtraDropAmount = Cfg("10 - Fiddlehead", "10.02 - Fiddlehead Seed Drop Amount", 1, "Fiddlehead seed drop amount.");
			CE_RD_Fiddlehead_ExtraDropChance = Cfg("10 - Fiddlehead", "10.03 - Fiddlehead Seed Drop Chance", 0.05f, "Chance for Fiddlehead seed to drop. 0 = never, 1 = always.");
			CE_RD_Fiddlehead_VanillaSeedDropEnabled = Cfg("10 - Fiddlehead", "10.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Fiddlehead can also drop seed. If false, another external way to obtain seeds is required.");
			CE_RD_Fiddlehead_RespawnTimeMinutes = Cfg("10 - Fiddlehead", "10.05 - Fiddlehead Respawn Time Minutes", 60f, "Fiddlehead respawn time in minutes.");
			Registry_Seeds.RegistrySeeds();
			Registry_Plantations.RegistryPlantations();
			Registry_Effects.RegistryEffects();
			_harmony.PatchAll();
		}

		public static bool IsLocalPlayerAdmin()
		{
			return ConfigSync != null && ConfigSync.IsAdmin;
		}

		public void SetupServerSyncAndWatcher()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			bool flag = false;
			try
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
				ConfigSync = new ConfigSync(((BaseUnityPlugin)this).Info.Metadata.GUID)
				{
					DisplayName = ((BaseUnityPlugin)this).Info.Metadata.Name,
					CurrentVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString(),
					MinimumRequiredVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString()
				};
				_serverConfigLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "LockConfiguration", true, new ConfigDescription("If true, the server locks synchronized configs.", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Browsable = false
					}
				}));
				ConfigSync.AddLockingConfigEntry<bool>(_serverConfigLocked);
				SetupConfigWatcher();
				flag = true;
			}
			catch
			{
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
				if (flag)
				{
					((BaseUnityPlugin)this).Config.Save();
				}
			}
		}

		protected ConfigEntry<T> Cfg<[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] T>(string section, string key, T defaultValue, string description, bool synced = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synced);
		}

		private ConfigEntry<T> config<[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			try
			{
				SyncedConfigEntry<T> syncedConfigEntry = ((ConfigSync != null) ? ConfigSync.AddConfigEntry<T>(val2) : null);
				if (syncedConfigEntry != null)
				{
					syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
				}
			}
			catch
			{
			}
			return val2;
		}

		private void SetupConfigWatcher()
		{
			try
			{
				if (_configWatcher != null)
				{
					_configWatcher.Dispose();
				}
				string configPath = Paths.ConfigPath;
				string fileName = Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath);
				_configWatcher = new FileSystemWatcher(configPath, fileName)
				{
					IncludeSubdirectories = false,
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime)
				};
				FileSystemEventHandler onConfigChanged = [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, FileSystemEventArgs __) =>
				{
					if (!(DateTime.UtcNow < _ignoreEventsUntilUtc))
					{
						_lastCfgWriteUtc = DateTime.UtcNow;
						if (!_reloadScheduled)
						{
							_reloadScheduled = true;
							((MonoBehaviour)this).StartCoroutine(ReloadConfigAfterQuietPeriod(0.75f));
						}
					}
				};
				_configWatcher.Changed += onConfigChanged;
				_configWatcher.Created += onConfigChanged;
				_configWatcher.Renamed += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, RenamedEventArgs __) =>
				{
					onConfigChanged(_, __);
				};
				_configWatcher.EnableRaisingEvents = true;
				_watcherReady = true;
			}
			catch
			{
			}
		}

		[IteratorStateMachine(typeof(<ReloadConfigAfterQuietPeriod>d__65))]
		private IEnumerator ReloadConfigAfterQuietPeriod(float quietSeconds)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ReloadConfigAfterQuietPeriod>d__65(0)
			{
				<>4__this = this,
				quietSeconds = quietSeconds
			};
		}
	}
	internal static class Registry_Plantations
	{
		public static void RegistryPlantations()
		{
			BuildPiece buildPiece = new BuildPiece("rd_plantations", "RD_Dandelion");
			buildPiece.Tool.Add("Cultivator");
			buildPiece.Category.Set("Silvestres");
			buildPiece.SpecialProperties.AdminOnly = false;
			buildPiece.SpecialProperties.NoConfig = true;
			buildPiece.RequiredItems.Add("RD_seed_dandelion", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece2 = new BuildPiece("rd_plantations", "RD_Mushroom");
			buildPiece2.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece2.Tool.Add("Cultivator");
			buildPiece2.Category.Set("Silvestres");
			buildPiece2.SpecialProperties.AdminOnly = false;
			buildPiece2.SpecialProperties.NoConfig = true;
			buildPiece2.RequiredItems.Add("RD_red_spore", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece2.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece3 = new BuildPiece("rd_plantations", "RD_Mushroom_yellow");
			buildPiece3.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece3.Tool.Add("Cultivator");
			buildPiece3.Category.Set("Silvestres");
			buildPiece3.SpecialProperties.AdminOnly = false;
			buildPiece3.SpecialProperties.NoConfig = true;
			buildPiece3.RequiredItems.Add("RD_yellow_spore", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece3.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece4 = new BuildPiece("rd_plantations", "RD_RaspberryBush");
			buildPiece4.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece4.Tool.Add("Cultivator");
			buildPiece4.Category.Set("Silvestres");
			buildPiece4.SpecialProperties.AdminOnly = false;
			buildPiece4.SpecialProperties.NoConfig = true;
			buildPiece4.RequiredItems.Add("RD_seed_raspberry", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece4.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece5 = new BuildPiece("rd_plantations", "RD_BlueberryBush");
			buildPiece5.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece5.Tool.Add("Cultivator");
			buildPiece5.Category.Set("Silvestres");
			buildPiece5.SpecialProperties.AdminOnly = false;
			buildPiece5.SpecialProperties.NoConfig = true;
			buildPiece5.RequiredItems.Add("RD_seed_blueberry", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece5.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece6 = new BuildPiece("rd_plantations", "RD_thistle");
			buildPiece6.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece6.Tool.Add("Cultivator");
			buildPiece6.Category.Set("Silvestres");
			buildPiece6.SpecialProperties.AdminOnly = false;
			buildPiece6.SpecialProperties.NoConfig = true;
			buildPiece6.RequiredItems.Add("RD_seed_thistle", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece6.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece7 = new BuildPiece("rd_plantations", "RD_CloudberryBush");
			buildPiece7.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece7.Tool.Add("Cultivator");
			buildPiece7.Category.Set("Silvestres");
			buildPiece7.SpecialProperties.AdminOnly = false;
			buildPiece7.SpecialProperties.NoConfig = true;
			buildPiece7.RequiredItems.Add("RD_seed_cloudberry", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece7.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece8 = new BuildPiece("rd_plantations", "RD_MushroomSmokePuff");
			buildPiece8.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece8.Tool.Add("Cultivator");
			buildPiece8.Category.Set("Silvestres");
			buildPiece8.SpecialProperties.AdminOnly = false;
			buildPiece8.SpecialProperties.NoConfig = true;
			buildPiece8.RequiredItems.Add("RD_seed_smokepuff", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece8.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
			BuildPiece buildPiece9 = new BuildPiece("rd_plantations", "RD_Fiddlehead");
			buildPiece9.Crafting.Set(PieceManager.CraftingTable.None);
			buildPiece9.Tool.Add("Cultivator");
			buildPiece9.Category.Set("Silvestres");
			buildPiece9.SpecialProperties.AdminOnly = false;
			buildPiece9.SpecialProperties.NoConfig = true;
			buildPiece9.RequiredItems.Add("RD_seed_fiddlehead", 1, recover: true);
			MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece9.Prefab, MaterialReplacer.ShaderType.UseUnityShader);
		}
	}
	public static class Registry_Seeds
	{
		public static void RegistrySeeds()
		{
			Item item = new Item("rd_plantations", "RD_red_spore");
			item.Configurable = Configurability.Disabled;
			Item item2 = new Item("rd_plantations", "RD_yellow_spore");
			item2.Configurable = Configurability.Disabled;
			Item item3 = new Item("rd_plantations", "RD_seed_dandelion");
			item3.Configurable = Configurability.Disabled;
			Item item4 = new Item("rd_plantations", "RD_seed_raspberry");
			item4.Configurable = Configurability.Disabled;
			Item item5 = new Item("rd_plantations", "RD_seed_blueberry");
			item5.Configurable = Configurability.Disabled;
			Item item6 = new Item("rd_plantations", "RD_seed_thistle");
			item6.Configurable = Configurability.Disabled;
			Item item7 = new Item("rd_plantations", "RD_seed_cloudberry");
			item7.Configurable = Configurability.Disabled;
			Item item8 = new Item("rd_plantations", "RD_seed_smokepuff");
			item8.Configurable = Configurability.Disabled;
			Item item9 = new Item("rd_plantations", "RD_seed_fiddlehead");
			item9.Configurable = Configurability.Disabled;
		}
	}
	[HarmonyPatch]
	internal static class Code_PlantationsStartEmpty
	{
		private const string CloneSuffix = "(Clone)";

		private static readonly HashSet<int> AllowedPrefabHashes = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("RD_Dandelion"),
			StringExtensionMethods.GetStableHashCode("RD_Mushroom"),
			StringExtensionMethods.GetStableHashCode("RD_Mushroom_yellow"),
			StringExtensionMethods.GetStableHashCode("RD_RaspberryBush"),
			StringExtensionMethods.GetStableHashCode("RD_BlueberryBush"),
			StringExtensionMethods.GetStableHashCode("RD_thistle"),
			StringExtensionMethods.GetStableHashCode("RD_CloudberryBush"),
			StringExtensionMethods.GetStableHashCode("RD_MushroomSmokePuff"),
			StringExtensionMethods.GetStableHashCode("RD_Fiddlehead")
		};

		private static readonly Dictionary<string, int> NameHashCache = new Dictionary<string, int>(32);

		private static readonly FieldRef<Pickable, ZNetView> PickableNViewRef = AccessTools.FieldRefAccess<Pickable, ZNetView>("m_nview");

		private static int GetPrefabNameStableHash(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return 0;
			}
			if (NameHashCache.TryGetValue(name, out var value))
			{
				return value;
			}
			string text = (name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length) : name);
			value = StringExtensionMethods.GetStableHashCode(text);
			NameHashCache[name] = value;
			return value;
		}

		private static bool IsAllowed(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return false;
			}
			return AllowedPrefabHashes.Contains(GetPrefabNameStableHash(((Object)obj).name));
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Pickable), "Awake")]
		private static void Pickable_Awake_Postfix(Pickable __instance)
		{
			if ((Object)(object)__instance == (Object)null || !IsAllowed(((Component)__instance).gameObject) || __instance.m_respawnTimeMinutes <= 0f)
			{
				return;
			}
			ZNetView val = PickableNViewRef.Invoke(__instance);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner())
			{
				ZDO zDO = val.GetZDO();
				if (zDO != null && !zDO.GetBool(ZDOVars.s_picked, false) && zDO.GetLong(ZDOVars.s_pickedTime, 0L) == 0)
				{
					__instance.SetPicked(true);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Code_PlantationsTimerUI
	{
		private const string TokenReady = "$ve_plantation_ready";

		private const string TokenReadyIn = "$ve_plantation_ready_in";

		private static readonly HashSet<string> AllowedPickables = new HashSet<string> { "RD_Dandelion", "RD_Mushroom", "RD_Mushroom_yellow", "RD_RaspberryBush", "RD_BlueberryBush", "RD_thistle", "RD_CloudberryBush", "RD_MushroomSmokePuff", "RD_Fiddlehead" };

		private static readonly HashSet<string> AllowedPlants = new HashSet<string> { "RD_Dandelion", "RD_Mushroom", "RD_Mushroom_yellow", "RD_RaspberryBush", "RD_BlueberryBush", "RD_thistle", "RD_CloudberryBush", "RD_MushroomSmokePuff", "RD_Fiddlehead" };

		private static readonly FieldRef<Plant, ZNetView> PlantNViewRef = AccessTools.FieldRefAccess<Plant, ZNetView>("m_nview");

		private static readonly FieldRef<Pickable, ZNetView> PickableNViewRef = AccessTools.FieldRefAccess<Pickable, ZNetView>("m_nview");

		private static readonly FieldRef<Pickable, bool> PickablePickedRef = AccessTools.FieldRefAccess<Pickable, bool>("m_picked");

		private static readonly Func<Plant, float> PlantGetGrowTime = AccessTools.MethodDelegate<Func<Plant, float>>(AccessTools.DeclaredMethod(typeof(Plant), "GetGrowTime", (Type[])null, (Type[])null), (object)null, true);

		private static string GetPieceName(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return string.Empty;
			}
			string prefabName = Utils.GetPrefabName(obj);
			return string.IsNullOrEmpty(prefabName) ? ((Object)obj).name : prefabName;
		}

		private static bool IsAllowedPickable(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return false;
			}
			return AllowedPickables.Contains(GetPieceName(obj));
		}

		private static bool IsAllowedPlant(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return false;
			}
			string pieceName = GetPieceName(obj);
			if (AllowedPlants.Contains(pieceName))
			{
				return true;
			}
			return PlantationsPlugin.CE_VanillaPlantTimerUI_Enabled.Value;
		}

		private static string FormatTime(double seconds)
		{
			if (seconds <= 0.0)
			{
				return string.Empty;
			}
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			if (timeSpan.TotalHours >= 1.0)
			{
				return $"{timeSpan.Hours:D2}h {timeSpan.Minutes:D2}m {timeSpan.Seconds:D2}s";
			}
			if (timeSpan.TotalMinutes >= 1.0)
			{
				return $"{timeSpan.Minutes:D2}m {timeSpan.Seconds:D2}s";
			}
			return $"{timeSpan.Seconds:D2}s";
		}

		private static string GetReadyLine()
		{
			return string.Format("<color=#00FF00>{0}</color>", Localization.instance.Localize("$ve_plantation_ready"));
		}

		private static string GetRemainingLine(double remainingSeconds)
		{
			return string.Format(Localization.instance.Localize("$ve_plantation_ready_in"), FormatTime(remainingSeconds));
		}

		[HarmonyPatch(typeof(Pickable), "GetHoverText")]
		[HarmonyPostfix]
		private static void Pickable_GetHoverText_Postfix(Pickable __instance, ref string __result)
		{
			if ((Object)(object)__instance == (Object)null || !IsAllowedPickable(((Component)__instance).gameObject) || __instance.m_respawnTimeMinutes <= 0f || !PickablePickedRef.Invoke(__instance))
			{
				return;
			}
			ZNetView val = PickableNViewRef.Invoke(__instance);
			ZDO val2 = (Object.op_Implicit((Object)(object)val) ? val.GetZDO() : null);
			if (val2 != null && !((Object)(object)ZNet.instance == (Object)null))
			{
				long @long = val2.GetLong(ZDOVars.s_pickedTime, 0L);
				if (@long > 0)
				{
					DateTime dateTime = new DateTime(@long);
					TimeSpan timeSpan = ZNet.instance.GetTime() - dateTime;
					double num = (double)__instance.m_respawnTimeMinutes * 60.0;
					double num2 = num - timeSpan.TotalSeconds;
					string arg = Localization.instance.Localize(__instance.GetHoverName());
					__result = ((num2 <= 0.0) ? $"{arg}\n{GetReadyLine()}" : $"{arg}\n{GetRemainingLine(num2)}");
				}
			}
		}

		[HarmonyPatch(typeof(Plant), "GetHoverText")]
		[HarmonyPostfix]
		private static void Plant_GetHoverText_Postfix(Plant __instance, ref string __result)
		{
			if ((Object)(object)__instance == (Object)null || !IsAllowedPlant(((Component)__instance).gameObject))
			{
				return;
			}
			ZNetView val = PlantNViewRef.Invoke(__instance);
			ZDO val2 = (Object.op_Implicit((Object)(object)val) ? val.GetZDO() : null);
			if (val2 != null && !((Object)(object)ZNet.instance == (Object)null))
			{
				long @long = val2.GetLong(ZDOVars.s_plantTime, 0L);
				if (@long > 0)
				{
					DateTime dateTime = new DateTime(@long);
					double totalSeconds = (ZNet.instance.GetTime() - dateTime).TotalSeconds;
					float num = PlantGetGrowTime(__instance);
					double num2 = (double)num - totalSeconds;
					string text = ((num2 <= 0.0) ? GetReadyLine() : GetRemainingLine(num2));
					__result = (string.IsNullOrEmpty(__result) ? text : $"{__result}\n{text}");
				}
			}
		}
	}
}
namespace PieceManager
{
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[PublicAPI]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	public static class MaterialReplacer
	{
		[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)]
		public enum ShaderType
		{
			PieceShader,
			VegetationShader,
			RockShader,
			RugShader,
			GrassShader,
			CustomCreature,
			UseUnityShader
		}

		private static readonly Dictionary<GameObject, bool> ObjectToSwap;

		private static readonly Dictionary<string, Material> OriginalMaterials;

		private static readonly Dictionary<GameObject, ShaderType> ObjectsForShaderReplace;

		private static readonly HashSet<Shader> CachedShaders;

		private static bool hasRun;

		static MaterialReplacer()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			CachedShaders = new HashSet<Shader>();
			hasRun = false;
			OriginalMaterials = new Dictionary<string, Material>();
			ObjectToSwap = new Dictionary<GameObject, bool>();
			ObjectsForShaderReplace = new Dictionary<GameObject, ShaderType>();
			Harmony val = new Harmony("org.bepinex.helpers.PieceManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZoneSystem), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(MaterialReplacer), "ReplaceAllMaterialsWithOriginal", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void RegisterGameObjectForShaderSwap(GameObject go, ShaderType type)
		{
			if (!ObjectsForShaderReplace.ContainsKey(go))
			{
				ObjectsForShaderReplace.Add(go, type);
			}
		}

		public static void RegisterGameObjectForMatSwap(GameObject go, bool isJotunnMock = false)
		{
			if (!((Object)(object)go == (Object)null) && !ObjectToSwap.ContainsKey(go))
			{
				ObjectToSwap.Add(go, isJotunnMock);
			}
		}

		private static void GetAllMaterials()
		{
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material val in array)
			{
				OriginalMaterials[((Object)val).name] = val;
			}
		}

		[HarmonyPriority(700)]
		private static void ReplaceAllMaterialsWithOriginal()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)SystemInfo.graphicsDeviceType == 4 || hasRun)
			{
				return;
			}
			if (OriginalMaterials.Count == 0)
			{
				GetAllMaterials();
			}
			foreach (KeyValuePair<GameObject, bool> item in ObjectToSwap)
			{
				GameObject key = item.Key;
				bool value = item.Value;
				ProcessGameObjectMaterials(key, value);
			}
			AssetBundle[] array = Resources.FindObjectsOfTypeAll<AssetBundle>();
			AssetBundle[] array2 = array;
			foreach (AssetBundle val in array2)
			{
				IEnumerable<Shader> enumerable3;
				try
				{
					IEnumerable<Shader> enumerable2;
					if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val))
					{
						IEnumerable<Shader> enumerable = val.LoadAllAssets<Shader>();
						enumerable2 = enumerable;
					}
					else
					{
						enumerable2 = from shader in ((IEnumerable<string>)val.GetAllAssetNames()).Select((Func<string, Shader>)val.LoadAsset<Shader>)
							where (Object)(object)shader != (Object)null
							select shader;
					}
					enumerable3 = enumerable2;
				}
				catch (Exception)
				{
					continue;
				}
				if (enumerable3 == null)
				{
					continue;
				}
				foreach (Shader item2 in enumerable3)
				{
					CachedShaders.Add(item2);
				}
			}
			foreach (KeyValuePair<GameObject, ShaderType> item3 in ObjectsForShaderReplace)
			{
				GameObject key2 = item3.Key;
				ShaderType value2 = item3.Value;
				ProcessGameObjectShaders(key2, value2);
			}
			hasRun = true;
		}

		private static void ProcessGameObjectMaterials(GameObject go, bool isJotunnMock)
		{
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				Material[] sharedMaterials = val.sharedMaterials.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Material material) => ((Object)(object)material == (Object)null) ? null : ReplaceMaterial(material, isJotunnMock)).ToArray();
				val.sharedMaterials = sharedMaterials;
			}
		}

		private static Material ReplaceMaterial(Material originalMaterial, bool isJotunnMock)
		{
			if ((Object)(object)originalMaterial == (Object)null)
			{
				return null;
			}
			string text = (isJotunnMock ? "JVLmock_" : "_REPLACE_");
			if (!((Object)originalMaterial).name.StartsWith(text, StringComparison.Ordinal))
			{
				return originalMaterial;
			}
			string text2 = ((Object)originalMaterial).name.Replace(" (Instance)", "").Replace(text, "");
			if (OriginalMaterials.TryGetValue(text2, out var value))
			{
				return value;
			}
			Debug.LogWarning((object)("No suitable material found to replace: " + text2));
			return originalMaterial;
		}

		private static void ProcessGameObjectShaders(GameObject go, ShaderType shaderType)
		{
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				foreach (Material val2 in sharedMaterials)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						val2.shader = GetShaderForType(val2.shader, shaderType, ((Object)val2.shader).name);
					}
				}
			}
		}

		private static Shader GetShaderForType(Shader orig, ShaderType shaderType, string originalShaderName)
		{
			return (Shader)(shaderType switch
			{
				ShaderType.PieceShader => FindShaderWithName(orig, "Custom/Piece"), 
				ShaderType.VegetationShader => FindShaderWithName(orig, "Custom/Vegetation"), 
				ShaderType.RockShader => FindShaderWithName(orig, "Custom/StaticRock"), 
				ShaderType.RugShader => FindShaderWithName(orig, "Custom/Rug"), 
				ShaderType.GrassShader => FindShaderWithName(orig, "Custom/Grass"), 
				ShaderType.CustomCreature => FindShaderWithName(orig, "Custom/Creature"), 
				ShaderType.UseUnityShader => FindShaderWithName(orig, ((Object)(object)FindShaderWithName(orig, originalShaderName) != (Object)null) ? originalShaderName : "ToonDeferredShading2017"), 
				_ => FindShaderWithName(orig, "Standard"), 
			});
		}

		public static Shader FindShaderWithName(Shader origShader, string name)
		{
			foreach (Shader cachedShader in CachedShaders)
			{
				if (((Object)cachedShader).name == name)
				{
					return cachedShader;
				}
			}
			return origShader;
		}
	}
	[PublicAPI]
	public enum CraftingTable
	{
		None,
		[InternalName("piece_workbench")]
		Workbench,
		[InternalName("piece_cauldron")]
		Cauldron,
		[InternalName("forge")]
		Forge,
		[InternalName("piece_artisanstation")]
		ArtisanTable,
		[InternalName("piece_stonecutter")]
		StoneCutter,
		[InternalName("piece_magetable")]
		MageTable,
		[InternalName("blackforge")]
		BlackForge,
		[InternalName("piece_preptable")]
		FoodPreparationTable,
		[InternalName("piece_MeadCauldron")]
		MeadKetill,
		Custom
	}
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	public class InternalName : Attribute
	{
		public readonly string internalName;

		public InternalName(string internalName)
		{
			this.internalName = internalName;
		}
	}
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[PublicAPI]
	public class ExtensionList
	{
		public readonly List<ExtensionConfig> ExtensionStations = new List<ExtensionConfig>();

		public void Set(CraftingTable table, int maxStationDistance = 5)
		{
			ExtensionStations.Add(new ExtensionConfig
			{
				Table = table,
				maxStationDistance = maxStationDistance
			});
		}

		public void Set(string customTable, int maxStationDistance = 5)
		{
			ExtensionStations.Add(new ExtensionConfig
			{
				Table = CraftingTable.Custom,
				custom = customTable,
				maxStationDistance = maxStationDistance
			});
		}
	}
	public struct ExtensionConfig
	{
		public CraftingTable Table;

		public float maxStationDistance;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		public string custom;
	}
	[PublicAPI]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	public class CraftingStationList
	{
		public readonly List<CraftingStationConfig> Stations = new List<CraftingStationConfig>();

		public void Set(CraftingTable table)
		{
			Stations.Add(new CraftingStationConfig
			{
				Table = table
			});
		}

		public void Set(string customTable)
		{
			Stations.Add(new CraftingStationConfig
			{
				Table = CraftingTable.Custom,
				custom = customTable
			});
		}
	}
	public struct CraftingStationConfig
	{
		public CraftingTable Table;

		public int level;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		public string custom;
	}
	[PublicAPI]
	public enum BuildPieceCategory
	{
		Misc = 0,
		Crafting = 1,
		BuildingWorkbench = 2,
		BuildingStonecutter = 3,
		Furniture = 4,
		All = 100,
		Custom = 99
	}
	[PublicAPI]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	public class RequiredResourcesList
	{
		public readonly List<Requirement> Requirements = new List<Requirement>();

		public void Add(string item, int amount, bool recover)
		{
			Requirements.Add(new Requirement
			{
				itemName = item,
				amount = amount,
				recover = recover
			});
		}
	}
	public struct Requirement
	{
		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(1)]
		public string itemName;

		public int amount;

		public bool recover;
	}
	public struct SpecialProperties
	{
		[Description("Admins should be the only ones that can build this piece.")]
		public bool AdminOnly;

		[Description("Turns off generating a config for this build piece.")]
		public bool NoConfig;
	}
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[PublicAPI]
	public class BuildingPieceCategory
	{
		public BuildPieceCategory Category;

		public string custom = "";

		public void Set(BuildPieceCategory category)
		{
			Category = category;
		}

		public void Set(string customCategory)
		{
			Category = BuildPieceCategory.Custom;
			custom = customCategory;
		}
	}
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[PublicAPI]
	public class PieceTool
	{
		public readonly HashSet<string> Tools = new HashSet<string>();

		public void Add(string tool)
		{
			Tools.Add(tool);
		}
	}
	[PublicAPI]
	[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
	[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)]
	public class BuildPiece
	{
		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
		internal class PieceConfig
		{
			public ConfigEntry<string> craft = null;

			public ConfigEntry<BuildPieceCategory> category = null;

			public ConfigEntry<string> customCategory = null;

			public ConfigEntry<string> tools = null;

			public ConfigEntry<CraftingTable> extensionTable = null;

			public ConfigEntry<string> customExtentionTable = null;

			public ConfigEntry<float> maxStationDistance = null;

			public ConfigEntry<CraftingTable> table = null;

			public ConfigEntry<string> customTable = null;
		}

		[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
			[UsedImplicitly]
			public string Category;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(new byte[] { 2, 1 })]
			[UsedImplicitly]
			public Action<ConfigEntryBase> CustomDrawer;
		}

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
		private class SerializedRequirements
		{
			public readonly List<Requirement> Reqs;

			public SerializedRequirements(List<Requirement> reqs)
			{
				Reqs = reqs;
			}

			public SerializedRequirements(string reqs)
			{
				Reqs = reqs.Split(new char[1] { ',' }).Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (string r) =>
				{
					string[] array = r.Split(new char[1] { ':' });
					Requirement result = default(Requirement);
					result.itemName = array[0];
					result.amount = ((array.Length <= 1 || !int.TryParse(array[1], out var result2)) ? 1 : result2);
					bool result3 = default(bool);
					result.recover = array.Length <= 2 || !bool.TryParse(array[2], out result3) || result3;
					return result;
				}).ToList();
			}

			public override string ToString()
			{
				return string.Join(",", Reqs.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement r) => $"{r.itemName}:{r.amount}:{r.recover}"));
			}

			[return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
			public static ItemDrop fetchByName(ObjectDB objectDB, string name)
			{
				GameObject itemPrefab = objectDB.GetItemPrefab(name);
				ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					Debug.LogWarning((object)(((!string.IsNullOrWhiteSpace(((Object)plugin).name)) ? ("[" + ((Object)plugin).name + "]") : "") + " The required item '" + name + "' does not exist."));
				}
				return val;
			}

			public static Requirement[] toPieceReqs(SerializedRequirements craft)
			{
				Dictionary<string, Requirement> dictionary = craft.Reqs.Where((Requirement r) => r.itemName != "").ToDictionary((Func<Requirement, string>)([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement r) => r.itemName), (Func<Requirement, Requirement>)([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement r) =>
				{
					//IL_000d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					//IL_001e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					ItemDrop val = ResItem(r);
					return (val == null) ? ((Requirement)null) : new Requirement
					{
						m_amount = r.amount,
						m_resItem = val,
						m_recover = r.recover
					};
				}));
				return dictionary.Values.Where([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement v) => v != null).ToArray();
				[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)]
				static ItemDrop ResItem(Requirement r)
				{
					return fetchByName(ObjectDB.instance, r.itemName);
				}
			}
		}

		[CompilerGenerated]
		private sealed class <RunQueuedSnapshots>d__33 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
			private object <>2__current;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
			private WaitForEndOfFrame <eof>5__1;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
			private GameObject <prefab>5__2;

			private float <intensity>5__3;

			private Quaternion? <rot>5__4;

			[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
			private Exception <ex>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				[return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				[return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RunQueuedSnapshots>d__33(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<eof>5__1 = null;
				<prefab>5__2 = null;
				<ex>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<eof>5__1 = new WaitForEndOfFrame();
					<>2__current = <eof>5__1;
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					break;
				case 3:
					<>1__state = -1;
					if (!Application.isBatchMode && Object.op_Implicit((Object)(object)<prefab>5__2))
					{
						try
						{
							SnapshotPiece(<prefab>5__2, <intensity>5__3, <rot>5__4);
						}
						catch (Exception ex)
						{
							<ex>5__5 = ex;
							Debug.LogError((object)$"[PieceManager] Snapshot failed for '{((Object)<prefab>5__2).name}': {<ex>5__5}");
						}
					}
					<prefab>5__2 = null;
					break;
				}
				if (_snapshotQueue.Count > 0)
				{
					(GameObject, float, Quaternion?) tuple = _snapshotQueue.Dequeue();
					<prefab>5__2 = tuple.Item1;
					<intensity>5__3 = tuple.Item2;
					<rot>5__4 = tuple.Item3;
					<>2__current = <eof>5__1;
					<>1__state = 3;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static readonly List<BuildPiece> registeredPieces = new List<BuildPiece>();

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(new byte[] { 1, 0, 1 })]
		private static readonly Queue<(GameObject prefab, float lightIntensity, Quaternion? camRot)> _snapshotQueue = new Queue<(GameObject, float, Quaternion?)>();

		private static readonly Dictionary<Piece, BuildPiece> pieceMap = new Dictionary<Piece, BuildPiece>();

		internal static Dictionary<BuildPiece, PieceConfig> pieceConfigs = new Dictionary<BuildPiece, PieceConfig>();

		internal List<Conversion> Conversions = new List<Conversion>();

		internal List<ItemConversion> conversions = new List<ItemConversion>();

		[Description("Disables generation of the configs for your pieces. This is global, this turns it off for all pieces in your mod.")]
		public static bool ConfigurationEnabled = true;

		public readonly GameObject Prefab;

		[Description("Specifies the resources needed to craft the piece.\nUse .Add to add resources with their internal ID and an amount.\nUse one .Add for each resource type the building piece should need.")]
		public readonly RequiredResourcesList RequiredItems = new RequiredResourcesList();

		[Description("Sets the category for the building piece.")]
		public readonly BuildingPieceCategory Category = new BuildingPieceCategory();

		[Description("Specifies the tool needed to build your piece.\nUse .Add to add a tool.")]
		public readonly PieceTool Tool = new PieceTool();

		[Description("Specifies the crafting station needed to build your piece.\nUse .Add to add a crafting station, using the CraftingTable enum and a minimum level for the crafting station.")]
		public CraftingStationList Crafting = new CraftingStationList();

		[Description("Makes this piece a station extension")]
		public ExtensionList Extension = new ExtensionList();

		[Description("Change the extended/special properties of your build piece.")]
		public SpecialProperties SpecialProperties;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		[Description("Specifies a config entry which toggles whether a recipe is active.")]
		public ConfigEntryBase RecipeIsActive = null;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private LocalizeKey _name;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private LocalizeKey _description;

		internal string[] activeTools = null;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static object configManager;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static Localization _english;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		internal static BaseUnityPlugin _plugin = null;

		private static bool hasConfigSync = true;

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static object _configSync;

		public LocalizeKey Name
		{
			get
			{
				LocalizeKey name = _name;
				if (name != null)
				{
					return name;
				}
				Piece component = Prefab.GetComponent<Piece>();
				if (component.m_name.StartsWith("$"))
				{
					_name = new LocalizeKey(component.m_name);
				}
				else
				{
					string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_");
					_name = new LocalizeKey(text).English(component.m_name);
					component.m_name = text;
				}
				return _name;
			}
		}

		public LocalizeKey Description
		{
			get
			{
				LocalizeKey description = _description;
				if (description != null)
				{
					return description;
				}
				Piece component = Prefab.GetComponent<Piece>();
				if (component.m_description.StartsWith("$"))
				{
					_description = new LocalizeKey(component.m_description);
				}
				else
				{
					string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_") + "_description";
					_description = new LocalizeKey(text).English(component.m_description);
					component.m_description = text;
				}
				return _description;
			}
		}

		private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English"));

		internal static BaseUnityPlugin plugin
		{
			get
			{
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Expected O, but got Unknown
				if (_plugin != null)
				{
					return _plugin;
				}
				IEnumerable<TypeInfo> source;
				try
				{
					source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
				}
				catch (ReflectionTypeLoadException ex)
				{
					source = from t in ex.Types
						where t != null
						select t.GetTypeInfo();
				}
				_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				return _plugin;
			}
		}

		[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)]
		private static object configSync
		{
			[<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)]
			get
			{
				if (_configSync != null || !hasConfigSync)
				{
					return _configSync;
				}
				Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync");
				if ((object)type != null)
				{
					_configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " PieceManager");
					type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString());
					type.GetProperty("IsLocked").SetValue(_configSync, true);
				}
				else
				{
					hasConfigSync = false;
				}
				return _configSync;
			}
		}

		public BuildPiece(string assetBundleFileName, string prefabName, string folderName = "assets")
			: this(PiecePrefabManager.RegisterAssetBundle(assetBundleFileName, folderName), prefabName)
		{
		}

		public BuildPiece(AssetBundle bundle, string prefabName)
		{
			Prefab = PiecePrefabManager.RegisterPrefab(bundle, prefabName);
			registeredPieces.Add(this);
		}

		internal static void Patch_FejdStartup(FejdStartup __instance)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Expected O, but got Unknown
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Expected O, but got Unknown
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Expected O, but got Unknown
			//IL_0606: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Expected O, but got Unknown
			//IL_08ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f4: Expected O, but got Unknown
			//IL_067b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0685: Expected O, but got Unknown
			//IL_0721: Unknown result type (might be due to invalid IL or missing references)
			//IL_072b: Expected O, but got Unknown
			//IL_095f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0969: Expected O, but got Unknown
			//IL_0b7e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b88: Expected O, but got Unknown
			//IL_0c18: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c22: Expected O, but got Unknown
			Type configManagerType = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Assembly a) => a.GetName().Name == "ConfigurationManager")?.GetType("ConfigurationManager.ConfigurationManager");
			configManager = ((configManagerType == null) ? null : Chainloader.ManagerObject.GetComponent(configManagerType));
			foreach (BuildPiece registeredPiece in registeredPieces)
			{
				registeredPiece.activeTools = registeredPiece.Tool.Tools.DefaultIfEmpty("Hammer").ToArray();
				if (registeredPiece.Category.Category != BuildPieceCategory.Custom)
				{
					registeredPiece.Prefab.GetComponent<Piece>().m_category = (PieceCategory)registeredPiece.Category.Category;
				}
				else
				{
					registeredPiece.Prefab.GetComponent<Piece>().m_category = PiecePrefabManager.GetCategory(registeredPiece.Category.custom);
				}
			}
			if (!ConfigurationEnabled)
			{
				return;
			}
			bool saveOnConfigSet = plugin.Config.SaveOnConfigSet;
			plugin.Config.SaveOnConfigSet = false;
			foreach (BuildPiece registeredPiece2 in registeredPieces)
			{
				BuildPiece piece = registeredPiece2;
				if (piece.SpecialProperties.NoConfig)
				{
					continue;
				}
				PieceConfig pieceConfig2 = (pieceConfigs[piece] = new PieceConfig());
				PieceConfig cfg = pieceConfig2;
				Piece piecePrefab2 = piece.Prefab.GetComponent<Piece>();
				string pieceName = piecePrefab2.m_name;
				string englishName = new Regex("[=\\n\\t\\\\\"\\'\\[\\]]*").Replace(english.Localize(pieceName), "").Trim();
				string localizedName = Localization.instance.Localize(pieceName).Trim();
				int order = 0;
				cfg.category = config(englishName, "Build Table Category", piece.Category.Category, new ConfigDescription("Build Category where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = (order -= 1),
						Category = localizedName
					}
				}));
				ConfigurationManagerAttributes customTableAttributes = new ConfigurationManagerAttributes
				{
					Order = (order -= 1),
					Browsable = (cfg.category.Value == BuildPieceCategory.Custom),
					Category = localizedName
				};
				cfg.customCategory = config(englishName, "Custom Build Category", piece.Category.custom, new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes }));
				cfg.category.SettingChanged += BuildTableConfigChanged;
				cfg.customCategory.SettingChanged += BuildTableConfigChanged;
				if (cfg.category.Value == BuildPieceCategory.Custom)
				{
					piecePrefab2.m_category = PiecePrefabManager.GetCategory(cfg.customCategory.Value);
				}
				else
				{
					piecePrefab2.m_category = (PieceCategory)cfg.category.Value;
				}
				cfg.tools = config(englishName, "Tools", string.Join(", ", piece.activeTools), new ConfigDescription("Comma separated list of tools where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1] { customTableAttributes }));
				piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' })
					select s.Trim()).ToArray();
				cfg.tools.SettingChanged += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, EventArgs _) =>
				{
					Inventory[] source = (from c in Player.s_players.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Player p) => ((Humanoid)p).GetInventory()).Concat(from c in Object.FindObjectsByType<Container>((FindObjectsSortMode)0)
							select c.GetInventory())
						where c != null
						select c).ToArray();
					Dictionary<string, List<PieceTable>> dictionary = (from kv in (from i in (from p in ObjectDB.instance.m_items
								select p.GetComponent<ItemDrop>() into c
								where Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>())
								select c).Concat(ItemDrop.s_instances)
							select new KeyValuePair<string, ItemData>(Utils.GetPrefabName(((Component)i).gameObject), i.m_itemData)).Concat(from i in source.SelectMany([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Inventory i) => i.GetAllItems())
							select new KeyValuePair<string, ItemData>(((Object)i.m_dropPrefab).name, i))
						where Object.op_Implicit((Object)(object)kv.Value.m_shared.m_buildPieces)
						group kv by kv.Key).ToDictionary([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (IGrouping<string, KeyValuePair<string, ItemData>> g) => g.Key, [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (IGrouping<string, KeyValuePair<string, ItemData>> g) => g.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (KeyValuePair<string, ItemData> kv) => kv.Value.m_shared.m_buildPieces).Distinct().ToList());
					string[] array5 = piece.activeTools;
					foreach (string key in array5)
					{
						if (dictionary.TryGetValue(key, out var value3))
						{
							foreach (PieceTable item3 in value3)
							{
								item3.m_pieces.Remove(piece.Prefab);
							}
						}
					}
					piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' })
						select s.Trim()).ToArray();
					if (Object.op_Implicit((Object)(object)ObjectDB.instance))
					{
						string[] array6 = piece.activeTools;
						foreach (string key2 in array6)
						{
							if (dictionary.TryGetValue(key2, out var value4))
							{
								foreach (PieceTable item4 in value4)
								{
									if (!item4.m_pieces.Contains(piece.Prefab))
									{
										item4.m_pieces.Add(piece.Prefab);
									}
								}
							}
						}
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_buildPieces))
						{
							PiecePrefabManager.CategoryRefreshNeeded = true;
							((Humanoid)Player.m_localPlayer).SetPlaceMode(Player.m_localPlayer.m_buildPieces);
						}
					}
				};
				StationExtension pieceExtensionComp;
				List<ConfigurationManagerAttributes> hideWhenNoneAttributes2;
				if (piece.Extension.ExtensionStations.Count > 0)
				{
					pieceExtensionComp = piece.Prefab.GetOrAddComponent<StationExtension>();
					PieceConfig pieceConfig3 = cfg;
					string group = englishName;
					CraftingTable table = piece.Extension.ExtensionStations.First().Table;
					string text = "Crafting station that " + localizedName + " extends.";
					object[] array = new object[1];
					ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes();
					int num = order - 1;
					order = num;
					configurationManagerAttributes.Order = num;
					array[0] = configurationManagerAttributes;
					pieceConfig3.extensionTable = config(group, "Extends Station", table, new ConfigDescription(text, (AcceptableValueBase)null, array));
					cfg.customExtentionTable = config(englishName, "Custom Extend Station", piece.Extension.ExtensionStations.First().custom ?? "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes }));
					PieceConfig pieceConfig4 = cfg;
					string group2 = englishName;
					float maxStationDistance = piece.Extension.ExtensionStations.First().maxStationDistance;
					string text2 = "Distance from the station that " + localizedName + " can be placed.";
					object[] array2 = new object[1];
					ConfigurationManagerAttributes configurationManagerAttributes2 = new ConfigurationManagerAttributes();
					num = order - 1;
					order = num;
					configurationManagerAttributes2.Order = num;
					array2[0] = configurationManagerAttributes2;
					pieceConfig4.maxStationDistance = config(group2, "Max Station Distance", maxStationDistance, new ConfigDescription(text2, (AcceptableValueBase)null, array2));
					hideWhenNoneAttributes2 = new List<ConfigurationManagerAttributes>();
					cfg.extensionTable.SettingChanged += ExtensionTableConfigChanged;
					cfg.customExtentionTable.SettingChanged += ExtensionTableConfigChanged;
					cfg.maxStationDistance.SettingChanged += ExtensionTableConfigChanged;
					ConfigurationManagerAttributes configurationManagerAttributes3 = new ConfigurationManagerAttributes();
					num = order - 1;
					order = num;
					configurationManagerAttributes3.Order = num;
					configurationManagerAttributes3.Browsable = cfg.extensionTable.Value != CraftingTable.None;
					ConfigurationManagerAttributes item = configurationManagerAttributes3;
					hideWhenNoneAttributes2.Add(item);
				}
				List<ConfigurationManagerAttributes> hideWhenNoneAttributes;
				if (piece.Crafting.Stations.Count > 0)
				{
					hideWhenNoneAttributes = new List<ConfigurationManagerAttributes>();
					PieceConfig pieceConfig5 = cfg;
					string group3 = englishName;
					CraftingTable table2 = piece.Crafting.Stations.First().Table;
					string text3 = "Crafting station where " + localizedName + " is available.";
					object[] array3 = new object[1];
					ConfigurationManagerAttributes configurationManagerAttributes4 = new ConfigurationManagerAttributes();
					int num = order - 1;
					order = num;
					configurationManagerAttributes4.Order = num;
					array3[0] = configurationManagerAttributes4;
					pieceConfig5.table = config(group3, "Crafting Station", table2, new ConfigDescription(text3, (AcceptableValueBase)null, array3));
					cfg.customTable = config(englishName, "Custom Crafting Station", piece.Crafting.Stations.First().custom ?? "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes }));
					cfg.table.SettingChanged += TableConfigChanged;
					cfg.customTable.SettingChanged += TableConfigChanged;
					ConfigurationManagerAttributes configurationManagerAttributes5 = new ConfigurationManagerAttributes();
					num = order - 1;
					order = num;
					configurationManagerAttributes5.Order = num;
					configurationManagerAttributes5.Browsable = cfg.table.Value != CraftingTable.None;
					ConfigurationManagerAttributes item2 = configurationManagerAttributes5;
					hideWhenNoneAttributes.Add(item2);
				}
				cfg.craft = itemConfig("Crafting Costs", new SerializedRequirements(piece.RequiredItems.Requirements).ToString(), "Item costs to craft " + localizedName);
				cfg.craft.SettingChanged += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, EventArgs _) =>
				{
					if (Object.op_Imp