Decompiled source of Planting Tools v1.0.1

DigiPlanting.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DigiCore;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PlantingTools;
using Splatform;
using TMPro;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("DigiPlanting")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DigiPlanting")]
[assembly: AssemblyTitle("DigiPlanting")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal static class SettingOrder
{
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;
	}

	internal static void Apply(ConfigFile config)
	{
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Expected O, but got Unknown
		FieldInfo fieldInfo = AccessTools.Field(typeof(ConfigEntryBase), "<Description>k__BackingField");
		if (fieldInfo == null)
		{
			return;
		}
		int num = 1000;
		foreach (ConfigDefinition item in config.Keys.ToList())
		{
			ConfigEntryBase val = config[item];
			ConfigDescription description = val.Description;
			object[] array = ((description != null) ? description.Tags : null) ?? new object[0];
			object obj = array.FirstOrDefault((object t) => t != null && t.GetType().Name == "ConfigurationManagerAttributes");
			if (obj != null)
			{
				FieldInfo fieldInfo2 = AccessTools.Field(obj.GetType(), "Order");
				if (fieldInfo2 != null && fieldInfo2.GetValue(obj) == null)
				{
					fieldInfo2.SetValue(obj, num);
				}
			}
			else
			{
				fieldInfo.SetValue(val, (object?)new ConfigDescription(((description != null) ? description.Description : null) ?? "", (description != null) ? description.AcceptableValues : null, array.Concat(new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = num
					}
				}).ToArray()));
			}
			num--;
		}
	}
}
internal static class StoreRules
{
	private static bool _resolved;

	private static MethodInfo _readMarker;

	private static PropertyInfo _settings;

	private static PropertyInfo _useMarkers;

	private static PropertyInfo _canDeposit;

	private static PropertyInfo _canWithdraw;

	private static MethodInfo _isProtected;

	private static void Resolve()
	{
		if (_resolved)
		{
			return;
		}
		_resolved = true;
		try
		{
			Type type = AccessTools.TypeByName("LocalCraftFromStoragePrime.ContainerPolicyApi");
			Type type2 = AccessTools.TypeByName("LocalCraftFromStoragePrime.ContainerMarkerPolicy");
			Type type3 = AccessTools.TypeByName("LocalCraftFromStoragePrime.Plugin");
			if (!(type == null) && !(type2 == null) && !(type3 == null))
			{
				_readMarker = AccessTools.Method(type, "ReadMarker", new Type[2]
				{
					typeof(Inventory),
					typeof(bool)
				}, (Type[])null);
				_settings = AccessTools.Property(type3, "Settings");
				_useMarkers = ((_settings != null) ? AccessTools.Property(_settings.PropertyType, "UseContainerMarkers") : null);
				_canDeposit = AccessTools.Property(type2, "CanDeposit");
				_canWithdraw = AccessTools.Property(type2, "CanWithdraw");
				_isProtected = AccessTools.Method(type2, "IsProtectedPosition", new Type[2]
				{
					typeof(int),
					typeof(int)
				}, (Type[])null);
			}
		}
		catch (Exception)
		{
			_readMarker = null;
		}
	}

	private static object Marker(Inventory inv)
	{
		Resolve();
		if (_readMarker == null || _canDeposit == null || _canWithdraw == null || _isProtected == null)
		{
			return null;
		}
		try
		{
			bool flag = true;
			if (_settings != null && _useMarkers != null)
			{
				flag = (bool)_useMarkers.GetValue(_settings.GetValue(null));
			}
			return _readMarker.Invoke(null, new object[2] { inv, flag });
		}
		catch (Exception)
		{
			return null;
		}
	}

	internal static bool CanDeposit(Inventory inv)
	{
		object obj = Marker(inv);
		if (obj != null)
		{
			return (bool)_canDeposit.GetValue(obj);
		}
		return true;
	}

	internal static bool CanWithdraw(Inventory inv)
	{
		object obj = Marker(inv);
		if (obj != null)
		{
			return (bool)_canWithdraw.GetValue(obj);
		}
		return true;
	}

	internal static bool IsProtected(Inventory inv, ItemData item)
	{
		return IsProtectedSlot(inv, item.m_gridPos.x, item.m_gridPos.y);
	}

	internal static bool IsProtectedSlot(Inventory inv, int x, int y)
	{
		object obj = Marker(inv);
		if (obj != null)
		{
			return (bool)_isProtected.Invoke(obj, new object[2] { x, y });
		}
		return false;
	}

	internal static Func<int, int, bool> ProtectedSlots(Inventory inv)
	{
		object m = Marker(inv);
		if (m == null)
		{
			return null;
		}
		return (int x, int y) => (bool)_isProtected.Invoke(m, new object[2] { x, y });
	}

	internal static Container PickOutputChest(List<Container> nearestFirst, GameObject prefab, int amount)
	{
		string shared = prefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_name;
		List<Container> source = nearestFirst.Where((Container c) => CanDeposit(c.GetInventory()) && c.GetInventory().CanAddItem(prefab, amount)).ToList();
		return ((IEnumerable<Container>)source).FirstOrDefault((Func<Container, bool>)((Container c) => c.GetInventory().GetAllItems().Any((ItemData i) => i?.m_shared != null && i.m_shared.m_name == shared && !IsProtected(c.GetInventory(), i)))) ?? source.FirstOrDefault();
	}

	internal static bool TakeOne(List<Container> nearestFirst, Func<ItemData, bool> match, out ItemData taken)
	{
		foreach (Container item in nearestFirst)
		{
			Inventory inv = item.GetInventory();
			if (CanWithdraw(inv))
			{
				ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => match(i) && !IsProtected(inv, i)));
				if (val != null)
				{
					taken = val.Clone();
					inv.RemoveOneItem(val);
					return true;
				}
			}
		}
		taken = null;
		return false;
	}
}
namespace DigiCore
{
	public static class ChestFlags
	{
		public const string NoStore = "digi_nostore";

		public static bool StoreBlocked(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)chest).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				return component.GetZDO().GetBool("digi_nostore", false);
			}
			return false;
		}
	}
	public sealed class ModuleInfo
	{
		public readonly Type Type;

		public readonly string Title;

		public readonly string OldGuid;

		public readonly string Description;

		public readonly string[] Requires;

		public readonly bool DefaultOn;

		public readonly bool OffOnce;

		public readonly string FormerTitle;

		public ModuleInfo(Type type, string title, string oldGuid, string description, string[] requires = null, bool defaultOn = true, bool offOnce = false, string formerTitle = null)
		{
			OffOnce = offOnce;
			FormerTitle = formerTitle;
			Type = type;
			Title = title;
			OldGuid = oldGuid;
			Description = description;
			Requires = requires ?? new string[0];
			DefaultOn = defaultOn;
		}
	}
	public abstract class DigiPlugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<string, string> <>9__15_0;

			public static Func<string, bool> <>9__15_1;

			public static Func<string, bool> <>9__15_2;

			public static Func<string, string> <>9__15_3;

			public static Func<string, bool> <>9__15_4;

			public static Func<string, string> <>9__15_5;

			public static Func<string, string[]> <>9__24_0;

			public static Func<string[], string> <>9__24_1;

			public static Func<string[], string> <>9__24_4;

			public static Func<IGrouping<string, string[]>, string> <>9__24_2;

			public static PopupButtonCallback <>9__24_3;

			public static Func<string, bool> <>9__29_0;

			internal string <Awake>b__15_0(string l)
			{
				return l.Trim();
			}

			internal bool <Awake>b__15_1(string l)
			{
				return l.Length > 0;
			}

			internal bool <Awake>b__15_2(string r)
			{
				return !Chainloader.PluginInfos.ContainsKey(r);
			}

			internal string <Awake>b__15_3(string r)
			{
				if (!RequirementNames.TryGetValue(r, out var value))
				{
					return r;
				}
				return value;
			}

			internal bool <Awake>b__15_4(string r)
			{
				return !Chainloader.PluginInfos.ContainsKey(r);
			}

			internal string <Awake>b__15_5(string r)
			{
				if (!RequirementNames.TryGetValue(r, out var value))
				{
					return r;
				}
				return value;
			}

			internal string[] <ShowDuplicates>b__24_0(string d)
			{
				return d.Split(new char[1] { '|' });
			}

			internal string <ShowDuplicates>b__24_1(string[] d)
			{
				return d[0];
			}

			internal string <ShowDuplicates>b__24_2(IGrouping<string, string[]> g)
			{
				return "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1]));
			}

			internal string <ShowDuplicates>b__24_4(string[] d)
			{
				return d[1];
			}

			internal void <ShowDuplicates>b__24_3()
			{
				UnifiedPopup.Pop();
			}

			internal bool <Apply>b__29_0(string r)
			{
				return !Chainloader.PluginInfos.ContainsKey(r);
			}
		}

		public const string ModulesSection = "0 - Sub-mods";

		internal static DigiPlugin StartingHost;

		internal static ModuleInfo StartingModule;

		private static readonly Dictionary<string, string> RequirementNames = new Dictionary<string, string>
		{
			{ "randyknapp.mods.epicloot", "Epic Loot" },
			{ "com.jotunn.jotunn", "Jotunn" },
			{ "ValheimLegends", "Valheim Legends" },
			{ "vapok.mods.adventurebackpacks", "Adventure Backpacks" },
			{ "MidnightsFX.StarLevelSystem", "Star Level System" },
			{ "sosal.nordicrugs", "Nordic Rugs" },
			{ "LuminairPrime.valheim.localcraftfromstorageprime", "Local Craft From Storage Prime" }
		};

		private readonly Dictionary<ModuleInfo, DigiModule> _running = new Dictionary<ModuleInfo, DigiModule>();

		private readonly Dictionary<ModuleInfo, ConfigEntry<bool>> _switches = new Dictionary<ModuleInfo, ConfigEntry<bool>>();

		private HashSet<string> _migrated;

		private const string DuplicatesKey = "digi.valheim.duplicates";

		private const string DuplicatesShownKey = "digi.valheim.duplicates.shown";

		protected abstract ModuleInfo[] Modules { get; }

		protected virtual bool Standalone => false;

		internal bool IsStandalone => Standalone;

		private string MigratedFile => Path.Combine(Paths.ConfigPath, ((BaseUnityPlugin)this).Info.Metadata.GUID + ".migrated.txt");

		private static List<string> Duplicates
		{
			get
			{
				List<string> list = AppDomain.CurrentDomain.GetData("digi.valheim.duplicates") as List<string>;
				if (list == null)
				{
					list = new List<string>();
					AppDomain.CurrentDomain.SetData("digi.valheim.duplicates", list);
				}
				return list;
			}
		}

		protected virtual void Awake()
		{
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			((BaseUnityPlugin)this).Config.Save();
			_migrated = (File.Exists(MigratedFile) ? new HashSet<string>(from l in File.ReadAllLines(MigratedFile)
				select l.Trim() into l
				where l.Length > 0
				select l) : new HashSet<string>());
			bool flag = !_migrated.Contains("#switches");
			ModuleInfo[] modules;
			if (Standalone)
			{
				modules = Modules;
				foreach (ModuleInfo moduleInfo in modules)
				{
					List<string> list = moduleInfo.Requires.Where((string r) => !Chainloader.PluginInfos.ContainsKey(r)).ToList();
					if (list.Count > 0)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)(moduleInfo.Title + ": not started, needs " + string.Join(" and ", list.Select((string r) => (!RequirementNames.TryGetValue(r, out var value2)) ? r : value2)) + "."));
					}
					else
					{
						StartModule(moduleInfo);
					}
				}
				return;
			}
			modules = Modules;
			foreach (ModuleInfo moduleInfo2 in modules)
			{
				List<string> list2 = moduleInfo2.Requires.Where((string r) => !Chainloader.PluginInfos.ContainsKey(r)).ToList();
				string value2;
				string text = ((moduleInfo2.Requires.Length == 0) ? "" : (" Needs " + string.Join(" and ", moduleInfo2.Requires.Select((string r) => (!RequirementNames.TryGetValue(r, out value2)) ? r : value2)) + "."));
				ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Sub-mods", moduleInfo2.Title, moduleInfo2.DefaultOn, moduleInfo2.Description + text);
				if (flag && !moduleInfo2.DefaultOn && File.Exists(OldConfigPath(moduleInfo2)))
				{
					val.Value = true;
				}
				if (moduleInfo2.FormerTitle != null && !_migrated.Contains("#renamed:" + moduleInfo2.FormerTitle))
				{
					if (File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath) && ReadCfg(((BaseUnityPlugin)this).Config.ConfigFilePath).TryGetValue("0 - Sub-mods\n" + moduleInfo2.FormerTitle, out var value) && bool.TryParse(value, out var result))
					{
						val.Value = result;
					}
					Remember("#renamed:" + moduleInfo2.FormerTitle);
				}
				if (moduleInfo2.OffOnce && !_migrated.Contains("#off:" + moduleInfo2.OldGuid))
				{
					val.Value = false;
					Remember("#off:" + moduleInfo2.OldGuid);
				}
				_switches[moduleInfo2] = val;
				ModuleInfo captured = moduleInfo2;
				val.SettingChanged += delegate
				{
					Apply(captured);
				};
				if (list2.Count > 0)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)(moduleInfo2.Title + ": off, needs " + string.Join(", ", list2) + "."));
				}
			}
			if (flag)
			{
				Remember("#switches");
			}
			modules = Modules;
			foreach (ModuleInfo module in modules)
			{
				Apply(module);
			}
		}

		private void Start()
		{
			foreach (KeyValuePair<ModuleInfo, DigiModule> item in _running.ToList())
			{
				if (!((Object)(object)item.Value == (Object)null) && !(item.Key.OldGuid == ((BaseUnityPlugin)this).Info.Metadata.GUID) && Chainloader.PluginInfos.ContainsKey(item.Key.OldGuid))
				{
					item.Value.Teardown();
					_running.Remove(item.Key);
					Forget(item.Key.OldGuid);
					ReportDuplicate(item.Key);
				}
			}
			SettingOrder.Apply(((BaseUnityPlugin)this).Config);
			if (!Application.isBatchMode)
			{
				((MonoBehaviour)this).StartCoroutine(ShowDuplicates());
			}
		}

		private void ReportDuplicate(ModuleInfo module)
		{
			if (IsOurSingle(module.OldGuid))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)(module.Title + ": runs as its own mod (" + module.OldGuid + "), so the copy in " + ((BaseUnityPlugin)this).Info.Metadata.Name + " stays off."));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": not started, because the separate mod (" + module.OldGuid + ") is installed too. Remove that one."));
				string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + module.Title;
				if (!Duplicates.Contains(item))
				{
					Duplicates.Add(item);
				}
			}
		}

		private static bool IsOurSingle(string guid)
		{
			if (!Chainloader.PluginInfos.TryGetValue(guid, out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return false;
			}
			Type type = ((object)value.Instance).GetType();
			while (type != null)
			{
				if (type.FullName == "DigiCore.DigiPlugin")
				{
					return true;
				}
				type = type.BaseType;
			}
			return false;
		}

		internal void ReportReplaced(string what)
		{
			string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + what;
			if (!Duplicates.Contains(item))
			{
				Duplicates.Add(item);
			}
		}

		private IEnumerator ShowDuplicates()
		{
			while ((Object)(object)FejdStartup.instance == (Object)null || !UnifiedPopup.IsAvailable())
			{
				yield return (object)new WaitForSeconds(0.5f);
			}
			yield return (object)new WaitForSeconds(1f);
			if (Duplicates.Count == 0 || AppDomain.CurrentDomain.GetData("digi.valheim.duplicates.shown") != null)
			{
				yield break;
			}
			AppDomain.CurrentDomain.SetData("digi.valheim.duplicates.shown", true);
			IEnumerable<string> values = from d in Duplicates
				select d.Split(new char[1] { '|' }) into d
				group d by d[0] into g
				select "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1]));
			string text = "These mods are installed twice: on their own and inside one of our combined mods.\n\n" + string.Join("\n", values) + "\n\nThe copy in the combined mod stays off until you remove the separate ones in your mod manager (or make a new profile with Digi Modpack). Your settings are copied over.";
			object obj = <>c.<>9__24_3;
			if (obj == null)
			{
				PopupButtonCallback val = delegate
				{
					UnifiedPopup.Pop();
				};
				<>c.<>9__24_3 = val;
				obj = (object)val;
			}
			UnifiedPopup.Push((PopupBase)new WarningPopup("Mods installed twice", text, (PopupButtonCallback)obj, false));
		}

		private static string OldConfigPath(ModuleInfo module)
		{
			return Path.Combine(Paths.ConfigPath, module.OldGuid + ".cfg");
		}

		internal bool FirstTime(string key)
		{
			if (_migrated == null || _migrated.Contains(key))
			{
				return false;
			}
			Remember(key);
			return true;
		}

		private void Remember(string key)
		{
			if (!_migrated.Add(key))
			{
				return;
			}
			try
			{
				File.AppendAllText(MigratedFile, key + Environment.NewLine);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message));
			}
		}

		private void Forget(string key)
		{
			if (!_migrated.Remove(key))
			{
				return;
			}
			try
			{
				File.WriteAllLines(MigratedFile, _migrated.ToArray());
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message));
			}
		}

		private void Apply(ModuleInfo module)
		{
			bool value = _switches[module].Value;
			_running.TryGetValue(module, out var value2);
			if (value && (Object)(object)value2 == (Object)null)
			{
				if (!module.Requires.Any((string r) => !Chainloader.PluginInfos.ContainsKey(r)))
				{
					if (module.OldGuid != ((BaseUnityPlugin)this).Info.Metadata.GUID && Chainloader.PluginInfos.ContainsKey(module.OldGuid))
					{
						ReportDuplicate(module);
					}
					else
					{
						StartModule(module);
					}
				}
			}
			else if (!value && (Object)(object)value2 != (Object)null)
			{
				value2.Teardown();
				_running.Remove(module);
				((BaseUnityPlugin)this).Logger.LogInfo((object)(module.Title + ": switched off."));
			}
		}

		private void StartModule(ModuleInfo module)
		{
			StartingHost = this;
			StartingModule = module;
			try
			{
				DigiModule digiModule = (DigiModule)(object)((Component)this).gameObject.AddComponent(module.Type);
				digiModule.Host = this;
				digiModule.Info2 = module;
				_running[module] = digiModule;
				MigrateOldSettings(module, digiModule);
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"{module.Title} could not start: {arg}");
			}
			finally
			{
				StartingHost = null;
				StartingModule = null;
			}
			SettingOrder.Apply(((BaseUnityPlugin)this).Config);
		}

		private void MigrateOldSettings(ModuleInfo module, DigiModule component)
		{
			if (_migrated.Contains(module.OldGuid) || module.OldGuid == ((BaseUnityPlugin)this).Info.Metadata.GUID)
			{
				return;
			}
			string path = OldConfigPath(module);
			if (File.Exists(path) && component.ConfigOrNull != null)
			{
				Dictionary<string, string> dictionary = ReadCfg(path);
				int num = 0;
				foreach (ModuleConfig.Bound entry in component.ConfigOrNull.Entries)
				{
					if (dictionary.TryGetValue(entry.Section + "\n" + entry.Key, out var value))
					{
						try
						{
							entry.Entry.SetSerializedValue(value);
							num++;
						}
						catch (Exception ex)
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": could not copy '" + entry.Key + "': " + ex.Message));
						}
					}
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"{module.Title}: copied {num} setting(s) from {Path.GetFileName(path)}.");
			}
			Remember(module.OldGuid);
		}

		private static Dictionary<string, string> ReadCfg(string path)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string text = "";
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2);
					continue;
				}
				int num = text2.IndexOf(" = ", StringComparison.Ordinal);
				if (num > 0)
				{
					dictionary[text + "\n" + text2.Substring(0, num).Trim()] = text2.Substring(num + 3);
				}
			}
			return dictionary;
		}

		protected virtual void OnDestroy()
		{
			foreach (DigiModule item in _running.Values.ToList())
			{
				item?.Teardown();
			}
			_running.Clear();
		}

		public bool IsRunning(Type moduleType)
		{
			return _running.Any((KeyValuePair<ModuleInfo, DigiModule> p) => p.Key.Type == moduleType && (Object)(object)p.Value != (Object)null);
		}
	}
	public abstract class DigiModule : MonoBehaviour
	{
		internal DigiPlugin Host;

		internal ModuleInfo Info2;

		private ModuleConfig _config;

		private ManualLogSource _logger;

		private Harmony _harmony;

		internal ModuleConfig ConfigOrNull => _config;

		protected ModuleConfig Config => _config ?? (_config = new ModuleConfig(((BaseUnityPlugin)(Host ?? DigiPlugin.StartingHost)).Config, (Host ?? DigiPlugin.StartingHost).IsStandalone ? null : (Info2 ?? DigiPlugin.StartingModule).Title));

		protected ManualLogSource Logger => _logger ?? (_logger = Logger.CreateLogSource("Digi's " + (Info2 ?? DigiPlugin.StartingModule)?.Title));

		protected Harmony ModuleHarmony
		{
			get
			{
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Expected O, but got Unknown
				//IL_004a: Expected O, but got Unknown
				Harmony obj = _harmony;
				if (obj == null)
				{
					Harmony val = new Harmony(((object)this).GetType().Namespace?.ToLowerInvariant() + "." + Guid.NewGuid().ToString("N"));
					Harmony val2 = val;
					_harmony = val;
					obj = val2;
				}
				return obj;
			}
		}

		protected void ReportReplacedMod(string what)
		{
			(Host ?? DigiPlugin.StartingHost)?.ReportReplaced(what);
		}

		protected bool FirstTime(string key)
		{
			return (Host ?? DigiPlugin.StartingHost)?.FirstTime("#once:" + (Info2 ?? DigiPlugin.StartingModule)?.Title + ":" + key) ?? false;
		}

		protected Harmony PatchModule(Type type)
		{
			ModuleHarmony.PatchAll(type);
			return ModuleHarmony;
		}

		protected Harmony PatchModuleNamespace()
		{
			string text = ((object)this).GetType().Namespace;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(((object)this).GetType().Assembly);
			foreach (Type type in typesFromAssembly)
			{
				if (type.Namespace == text || (type.Namespace != null && text != null && type.Namespace.StartsWith(text + ".")))
				{
					ModuleHarmony.CreateClassProcessor(type).Patch();
				}
			}
			return ModuleHarmony;
		}

		internal void Teardown()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Unpatch: " + ex.Message));
			}
			Object.Destroy((Object)(object)this);
		}
	}
	public sealed class ModuleConfig
	{
		public sealed class Bound
		{
			public string Section;

			public string Key;

			public ConfigEntryBase Entry;
		}

		private readonly ConfigFile _file;

		private readonly string _prefix;

		internal readonly List<Bound> Entries = new List<Bound>();

		private static readonly char[] Invalid = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' };

		public ConfigFile File => _file;

		public string ConfigFilePath => _file.ConfigFilePath;

		internal ModuleConfig(ConfigFile file, string title)
		{
			_file = file;
			_prefix = ((title == null) ? "" : (title + " - "));
		}

		public void Reload()
		{
		}

		public void Save()
		{
			_file.Save();
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, ConfigDescription configDescription = null)
		{
			section = Clean(section);
			key = Clean(key);
			ConfigEntry<T> val = _file.Bind<T>(_prefix + section, key, defaultValue, configDescription);
			if (!Entries.Any((Bound b) => b.Section == section && b.Key == key))
			{
				Entries.Add(new Bound
				{
					Section = section,
					Key = key,
					Entry = (ConfigEntryBase)(object)val
				});
			}
			return val;
		}

		private static string Clean(string name)
		{
			if (name.IndexOfAny(Invalid) < 0)
			{
				return name;
			}
			string[] value = name.Split(Invalid, StringSplitOptions.None);
			return string.Join("", value).Trim();
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		public ConfigEntry<T> Bind<T>(ConfigDefinition definition, T defaultValue, ConfigDescription configDescription = null)
		{
			return Bind(definition.Section, definition.Key, defaultValue, configDescription);
		}

		public bool TryGetEntry<T>(ConfigDefinition definition, out ConfigEntry<T> entry)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			return _file.TryGetEntry<T>(new ConfigDefinition(_prefix + definition.Section, definition.Key), ref entry);
		}
	}
}
namespace DigiPlanting
{
	[BepInPlugin("digi.valheim.plantingtools", "Digi's Planting Tools", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : DigiPlugin
	{
		public const string Guid = "digi.valheim.plantingtools";

		public const string Name = "Digi's Planting Tools";

		public const string Version = "1.0.1";

		protected override ModuleInfo[] Modules { get; } = new ModuleInfo[1]
		{
			new ModuleInfo(typeof(PlantingTools.Plugin), "Planting Tools", "digi.valheim.plantingtools", "Plant a whole grid of crops, saplings or bushes with one click of the cultivator, in about a second and without lag; lines up with your fields, fills a cultivated patch, Shift+E harvests everything around you.")
		};
	}
}
namespace PlantingTools
{
	internal enum Spot : byte
	{
		Ok,
		NoSeeds,
		Taken,
		NotCultivated,
		WrongBiome,
		NoSpace,
		NoSun,
		TooHot,
		TooCold,
		Blocked,
		Invalid
	}
	internal sealed class Kind
	{
		public GameObject Prefab;

		public Piece Piece;

		public Plant Plant;

		public string Name;

		public bool NeedCultivated;

		public bool TolerateHeat;

		public bool TolerateCold;

		public bool Tree;

		public Biome Biome;

		public float GrowRadius;

		public float BodyRadius;

		public float Spacing;

		public static Kind Of(GameObject prefab)
		{
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			Piece component = prefab.GetComponent<Piece>();
			Plant component2 = prefab.GetComponent<Plant>();
			if ((Object)(object)component == (Object)null || component.m_repairPiece || component.m_removePiece)
			{
				return null;
			}
			if ((Object)(object)component2 == (Object)null && (Object)(object)prefab.GetComponent<Pickable>() == (Object)null)
			{
				return null;
			}
			if ((Object)(object)component2 != (Object)null && component2.m_attachDistance > 0f)
			{
				return null;
			}
			Kind kind = new Kind
			{
				Prefab = prefab,
				Piece = component,
				Plant = component2,
				Name = ((Object)prefab).name
			};
			if ((Object)(object)component2 != (Object)null)
			{
				kind.NeedCultivated = component2.m_needCultivatedGround;
				kind.Biome = component2.m_biome;
				kind.TolerateHeat = component2.m_tolerateHeat;
				kind.TolerateCold = component2.m_tolerateCold;
				kind.GrowRadius = component2.m_growRadius;
				GameObject[] grownPrefabs = component2.m_grownPrefabs;
				foreach (GameObject val in grownPrefabs)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<TreeBase>() != (Object)null)
					{
						kind.Tree = true;
					}
				}
				if ((Object)(object)prefab.GetComponent<TreeBase>() != (Object)null)
				{
					kind.Tree = true;
				}
				Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
				foreach (Collider val2 in componentsInChildren)
				{
					if (((1 << ((Component)val2).gameObject.layer) & Grid.SpaceMask) != 0)
					{
						kind.BodyRadius = Mathf.Max(kind.BodyRadius, Radius(val2));
					}
				}
			}
			else
			{
				kind.NeedCultivated = component.m_cultivatedGroundOnly;
				kind.Biome = component.m_onlyInBiome;
			}
			kind.Spacing = Plugin.SpacingFor(kind);
			return kind;
		}

		private static float Radius(Collider c)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			Vector3 lossyScale = ((Component)c).transform.lossyScale;
			float num = Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z));
			CapsuleCollider val = (CapsuleCollider)(object)((c is CapsuleCollider) ? c : null);
			if (val == null)
			{
				SphereCollider val2 = (SphereCollider)(object)((c is SphereCollider) ? c : null);
				if (val2 == null)
				{
					BoxCollider val3 = (BoxCollider)(object)((c is BoxCollider) ? c : null);
					if (val3 != null)
					{
						return Mathf.Max(val3.size.x * Mathf.Abs(lossyScale.x), val3.size.z * Mathf.Abs(lossyScale.z)) * 0.5f;
					}
					return 0f;
				}
				return val2.radius * num;
			}
			return val.radius * num;
		}

		public float CapsuleRadius()
		{
			float num = 0f;
			List<GameObject> list = new List<GameObject> { Prefab };
			if ((Object)(object)Plant != (Object)null)
			{
				list.AddRange(Plant.m_grownPrefabs);
			}
			foreach (GameObject item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					CapsuleCollider[] componentsInChildren = item.GetComponentsInChildren<CapsuleCollider>(true);
					foreach (CapsuleCollider val in componentsInChildren)
					{
						num = Mathf.Max(num, val.radius);
					}
				}
			}
			return num;
		}
	}
	internal static class Grid
	{
		public static readonly int SpaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });

		private static readonly int RoofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" });

		private static readonly int PickableMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "item" });

		private const int MaxHits = 8;

		public static Kind Kind;

		public static bool Active;

		public static Vector3 Root;

		public static Vector3 RowStep;

		public static Vector3 ColumnStep;

		public static Quaternion Rotation;

		public static int Rows;

		public static int Columns;

		public static int Count;

		public static Vector3[] Positions = (Vector3[])(object)new Vector3[0];

		public static Spot[] Spots = new Spot[0];

		public static readonly int[] Tally = new int[Enum.GetValues(typeof(Spot)).Length];

		public static int Version;

		public static int Seeds = int.MaxValue;

		public static float LastCheckMs;

		public static bool Fill;

		public static bool Snapped;

		public static string Note = "";

		private static readonly int AnchorMask = SpaceMask | LayerMask.GetMask(new string[1] { "item" });

		private static Vector3 _lastRoot;

		private static Vector3 _lastRow;

		private static Quaternion _lastRotation;

		private static int _lastRows;

		private static int _lastColumns;

		private static int _lastMax;

		private static int _lastQueued;

		private static bool _lastFill;

		private static float _lastSpacing;

		private static float _nextCheck;

		private static Kind _lastKind;

		private static Kind _familyFor;

		private static Heightmap _heightmap;

		private static bool _batchFailed;

		private static readonly List<int> Todo = new List<int>();

		private static readonly List<PrivateArea> Wards = new List<PrivateArea>();

		private static readonly List<Location> NoBuild = new List<Location>();

		private static readonly Collider[] Hits = (Collider[])(object)new Collider[8];

		private static readonly Collider[] Around = (Collider[])(object)new Collider[64];

		private static readonly HashSet<string> Family = new HashSet<string>();

		private static readonly Queue<long> Open = new Queue<long>();

		private static readonly HashSet<long> Seen = new HashSet<long>();

		private static bool? _rulesChanged;

		private static bool _probeFailed;

		public static void Clear()
		{
			Active = false;
			Kind = null;
			_lastKind = null;
			_familyFor = null;
		}

		public static void Update(Player player, GameObject ghost)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			Active = false;
			if (Kind == null || (Object)(object)ghost == (Object)null || !ghost.activeInHierarchy || !Plugin.GridOn)
			{
				return;
			}
			Fill = Plugin.FillOn;
			Rows = Plugin.Rows;
			Columns = Plugin.Columns;
			if (Fill || Mathf.Min(Rows * Columns, Plugin.MaxPlants) >= 2)
			{
				Active = true;
				float spacing = Kind.Spacing;
				Vector3 position = ghost.transform.position;
				Rotation = ghost.transform.rotation;
				Vector3 val = (Plugin.WorldAligned ? Vector3.forward : Utils.DirectionXZ(position - ((Component)player).transform.position));
				if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
				{
					val = Vector3.forward;
				}
				Vector3 row = Flat(Rotation * val);
				Vector3 column = Vector3.Cross(Vector3.up, row);
				Vector3 root = position;
				Snapped = Plugin.SnapOn && Snap(position, spacing, ref row, ref column, out root);
				if (!Snapped && Fill)
				{
					root = row * (Mathf.Round(Vector3.Dot(position, row) / spacing) * spacing) + column * (Mathf.Round(Vector3.Dot(position, column) / spacing) * spacing);
				}
				root.y = position.y;
				Root = root;
				RowStep = row * spacing;
				ColumnStep = column * spacing;
				if (Kind != _lastKind || Fill != _lastFill || Rows != _lastRows || Columns != _lastColumns || Plugin.MaxPlants != _lastMax || !Mathf.Approximately(spacing, _lastSpacing) || Flat2(Root - _lastRoot) > 0.0001f || Vector3.Angle(row, _lastRow) > 0.5f || Quaternion.Angle(Rotation, _lastRotation) > 0.5f || Planter.Queued != _lastQueued || Time.time >= _nextCheck)
				{
					_lastKind = Kind;
					_lastFill = Fill;
					_lastRows = Rows;
					_lastColumns = Columns;
					_lastMax = Plugin.MaxPlants;
					_lastSpacing = spacing;
					_lastRoot = Root;
					_lastRow = row;
					_lastRotation = Rotation;
					_lastQueued = Planter.Queued;
					_nextCheck = Time.time + 0.5f;
					Stopwatch stopwatch = Stopwatch.StartNew();
					Layout();
					Check(player);
					LastCheckMs = (float)stopwatch.Elapsed.TotalMilliseconds;
				}
				if (Count > 0 && (Snapped || Fill))
				{
					ghost.transform.position = Positions[0];
				}
			}
		}

		private static void Layout()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			Note = "";
			if (!Fill)
			{
				Count = Mathf.Min(Rows * Columns, Plugin.MaxPlants);
				Ensure(Count);
				for (int i = 0; i < Count; i++)
				{
					Positions[i] = Root + RowStep * (float)(i / Columns) + ColumnStep * (float)(i % Columns);
				}
				return;
			}
			Count = 0;
			Ensure(1);
			if (!Cultivated(Root))
			{
				Positions[0] = Root;
				Count = 1;
				Note = "not on cultivated ground";
				return;
			}
			int maxPlants = Plugin.MaxPlants;
			float num = Plugin.FillReach * Plugin.FillReach;
			Seen.Clear();
			Open.Clear();
			Seen.Add(Key(0, 0));
			Open.Enqueue(Key(0, 0));
			while (Open.Count > 0 && Count < maxPlants)
			{
				long num2 = Open.Dequeue();
				int num3 = (int)(num2 >> 32);
				int num4 = (int)(num2 & 0xFFFFFFFFu);
				Ensure(Count + 1);
				Positions[Count++] = Root + RowStep * (float)num3 + ColumnStep * (float)num4;
				for (int j = 0; j < 4; j++)
				{
					int num5 = num3 + j switch
					{
						1 => -1, 
						0 => 1, 
						_ => 0, 
					};
					int num6 = num4 + j switch
					{
						3 => -1, 
						2 => 1, 
						_ => 0, 
					};
					long item = Key(num5, num6);
					if (Seen.Add(item))
					{
						Vector3 val = Root + RowStep * (float)num5 + ColumnStep * (float)num6;
						if (Flat2(val - Root) <= num && Cultivated(val))
						{
							Open.Enqueue(item);
						}
					}
				}
			}
			if (Open.Count > 0 && Count >= maxPlants)
			{
				Note = "more than the most plants per click";
			}
		}

		private static bool Snap(Vector3 raw, float s, ref Vector3 row, ref Vector3 column, out Vector3 root)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			root = raw;
			if (_familyFor != Kind)
			{
				_familyFor = Kind;
				Family.Clear();
				Family.Add(Kind.Name);
				if ((Object)(object)Kind.Plant != (Object)null)
				{
					GameObject[] grownPrefabs = Kind.Plant.m_grownPrefabs;
					foreach (GameObject val in grownPrefabs)
					{
						if ((Object)(object)val != (Object)null)
						{
							Family.Add(((Object)val).name);
						}
					}
				}
			}
			if (!Nearest(raw, Mathf.Max(0.5f, s * 1.6f), raw, notAtFrom: false, out var found))
			{
				return false;
			}
			if (Nearest(found, s * 1.6f, found, notAtFrom: true, out var found2))
			{
				Vector3 val2 = Flat(found2 - found);
				if (Mathf.Abs(Vector3.Dot(val2, row)) >= Mathf.Abs(Vector3.Dot(val2, column)))
				{
					row = ((Vector3.Dot(val2, row) >= 0f) ? val2 : (-val2));
					Vector3 val3 = Vector3.Cross(Vector3.up, row);
					column = ((Vector3.Dot(val3, column) >= 0f) ? val3 : (-val3));
				}
				else
				{
					column = ((Vector3.Dot(val2, column) >= 0f) ? val2 : (-val2));
					Vector3 val4 = Vector3.Cross(column, Vector3.up);
					row = ((Vector3.Dot(val4, row) >= 0f) ? val4 : (-val4));
				}
			}
			Vector3 val5 = raw - found;
			int num = Mathf.RoundToInt(Vector3.Dot(val5, row) / s);
			int num2 = Mathf.RoundToInt(Vector3.Dot(val5, column) / s);
			if (num == 0 && num2 == 0)
			{
				if (Mathf.Abs(Vector3.Dot(val5, row)) >= Mathf.Abs(Vector3.Dot(val5, column)))
				{
					num = ((Vector3.Dot(val5, row) >= 0f) ? 1 : (-1));
				}
				else
				{
					num2 = ((Vector3.Dot(val5, column) >= 0f) ? 1 : (-1));
				}
			}
			root = found + row * (s * (float)num) + column * (s * (float)num2);
			if (Mathf.Abs(num) >= Mathf.Abs(num2))
			{
				if (num < 0)
				{
					row = -row;
				}
			}
			else if (num2 < 0)
			{
				column = -column;
			}
			return true;
		}

		private static bool Nearest(Vector3 center, float radius, Vector3 from, bool notAtFrom, out Vector3 found)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			found = Vector3.zero;
			float num = float.MaxValue;
			float num2 = radius * radius;
			int num3 = Physics.OverlapSphereNonAlloc(center, radius, Around, AnchorMask);
			for (int i = 0; i < num3; i++)
			{
				ZNetView componentInParent = ((Component)Around[i]).GetComponentInParent<ZNetView>();
				if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsValid() && Family.Contains(Utils.GetPrefabName(((Component)componentInParent).gameObject)))
				{
					Vector3 position = ((Component)componentInParent).transform.position;
					float num4 = Flat2(position - from);
					if ((!notAtFrom || !(num4 < 0.0025f)) && !(Flat2(position - center) > num2) && !(num4 >= num))
					{
						num = num4;
						found = position;
					}
				}
			}
			if (Planter.Left > 0 && Planter.Nearest(center, radius, Kind.Prefab, from, notAtFrom, out var found2, out var bestD) && bestD < num)
			{
				num = bestD;
				found = found2;
			}
			return num < float.MaxValue;
		}

		private static Vector3 Flat(Vector3 v)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			v.y = 0f;
			if (!(((Vector3)(ref v)).sqrMagnitude > 1E-08f))
			{
				return Vector3.forward;
			}
			return ((Vector3)(ref v)).normalized;
		}

		private static float Flat2(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return v.x * v.x + v.z * v.z;
		}

		private static long Key(int i, int j)
		{
			return ((long)i << 32) | (uint)j;
		}

		private static bool Cultivated(Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Heightmap val = HeightmapAt(p);
			if ((Object)(object)val != (Object)null)
			{
				return val.IsCultivated(p);
			}
			return false;
		}

		private static void Ensure(int n)
		{
			if (Positions.Length < n)
			{
				int newSize = Mathf.Max(new int[3]
				{
					n,
					Positions.Length * 2,
					64
				});
				Array.Resize(ref Positions, newSize);
				Array.Resize(ref Spots, newSize);
			}
		}

		private static void Check(Player player)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: 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_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Invalid comparison between Unknown and I4
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Invalid comparison between Unknown and I4
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Invalid comparison between Unknown and I4
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (Object)(object)Kind.Plant != (Object)null;
			float num = float.MaxValue;
			float num2 = float.MinValue;
			float num3 = float.MaxValue;
			float num4 = float.MinValue;
			for (int i = 0; i < Count; i++)
			{
				Vector3 val = Positions[i];
				if (val.x < num)
				{
					num = val.x;
				}
				if (val.x > num2)
				{
					num2 = val.x;
				}
				if (val.z < num3)
				{
					num3 = val.z;
				}
				if (val.z > num4)
				{
					num4 = val.z;
				}
			}
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor((num + num2) * 0.5f, Root.y, (num3 + num4) * 0.5f);
			Vector2 val3 = new Vector2(num2 - num, num4 - num3);
			float num5 = ((Vector2)(ref val3)).magnitude * 0.5f + Kind.Spacing;
			Wards.Clear();
			foreach (PrivateArea allArea in PrivateArea.m_allAreas)
			{
				if ((Object)(object)allArea != (Object)null && allArea.IsEnabled() && !allArea.HaveLocalAccess() && allArea.IsInside(val2, num5))
				{
					Wards.Add(allArea);
				}
			}
			NoBuild.Clear();
			foreach (Location s_allLocation in Location.s_allLocations)
			{
				if ((Object)(object)s_allLocation != (Object)null && s_allLocation.m_noBuild && s_allLocation.IsInside(val2, num5, true))
				{
					NoBuild.Add(s_allLocation);
				}
			}
			bool flag2 = ShieldGenerator.m_instances.Count > 0;
			float distance = Kind.Spacing * 0.5f;
			Todo.Clear();
			float y = default(float);
			for (int j = 0; j < Count; j++)
			{
				Vector3 val4 = Positions[j];
				Spot spot = Spot.Ok;
				Heightmap val5 = HeightmapAt(val4);
				if ((Object)(object)val5 == (Object)null || !val5.GetWorldHeight(val4, ref y))
				{
					spot = Spot.Invalid;
				}
				else
				{
					val4.y = y;
					if (Wards.Count > 0 && !PrivateArea.CheckAccess(val4, 0f, false, false))
					{
						spot = Spot.Blocked;
					}
					else if (NoBuild.Count > 0 && InsideNoBuild(val4))
					{
						spot = Spot.Blocked;
					}
					else
					{
						Biome biome = val5.GetBiome(val4, 0.02f, false);
						if ((int)Kind.Biome != 0 && (biome & Kind.Biome) == 0)
						{
							spot = Spot.WrongBiome;
						}
						else if (Kind.NeedCultivated && !val5.IsCultivated(val4))
						{
							spot = Spot.NotCultivated;
						}
						else if (flag && !Kind.TolerateHeat && (int)biome == 32 && (!flag2 || !ShieldGenerator.IsInsideShield(val4)))
						{
							spot = Spot.TooHot;
						}
						else if (flag && !Kind.TolerateCold && ((int)biome == 64 || (int)biome == 4) && (!flag2 || !ShieldGenerator.IsInsideShield(val4)))
						{
							spot = Spot.TooCold;
						}
						else if (Planter.Left > 0 && Planter.Near(val4, distance))
						{
							spot = Spot.Taken;
						}
					}
				}
				Positions[j] = val4;
				Spots[j] = spot;
				if (spot == Spot.Ok)
				{
					Todo.Add(j);
				}
			}
			if (!_batchFailed)
			{
				try
				{
					Batched(flag);
				}
				catch (Exception ex)
				{
					_batchFailed = true;
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("Batched physics checks are not available here, checking one by one: " + ex.Message));
					}
					OneByOne(flag);
				}
			}
			else
			{
				OneByOne(flag);
			}
			if (flag && GameRulesChanged())
			{
				AskTheGame(player);
			}
			Seeds = Plugin.ExtraPlantsPaid(player, Kind);
			int num6 = 0;
			for (int k = 1; k < Count; k++)
			{
				if (Spots[k] == Spot.Ok)
				{
					if (num6 < Seeds)
					{
						num6++;
					}
					else
					{
						Spots[k] = Spot.NoSeeds;
					}
				}
			}
			Array.Clear(Tally, 0, Tally.Length);
			for (int l = 0; l < Count; l++)
			{
				Tally[(uint)Spots[l]]++;
			}
			Version++;
		}

		private static void Batched(bool plant)
		{
			//IL_0086: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			int count = Todo.Count;
			if (count == 0)
			{
				return;
			}
			NativeArray<OverlapSphereCommand> val = default(NativeArray<OverlapSphereCommand>);
			val..ctor(count, (Allocator)3, (NativeArrayOptions)1);
			NativeArray<ColliderHit> val2 = default(NativeArray<ColliderHit>);
			val2..ctor(count * 8, (Allocator)3, (NativeArrayOptions)1);
			NativeArray<RaycastCommand> val3 = default(NativeArray<RaycastCommand>);
			val3..ctor(plant ? count : 0, (Allocator)3, (NativeArrayOptions)1);
			NativeArray<RaycastHit> val4 = default(NativeArray<RaycastHit>);
			val4..ctor(plant ? count : 0, (Allocator)3, (NativeArrayOptions)1);
			try
			{
				QueryParameters val5 = default(QueryParameters);
				((QueryParameters)(ref val5))..ctor(plant ? SpaceMask : PickableMask, false, (QueryTriggerInteraction)0, false);
				QueryParameters val6 = default(QueryParameters);
				((QueryParameters)(ref val6))..ctor(RoofMask, false, (QueryTriggerInteraction)0, false);
				for (int i = 0; i < count; i++)
				{
					Vector3 val7 = Positions[Todo[i]];
					val[i] = (plant ? new OverlapSphereCommand(val7, Kind.GrowRadius, val5) : new OverlapSphereCommand(val7 + Vector3.up * 0.05f, 0.05f, val5));
					if (plant)
					{
						val3[i] = new RaycastCommand(val7, Vector3.up, val6, 100f);
					}
				}
				JobHandle val8 = OverlapSphereCommand.ScheduleBatch(val, val2, 32, 8, default(JobHandle));
				if (plant)
				{
					val8 = JobHandle.CombineDependencies(val8, RaycastCommand.ScheduleBatch(val3, val4, 32, 1, default(JobHandle)));
				}
				((JobHandle)(ref val8)).Complete();
				for (int j = 0; j < count; j++)
				{
					int num = Todo[j];
					if (plant)
					{
						RaycastHit val9 = val4[j];
						if ((Object)(object)((RaycastHit)(ref val9)).collider != (Object)null)
						{
							Spots[num] = Spot.NoSun;
							continue;
						}
					}
					for (int k = 0; k < 8; k++)
					{
						ColliderHit val10 = val2[j * 8 + k];
						if (((ColliderHit)(ref val10)).instanceID == 0)
						{
							break;
						}
						if (Blocks(((ColliderHit)(ref val10)).collider, plant))
						{
							Spots[num] = Spot.NoSpace;
							break;
						}
					}
				}
			}
			finally
			{
				val.Dispose();
				val2.Dispose();
				val3.Dispose();
				val4.Dispose();
			}
		}

		private static void OneByOne(bool plant)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			foreach (int item in Todo)
			{
				Vector3 val = Positions[item];
				if (plant && Physics.Raycast(val, Vector3.up, 100f, RoofMask))
				{
					Spots[item] = Spot.NoSun;
					continue;
				}
				int num = (plant ? Physics.OverlapSphereNonAlloc(val, Kind.GrowRadius, Hits, SpaceMask) : Physics.OverlapSphereNonAlloc(val + Vector3.up * 0.05f, 0.05f, Hits, PickableMask));
				for (int i = 0; i < num; i++)
				{
					if (Blocks(Hits[i], plant))
					{
						Spots[item] = Spot.NoSpace;
						break;
					}
				}
			}
		}

		private static bool GameRulesChanged()
		{
			if (_rulesChanged.HasValue)
			{
				return _rulesChanged.Value;
			}
			_rulesChanged = Patched("HaveGrowSpace") || Patched("HaveRoof");
			if (_rulesChanged.Value)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Another mod changes the game's plant room or roof check: spots are checked through it.");
				}
			}
			return _rulesChanged.Value;
			static bool Patched(string name)
			{
				Patches patchInfo = Harmony.GetPatchInfo((MethodBase)AccessTools.Method(typeof(Plant), name, (Type[])null, (Type[])null));
				if (patchInfo != null)
				{
					return patchInfo.Prefixes.Count + patchInfo.Postfixes.Count + patchInfo.Transpilers.Count + patchInfo.Finalizers.Count > 0;
				}
				return false;
			}
		}

		private static void AskTheGame(Player player)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (_probeFailed || (Object)(object)player.m_placementGhost == (Object)null)
			{
				return;
			}
			Plant component = player.m_placementGhost.GetComponent<Plant>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)component).transform;
			Vector3 position = transform.position;
			try
			{
				for (int i = 0; i < Count; i++)
				{
					if (Spots[i] == Spot.NoSpace || Spots[i] == Spot.NoSun)
					{
						transform.position = Positions[i];
						Spots[i] = (component.HaveRoof() ? Spot.NoSun : ((!component.HaveGrowSpace()) ? Spot.NoSpace : Spot.Ok));
					}
				}
			}
			catch (Exception ex)
			{
				_probeFailed = true;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not ask the game's own plant check: " + ex.Message));
				}
			}
			finally
			{
				transform.position = position;
			}
		}

		private static bool Blocks(Collider c, bool plant)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			if (!plant)
			{
				return true;
			}
			Plant component = ((Component)c).GetComponent<Plant>();
			if (!((Object)(object)component == (Object)null))
			{
				return (int)component.m_status == 0;
			}
			return true;
		}

		private static Heightmap HeightmapAt(Vector3 p)
		{
			//IL_0025: 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)
			if ((Object)(object)_heightmap != (Object)null && _heightmap.IsPointInside(p, 0f))
			{
				return _heightmap;
			}
			_heightmap = Heightmap.FindHeightmap(p);
			return _heightmap;
		}

		private static bool InsideNoBuild(Vector3 p)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			foreach (Location item in NoBuild)
			{
				if ((Object)(object)item != (Object)null && item.IsInside(p, 0f, true))
				{
					return true;
				}
			}
			return false;
		}

		public static bool Bad(Spot spot)
		{
			if (spot != Spot.Ok && spot != Spot.NoSeeds)
			{
				return spot != Spot.Taken;
			}
			return false;
		}
	}
	internal static class Harvest
	{
		public enum Replant
		{
			HarvestedCrop,
			SelectedCrop
		}

		private static ConfigEntry<bool> _on;

		private static ConfigEntry<bool> _sameKind;

		private static ConfigEntry<bool> _hints;

		private static ConfigEntry<Modifier> _key;

		private static ConfigEntry<Modifier> _replantKey;

		private static ConfigEntry<float> _radius;

		private static ConfigEntry<Replant> _replantWhat;

		private static readonly Collider[] Around = (Collider[])(object)new Collider[4096];

		private static readonly HashSet<Component> Found = new HashSet<Component>();

		private static readonly List<Component> Picks = new List<Component>();

		private static readonly Dictionary<GameObject, List<Vector3>> ToReplant = new Dictionary<GameObject, List<Vector3>>();

		private static readonly Dictionary<string, GameObject> SaplingOf = new Dictionary<string, GameObject>();

		private static int _depth;

		private static bool _replantNow;

		internal static void Bind(ModuleConfig config)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			_on = config.Bind("Harvest", "Harvest around", defaultValue: true, "Hold the harvest key while you pick a crop, berry bush, mushroom or beehive: everything around it is picked at once.");
			_key = config.Bind("Harvest", "Harvest key", Modifier.Shift, "Hold this (left or right) while picking to pick everything around you.");
			_radius = config.Bind("Harvest", "Harvest radius (m)", 3f, new ConfigDescription("How far around the thing you pick the rest is picked.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			_sameKind = config.Bind("Harvest", "Same kind only", defaultValue: false, "Only things of the kind you picked are picked around it (only barley when you pick barley). Off: everything pickable around it.");
			_replantKey = config.Bind("Harvest", "Replant key", Modifier.Ctrl, "Hold this (left or right) while picking a crop to plant it again on its spot (with the harvest key too: everything picked around it). Seeds come from your bag, then nearby chests.");
			_replantWhat = config.Bind("Harvest", "Replant with", Replant.HarvestedCrop, "HarvestedCrop: the crop you picked. SelectedCrop: the crop chosen in the cultivator (or the picked one when none is).");
			_hints = config.Bind("Display", "Harvest hints", defaultValue: true, "Aiming at a crop, bush or beehive shows the harvest and replant keys.");
		}

		internal static void Copy(Dictionary<string, string> cfg, Action<Dictionary<string, string>, string, ConfigEntry<bool>> b, Action<Dictionary<string, string>, string, ConfigEntry<float>> f, Action<Dictionary<string, string>, string, ConfigEntry<Modifier>> k)
		{
			b(cfg, "Harvesting.EnableBulkHarvest", _on);
			f(cfg, "Harvesting.HarvestRadius", _radius);
			k(cfg, "Controls.KeyboardHarvestModifierKey", _key);
			if (cfg.TryGetValue("Harvesting.HarvestStyle", out var value))
			{
				_sameKind.Value = value.Trim() == "LikeResources";
			}
			if (cfg.TryGetValue("Harvesting.ReplantStyle", out var value2))
			{
				_replantWhat.Value = ((value2.Trim() == "SelectedCrop") ? Replant.SelectedCrop : Replant.HarvestedCrop);
			}
		}

		internal static void Learn(PieceTable tool)
		{
			foreach (GameObject piece in tool.m_pieces)
			{
				Plant val = (((Object)(object)piece != (Object)null) ? piece.GetComponent<Plant>() : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				GameObject[] grownPrefabs = val.m_grownPrefabs;
				foreach (GameObject val2 in grownPrefabs)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<Pickable>() != (Object)null && !SaplingOf.ContainsKey(((Object)val2).name))
					{
						SaplingOf[((Object)val2).name] = piece;
					}
				}
			}
		}

		private static void LearnOnce()
		{
			if (SaplingOf.Count <= 0)
			{
				GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Cultivator") : null);
				PieceTable val2 = ((!((Object)(object)val != (Object)null)) ? null : val.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
				if ((Object)(object)val2 != (Object)null)
				{
					Learn(val2);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Interact", new Type[]
		{
			typeof(GameObject),
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static void PickAround(Player __instance, GameObject go, bool hold, bool alt)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)go == (Object)null)
			{
				return;
			}
			if (_depth++ == 0)
			{
				_replantNow = Plugin.Held(_replantKey.Value);
			}
			if (!_on.Value || ((Character)__instance).InAttack() || ((Character)__instance).InDodge() || (hold && Time.time - __instance.m_lastHoverInteractTime < 0.2f) || (!Plugin.Held(_key.Value) && !alt))
			{
				return;
			}
			Interactable componentInParent = go.GetComponentInParent<Interactable>();
			Component val = (Component)(object)((componentInParent is Component) ? componentInParent : null);
			if (!(val is Pickable) && !(val is Beehive))
			{
				return;
			}
			Transform root = val.transform.root;
			int num = Physics.OverlapSphereNonAlloc(root.position, _radius.Value, Around, Grid.SpaceMask | LayerMask.GetMask(new string[1] { "item" }));
			Found.Clear();
			Picks.Clear();
			for (int i = 0; i < num; i++)
			{
				Collider val2 = Around[i];
				Component componentInParent2 = (Component)(object)((Component)val2).GetComponentInParent<Pickable>();
				if ((Object)(object)componentInParent2 == (Object)null)
				{
					componentInParent2 = (Component)(object)((Component)val2).GetComponentInParent<Beehive>();
				}
				if (!((Object)(object)componentInParent2 == (Object)null) && !((Object)(object)componentInParent2.transform.root == (Object)(object)root) && Found.Add(componentInParent2) && (!_sameKind.Value || !(((Object)componentInParent2.transform.root).name != ((Object)root).name)))
				{
					Beehive val3 = (Beehive)(object)((componentInParent2 is Beehive) ? componentInParent2 : null);
					if (val3 == null || val3.GetHoneyLevel() >= 1)
					{
						Picks.Add(componentInParent2);
					}
				}
			}
			foreach (Component pick in Picks)
			{
				if ((Object)(object)pick != (Object)null)
				{
					((Interactable)pick).Interact((Humanoid)(object)__instance, hold, alt);
				}
			}
			Picks.Clear();
			Found.Clear();
		}

		[HarmonyPatch(typeof(Player), "Interact", new Type[]
		{
			typeof(GameObject),
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyFinalizer]
		private static Exception AfterInteract(Player __instance, Exception __exception)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || _depth == 0)
			{
				return __exception;
			}
			if (--_depth > 0)
			{
				return __exception;
			}
			_replantNow = false;
			if (ToReplant.Count == 0)
			{
				return __exception;
			}
			try
			{
				ReplantNow(__instance);
				return __exception;
			}
			finally
			{
				ToReplant.Clear();
			}
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		[HarmonyPrefix]
		private static void Picked(Pickable __instance, Humanoid character)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (!_replantNow || (Object)(object)character != (Object)(object)Player.m_localPlayer || _depth == 0 || __instance.m_picked || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || __instance.m_enabled == 0)
			{
				return;
			}
			LearnOnce();
			if (!SaplingOf.TryGetValue(Utils.GetPrefabName(((Component)__instance).gameObject), out var value))
			{
				return;
			}
			if (_replantWhat.Value == Replant.SelectedCrop)
			{
				PieceTable buildPieces = Player.m_localPlayer.m_buildPieces;
				GameObject val = ((buildPieces != null) ? buildPieces.GetSelectedPrefab() : null);
				Plant val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Plant>() : null);
				if ((Object)(object)val2 != (Object)null && val2.m_attachDistance <= 0f)
				{
					value = val;
				}
			}
			if (!ToReplant.TryGetValue(value, out var value2))
			{
				value2 = (ToReplant[value] = new List<Vector3>());
			}
			value2.Add(((Component)__instance).transform.position);
		}

		private static void ReplantNow(Player player)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			Planter.Owner(player);
			foreach (KeyValuePair<GameObject, List<Vector3>> item in ToReplant)
			{
				Kind kind = Kind.Of(item.Key);
				if (kind == null)
				{
					continue;
				}
				int num = Plugin.ExtraPlantsPaid(player, kind);
				int num2 = ((num == int.MaxValue) ? item.Value.Count : Mathf.Min(item.Value.Count, num + 1));
				if (num2 > 0 && num != int.MaxValue)
				{
					num2 = Plugin.Pay(player, kind, num2);
				}
				if (num2 <= 0)
				{
					((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false);
					continue;
				}
				Game.instance.IncrementPlayerStat((PlayerStatType)2, (float)num2, false);
				for (int i = 0; i < num2; i++)
				{
					Planter.Add(item.Key, item.Value[i], Quaternion.Euler(0f, 22.5f * (float)Random.Range(0, 16), 0f));
				}
				if (num2 < item.Value.Count)
				{
					((Character)player).Message((MessageType)2, $"Seeds to replant {num2} of {item.Value.Count}", 0, (Sprite)null, false);
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "GetHoverText")]
		[HarmonyPostfix]
		private static void Hint(Pickable __instance, ref string __result)
		{
			if (!_hints.Value || string.IsNullOrEmpty(__result))
			{
				return;
			}
			if (_on.Value)
			{
				__result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_key.Value) + " + $KEY_Use</b></color>] Harvest around");
			}
			LearnOnce();
			if (SaplingOf.ContainsKey(Utils.GetPrefabName(((Component)__instance).gameObject)))
			{
				__result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_replantKey.Value) + " + $KEY_Use</b></color>] Harvest and replant");
				if (_on.Value)
				{
					__result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_replantKey.Value) + " + " + Name(_key.Value) + " + $KEY_Use</b></color>] Harvest around and replant");
				}
			}
		}

		[HarmonyPatch(typeof(Beehive), "GetHoverText")]
		[HarmonyPostfix]
		private static void HiveHint(ref string __result)
		{
			if (_hints.Value && _on.Value && !string.IsNullOrEmpty(__result))
			{
				__result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_key.Value) + " + $KEY_Use</b></color>] Harvest around");
			}
		}

		private static string Name(Modifier key)
		{
			return key.ToString();
		}
	}
	internal static class Planter
	{
		private struct Job
		{
			public GameObject Prefab;

			public Vector3 Pos;

			public Quaternion Rot;
		}

		private static readonly Queue<Job> Jobs = new Queue<Job>();

		private static readonly Dictionary<long, List<Job>> Squares = new Dictionary<long, List<Job>>();

		private static long _creator;

		private static PlatformUserID _platformUser;

		private static SkillType _skill;

		public static int Planted;

		public static int Queued;

		public static float LastFrameMs;

		public static int Left => Jobs.Count;

		public static void Add(GameObject prefab, Vector3 pos, Quaternion rot)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Job item = new Job
			{
				Prefab = prefab,
				Pos = pos,
				Rot = rot
			};
			Jobs.Enqueue(item);
			Queued++;
			long key = Key(pos);
			if (!Squares.TryGetValue(key, out var value))
			{
				value = (Squares[key] = new List<Job>());
			}
			value.Add(item);
		}

		public static void Owner(Player player)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			_creator = player.GetPlayerID();
			_platformUser = ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID;
			_skill = (SkillType)((!((Object)(object)player.m_buildPieces != (Object)null)) ? 106 : ((int)player.m_buildPieces.m_skill));
		}

		public static void Work(float budgetMs)
		{
			if (Jobs.Count != 0)
			{
				Stopwatch stopwatch = Stopwatch.StartNew();
				while (Jobs.Count > 0 && stopwatch.Elapsed.TotalMilliseconds < (double)budgetMs)
				{
					PlantOne();
				}
				LastFrameMs = (float)stopwatch.Elapsed.TotalMilliseconds;
			}
		}

		public static void Finish()
		{
			while (Jobs.Count > 0)
			{
				PlantOne();
			}
		}

		public static bool Near(Vector3 p, float distance)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			float num = distance * distance;
			int num2 = Mathf.FloorToInt(p.x);
			int num3 = Mathf.FloorToInt(p.z);
			int num4 = Mathf.CeilToInt(distance);
			for (int i = num2 - num4; i <= num2 + num4; i++)
			{
				for (int j = num3 - num4; j <= num3 + num4; j++)
				{
					if (!Squares.TryGetValue(((long)i << 32) ^ (uint)j, out var value))
					{
						continue;
					}
					foreach (Job item in value)
					{
						float num5 = item.Pos.x - p.x;
						float num6 = item.Pos.z - p.z;
						if (num5 * num5 + num6 * num6 < num)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		public static bool Nearest(Vector3 center, float radius, GameObject prefab, Vector3 from, bool notAtFrom, out Vector3 found, out float bestD2)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			found = Vector3.zero;
			bestD2 = float.MaxValue;
			float num = radius * radius;
			int num2 = Mathf.FloorToInt(center.x);
			int num3 = Mathf.FloorToInt(center.z);
			int num4 = Mathf.CeilToInt(radius);
			for (int i = num2 - num4; i <= num2 + num4; i++)
			{
				for (int j = num3 - num4; j <= num3 + num4; j++)
				{
					if (!Squares.TryGetValue(((long)i << 32) ^ (uint)j, out var value))
					{
						continue;
					}
					foreach (Job item in value)
					{
						if ((Object)(object)item.Prefab != (Object)(object)prefab)
						{
							continue;
						}
						float num5 = item.Pos.x - center.x;
						float num6 = item.Pos.z - center.z;
						if (!(num5 * num5 + num6 * num6 > num))
						{
							float num7 = item.Pos.x - from.x;
							float num8 = item.Pos.z - from.z;
							float num9 = num7 * num7 + num8 * num8;
							if ((!notAtFrom || !(num9 < 0.0025f)) && !(num9 >= bestD2))
							{
								bestD2 = num9;
								found = item.Pos;
							}
						}
					}
				}
			}
			return bestD2 < float.MaxValue;
		}

		public static void CopyQueued(List<Matrix4x4> into, Vector3 scale)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			into.Clear();
			foreach (Job job in Jobs)
			{
				into.Add(Matrix4x4.TRS(job.Pos, job.Rot, scale));
			}
		}

		private static void PlantOne()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			Job job = Jobs.Dequeue();
			long key = Key(job.Pos);
			if (Squares.TryGetValue(key, out var value))
			{
				for (int i = 0; i < value.Count; i++)
				{
					if (value[i].Pos == job.Pos && (Object)(object)value[i].Prefab == (Object)(object)job.Prefab)
					{
						value.RemoveAt(i);
						break;
					}
				}
				if (value.Count == 0)
				{
					Squares.Remove(key);
				}
			}
			if (!((Object)(object)job.Prefab == (Object)null))
			{
				TerrainModifier.SetTriggerOnPlaced(true);
				GameObject obj = Object.Instantiate<GameObject>(job.Prefab, job.Pos, job.Rot);
				TerrainModifier.SetTriggerOnPlaced(false);
				Piece component = obj.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetCreator(_creator, _platformUser);
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && (int)_skill != 0)
				{
					((Character)localPlayer).RaiseSkill(_skill, 1f);
				}
				Planted++;
			}
		}

		private static long Key(Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return ((long)Mathf.FloorToInt(p.x) << 32) ^ (uint)Mathf.FloorToInt(p.z);
		}
	}
	public enum Modifier
	{
		Ctrl,
		Shift,
		Alt
	}
	public class Plugin : DigiModule
	{
		private const string PlantEasilyGuid = "advize.PlantEasily";

		private const string PlantEasilyConfig = "advize.PlantEasily.cfg";

		internal static ManualLogSource Log;

		private static bool _running;

		private static ConfigEntry<bool> _gridOn;

		private static ConfigEntry<bool> _snapOn;

		private static ConfigEntry<bool> _fillOn;

		private static ConfigEntry<bool> _worldAligned;

		private static ConfigEntry<bool> _tighter;

		private static ConfigEntry<bool> _onlyWhereItGrows;

		private static ConfigEntry<bool> _allOrNothing;

		private static ConfigEntry<bool> _stamina;

		private static ConfigEntry<bool> _durability;

		private static ConfigEntry<bool> _randomRotation;

		private static ConfigEntry<bool> _preview;

		private static ConfigEntry<bool> _count;

		private static ConfigEntry<int> _rows;

		private static ConfigEntry<int> _columns;

		private static ConfigEntry<int> _maxPlants;

		private static ConfigEntry<float> _extraCrop;

		private static ConfigEntry<float> _extraSapling;

		private static ConfigEntry<float> _pickableSpacing;

		private static ConfigEntry<float> _scatter;

		private static ConfigEntry<float> _tilt;

		private static ConfigEntry<float> _budget;

		private static ConfigEntry<float> _fillReach;

		private static ConfigEntry<KeyCode> _toggleKey;

		private static ConfigEntry<KeyCode> _snapKey;

		private static ConfigEntry<KeyCode> _fillKey;

		private static ConfigEntry<KeyCode> _moreColumns;

		private static ConfigEntry<KeyCode> _fewerColumns;

		private static ConfigEntry<KeyCode> _moreRows;

		private static ConfigEntry<KeyCode> _fewerRows;

		private static ConfigEntry<Modifier> _sizeModifier;

		private static ConfigEntry<Modifier> _wheelModifier;

		private static TextMeshProUGUI _label;

		private static GameObject _labelRoot;

		private static List<Vector3> _clicked;

		private static Kind _clickedKind;

		private static Quaternion _clickedRotation;

		private static int _rotationBefore;

		private static bool _keepRotation;

		private static int _turnBefore;

		private static readonly Dictionary<string, ConfigEntry<float>> Bushes = new Dictionary<string, ConfigEntry<float>>();

		private static readonly Dictionary<string, float> BushDefaults = new Dictionary<string, float>
		{
			{ "Pickable_Dandelion", 0.75f },
			{ "Pickable_Fiddlehead", 1f },
			{ "Pickable_Mushroom", 0.5f },
			{ "Pickable_Mushroom_blue", 0.5f },
			{ "Pickable_Mushroom_yellow", 0.5f },
			{ "Pickable_SmokePuff", 1f },
			{ "Pickable_Thistle", 0.75f },
			{ "BlueberryBush", 1.5f },
			{ "RaspberryBush", 1.5f },
			{ "CloudberryBush", 1f },
			{ "LingonberryBush", 1.5f }
		};

		private static Plugin _instance;

		internal static bool GridOn => _gridOn.Value;

		internal static bool SnapOn => _snapOn.Value;

		internal static bool FillOn => _fillOn.Value;

		internal static float FillReach => _fillReach.Value;

		internal static int Rows => _rows.Value;

		internal static int Columns => _columns.Value;

		internal static int MaxPlants => _maxPlants.Value;

		internal static bool WorldAligned => _worldAligned.Value;

		internal static bool ShowPreview => _preview.Value;

		private void Awake()
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Expected O, but got Unknown
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Expected O, but got Unknown
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Expected O, but got Unknown
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Expected O, but got Unknown
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Expected O, but got Unknown
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Expected O, but got Unknown
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Expected O, but got Unknown
			_instance = this;
			Log = base.Logger;
			_gridOn = base.Config.Bind("General", "Grid on", defaultValue: true, "Plant a whole grid with each click of the cultivator. The toggle key switches it while you play.");
			_toggleKey = base.Config.Bind<KeyCode>("General", "Toggle key", (KeyCode)289, "Turns the grid on or off.");
			_snapOn = base.Config.Bind("General", "Line up with fields", defaultValue: true, "Aiming next to plants of the same kind (planted, grown or still being planted), the grid continues their field: same lines and spacing, starting on the free spot next to them nearest your aim, and growing away from them. The snap key switches it while you play.");
			_snapKey = base.Config.Bind<KeyCode>("General", "Snap key", (KeyCode)291, "Turns lining up with fields on or off.");
			_fillOn = base.Config.Bind("General", "Fill field", defaultValue: false, "Instead of rows x columns, the grid is every free spot of the cultivated patch under your aim (up to the most plants per click): one click plants a whole field. The fill key switches it while you play.");
			_fillKey = base.Config.Bind<KeyCode>("General", "Fill key", (KeyCode)288, "Turns Fill field on or off.");
			_fillReach = base.Config.Bind("General", "Fill reach (m)", 40f, new ConfigDescription("Fill field plants no further than this from your aim.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			_rows = base.Config.Bind("Grid", "Rows", 2, new ConfigDescription("Rows of plants (away from you).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>()));
			_columns = base.Config.Bind("Grid", "Columns", 2, new ConfigDescription("Plants per row (to the right).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>()));
			_maxPlants = base.Config.Bind("Grid", "Most plants per click", 10000, new ConfigDescription("A grid never has more plants than this, whatever its size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 40000), Array.Empty<object>()));
			_worldAligned = base.Config.Bind("Grid", "Line up with the world", defaultValue: true, "Rows run north and columns east (turned with the mouse wheel like any piece). Off: rows run away from you.");
			_tighter = base.Config.Bind("Grid", "Tighter spacing", defaultValue: false, "Crops stand closer together: just enough room to grow (1.1 x the room a plant needs, plus its own width) instead of twice the room.