Decompiled source of Lootheim v1.0.2

BepInEx/plugins/Lootheim/Lootheim.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Lootheim;

[BepInPlugin("Lootheim.Valheim", "Lootheim", "1.5.4")]
public sealed class LootheimPlugin : BaseUnityPlugin
{
	internal sealed class CropInfo
	{
		internal string SaplingPrefab;

		internal string ResourcePrefab;

		internal CropInfo(string saplingPrefab, string resourcePrefab)
		{
			SaplingPrefab = saplingPrefab;
			ResourcePrefab = resourcePrefab;
		}
	}

	[HarmonyPatch(typeof(Container), "Awake")]
	private static class ContainerRegistryPatch
	{
		private static void Postfix(Container __instance)
		{
			if ((Object)(object)__instance != (Object)null)
			{
				KnownContainers.Add(__instance);
			}
		}
	}

	[HarmonyPatch]
	private static class GridPlantBlockVanillaPlacementPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			for (int i = 0; i < methods.Length; i++)
			{
				if (methods[i].Name == "TryPlacePiece")
				{
					yield return methods[i];
				}
			}
		}

		private static bool Prefix(Player __instance)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance == (Object)null || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || Enabled == null || !Enabled.Value || FarmAssistEnabled == null || !FarmAssistEnabled.Value || GridPlantHotkey == null)
			{
				return true;
			}
			KeyboardShortcut value = GridPlantHotkey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			if ((int)mainKey == 0 || !Input.GetKey(mainKey))
			{
				return true;
			}
			GameObject placementGhost = GetPlacementGhost(__instance);
			if ((Object)(object)placementGhost == (Object)null)
			{
				return true;
			}
			string b = NormalizePrefabName(((Object)placementGhost).name);
			foreach (KeyValuePair<string, CropInfo> farmCrop in FarmCrops)
			{
				if (string.Equals(NormalizePrefabName(farmCrop.Value.SaplingPrefab), b, StringComparison.OrdinalIgnoreCase))
				{
					return false;
				}
			}
			return true;
		}
	}

	[HarmonyPatch]
	private static class PickableInteractHardGuardPatch
	{
		private static MethodBase TargetMethod()
		{
			return _pickableInteractMethod;
		}

		private static bool Prefix(Pickable __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (!CallOriginatesFromLootheim())
			{
				return true;
			}
			if (Enabled == null || !Enabled.Value)
			{
				return false;
			}
			if (CallOriginatesFromFarmAssist())
			{
				return true;
			}
			if (AutoHarvestEnabled == null || !AutoHarvestEnabled.Value)
			{
				return false;
			}
			string key = NormalizePrefabName(((Object)((Component)__instance).gameObject).name);
			if (!PickableToggles.TryGetValue(key, out var value))
			{
				return false;
			}
			return value?.Value ?? false;
		}
	}

	[HarmonyPatch]
	private static class PickableInteractMultiplierPatch
	{
		private sealed class State
		{
			internal Pickable Pickable;

			internal int Original;

			internal bool Changed;
		}

		private static MethodBase TargetMethod()
		{
			return _pickableInteractMethod;
		}

		private static void Prefix(Pickable __instance, ref State __state)
		{
			__state = null;
			int resourceMultiplier = GetResourceMultiplier();
			if (resourceMultiplier <= 1 || (Object)(object)__instance == (Object)null || _pickableAmountField == null)
			{
				return;
			}
			try
			{
				int num = Convert.ToInt32(_pickableAmountField.GetValue(__instance));
				__state = new State();
				__state.Pickable = __instance;
				__state.Original = num;
				__state.Changed = true;
				_pickableAmountField.SetValue(__instance, Mathf.Max(1, num) * resourceMultiplier);
			}
			catch
			{
				__state = null;
			}
		}

		private static Exception Finalizer(Pickable __instance, State __state, Exception __exception)
		{
			if (__state != null && __state.Changed && (Object)(object)__state.Pickable != (Object)null && _pickableAmountField != null)
			{
				try
				{
					_pickableAmountField.SetValue(__state.Pickable, __state.Original);
				}
				catch
				{
				}
			}
			return __exception;
		}
	}

	[HarmonyPatch]
	private static class DropTableMultiplierPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(DropTable).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo m in methods)
			{
				if ((!(m.Name != "GetDropList") || !(m.Name != "GetDrops") || !(m.Name != "GenerateDropList")) && typeof(IList).IsAssignableFrom(m.ReturnType))
				{
					yield return m;
				}
			}
		}

		private static void Postfix(object __result)
		{
			int resourceMultiplier = GetResourceMultiplier();
			if (resourceMultiplier <= 1 || _multiplierGuard || __result == null || !IsResourceHarvestDropCall() || !(__result is IList { IsFixedSize: false, IsReadOnly: false } list))
			{
				return;
			}
			try
			{
				_multiplierGuard = true;
				int count = list.Count;
				for (int i = 1; i < resourceMultiplier; i++)
				{
					for (int j = 0; j < count; j++)
					{
						list.Add(list[j]);
					}
				}
			}
			catch
			{
			}
			finally
			{
				_multiplierGuard = false;
			}
		}
	}

	[HarmonyPatch]
	private static class CharacterDropMultiplierPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(CharacterDrop).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo m in methods)
			{
				if ((!(m.Name != "GenerateDropList") || !(m.Name != "GetDropList") || !(m.Name != "GetDrops")) && typeof(IList).IsAssignableFrom(m.ReturnType))
				{
					yield return m;
				}
			}
		}

		private static void Postfix(object __result)
		{
			int resourceMultiplier = GetResourceMultiplier();
			if (resourceMultiplier <= 1 || _multiplierGuard || __result == null || !(__result is IList { IsFixedSize: false, IsReadOnly: false } list))
			{
				return;
			}
			try
			{
				_multiplierGuard = true;
				int count = list.Count;
				for (int i = 1; i < resourceMultiplier; i++)
				{
					for (int j = 0; j < count; j++)
					{
						list.Add(list[j]);
					}
				}
			}
			catch
			{
			}
			finally
			{
				_multiplierGuard = false;
			}
		}
	}

	internal static LootheimPlugin Instance;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> AutoHarvestEnabled;

	internal static ConfigEntry<float> AutoHarvestRadius;

	internal static ConfigEntry<float> PickupRadius;

	internal static ConfigEntry<bool> ResourceMultiplierEnabled;

	internal static ConfigEntry<int> ResourceMultiplier;

	internal static ConfigEntry<bool> MiningAuraEnabled;

	internal static ConfigEntry<float> MiningAuraRadius;

	public static ConfigEntry<KeyboardShortcut> MassActionHotkey;

	public static ConfigEntry<KeyboardShortcut> ControllerPickupHotkey;

	public static ConfigEntry<float> MassInteractRange;

	public static ConfigEntry<int> PlantGridWidth;

	public static ConfigEntry<int> PlantGridLength;

	public static ConfigEntry<bool> IgnoreStamina;

	public static ConfigEntry<bool> IgnoreDurability;

	public static ConfigEntry<bool> GridAnchorWidth;

	public static ConfigEntry<bool> GridAnchorLength;

	public static ConfigEntry<float> NonPlantFloraSpacing;

	internal static ConfigEntry<bool> FarmAssistEnabled;

	internal static ConfigEntry<KeyboardShortcut> FarmAssistHotkey;

	internal static ConfigEntry<float> FarmAssistRadius;

	internal static ConfigEntry<bool> AutoReplant;

	internal static ConfigEntry<KeyboardShortcut> GridPlantHotkey;

	internal static ConfigEntry<int> GridPlantLength;

	internal static ConfigEntry<int> GridPlantWidth;

	internal static ConfigEntry<float> GridPlantSpacing;

	internal static ConfigEntry<float> FarmAssistChestRange;

	private static readonly HashSet<Container> KnownContainers = new HashSet<Container>();

	private static readonly List<Container> CachedNearbyContainers = new List<Container>();

	private static float _nextContainerRefresh;

	private static Vector3 _lastContainerRefreshPosition;

	private readonly List<GameObject> _gridPreviewGhosts = new List<GameObject>();

	private readonly List<bool> _gridPreviewValid = new List<bool>();

	private bool _gridPreviewActive;

	private string _gridPreviewSaplingPrefab;

	private string _gridPreviewResourcePrefab;

	internal static readonly Dictionary<string, ConfigEntry<bool>> PickableToggles = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase);

	private Harmony _harmony;

	private float _nextHarvestScan;

	private float _nextMiningAuraScan;

	private float _nextFarmAssistAllowed;

	private Player _trackedPlayer;

	private bool _hasOriginalPickupRange;

	private float _originalPickupRange;

	private static FieldInfo _pickablePickedField;

	private static FieldInfo _pickableAmountField;

	private static FieldInfo _playerAutoPickupRangeField;

	private static MethodInfo _pickableInteractMethod;

	[ThreadStatic]
	private static bool _multiplierGuard;

	private static readonly HashSet<Pickable> SeenPickables = new HashSet<Pickable>();

	private static readonly string[] VanillaPickables = new string[84]
	{
		"BlueberryBush", "CloudberryBush", "goblin_totempole", "hanging_hairstrands", "LingonberryBush", "LuredFaderEmber", "LuredWisp", "Morkhalla_Eye1", "Morkhalla_Eye2", "Morkhalla_Eye3",
		"Morkhalla_Eye4", "Morkhalla_Eye5_gemstone", "Morkhalla_Eye6_gemstone", "Morkhalla_Eye7_gemstone", "Pickable_Ashstone", "Pickable_Barley", "Pickable_Barley_Wild", "Pickable_BlackCoreStand", "Pickable_BogIronOre", "Pickable_Branch",
		"Pickable_Branch_Snow", "Pickable_Carrot", "Pickable_Charredskull", "Pickable_Dandelion", "Pickable_DragonEgg", "Pickable_DvergerThing", "Pickable_DvergrLantern", "Pickable_DvergrMineTreasure", "Pickable_DvergrStein", "Pickable_Fiddlehead",
		"Pickable_Fishingrod", "Pickable_Flax", "Pickable_Flax_Wild", "Pickable_Flint", "Pickable_ForestCryptRemains01", "Pickable_ForestCryptRemains02", "Pickable_ForestCryptRemains03", "Pickable_ForestCryptRemains04", "Pickable_FrostCoreHanger", "Pickable_GlowWorm",
		"Pickable_Hairstrands01", "Pickable_Hairstrands02", "Pickable_HardRockOffspring", "Pickable_Kale", "Pickable_MeatPile", "Pickable_Meteorite", "Pickable_MoltenCoreStand", "Pickable_MountainCaveCrystal", "Pickable_MountainCaveObsidian", "Pickable_MountainRemains01_buried",
		"Pickable_Mushroom", "Pickable_Mushroom_blue", "Pickable_Mushroom_JotunPuffs", "Pickable_Mushroom_Magecap", "Pickable_Mushroom_yellow", "Pickable_Oat", "Pickable_Obsidian", "Pickable_Onion", "Pickable_Pot_Shard", "Pickable_Poteitr",
		"Pickable_RoyalJelly", "Pickable_SeedCarrot", "Pickable_SeedKale", "Pickable_SeedOnion", "Pickable_SeedTurnip", "Pickable_SmokePuff", "Pickable_Snowball", "Pickable_Stone", "Pickable_StoneRock", "Pickable_SulfurRock",
		"Pickable_SurtlingCoreStand", "Pickable_Swordpiece1", "Pickable_Swordpiece2", "Pickable_Swordpiece3", "Pickable_Tar", "Pickable_TarBig", "Pickable_Thistle", "Pickable_Tin", "Pickable_Turnip", "Pickable_VoltureEgg",
		"Placeable_Stone", "RaspberryBush", "VineAsh", "VineGreen"
	};

	internal static readonly Dictionary<string, CropInfo> FarmCrops = new Dictionary<string, CropInfo>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"Pickable_Carrot",
			new CropInfo("sapling_carrot", "CarrotSeeds")
		},
		{
			"Pickable_Turnip",
			new CropInfo("sapling_turnip", "TurnipSeeds")
		},
		{
			"Pickable_Onion",
			new CropInfo("sapling_onion", "OnionSeeds")
		},
		{
			"Pickable_Barley",
			new CropInfo("sapling_barley", "Barley")
		},
		{
			"Pickable_Flax",
			new CropInfo("sapling_flax", "Flax")
		},
		{
			"Pickable_Kale",
			new CropInfo("sapling_Kale", "KaleSeeds")
		},
		{
			"Pickable_Oat",
			new CropInfo("sapling_oat", "OatSeeds")
		}
	};

	private void Awake()
	{
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Expected O, but got Unknown
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Expected O, but got Unknown
		//IL_018e: 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_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_024e: Expected O, but got Unknown
		//IL_0342: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Expected O, but got Unknown
		//IL_0398: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a2: Expected O, but got Unknown
		Instance = this;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for Lootheim.");
		AutoHarvestEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Auto Harvest", "Enabled", true, "Automatically harvest enabled vanilla Pickables inside the configured radius.");
		AutoHarvestRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Auto Harvest", "Harvest Radius (m)", 6f, new ConfigDescription("How far from the player enabled Pickables can be automatically harvested.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 50f), new object[0]));
		PickupRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Pickup Magnet", "Pickup Radius (m)", 10f, new ConfigDescription("How far Valheim's normal auto-pickup magnet can pull dropped items toward you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), new object[0]));
		ResourceMultiplierEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Resource Multiplier", "Enabled", true, "Enable multiplied drops from Pickables, crops, trees/logs, rocks/ore, monsters and animals.");
		ResourceMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("Resource Multiplier", "Multiplier", 1, new ConfigDescription("Resource harvest multiplier. Uses whole-number multipliers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[0]));
		MiningAuraEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Mining Aura", "Enabled", false, "While a pickaxe is equipped, hold Shift to instantly mine nearby resource nodes.");
		MiningAuraRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Mining Aura", "Mining Radius (m)", 8f, new ConfigDescription("Radius around the character affected by Mining Aura.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[0]));
		MassActionHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Farm Assist - Hotkeys", "MassActionHotkey", new KeyboardShortcut((KeyCode)304, (KeyCode[])(object)new KeyCode[0]), "Mass activation hotkey for multi-pickup/multi-plant.");
		ControllerPickupHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Farm Assist - Hotkeys", "ControllerPickupHotkey", new KeyboardShortcut((KeyCode)334, (KeyCode[])(object)new KeyCode[0]), "Mass activation hotkey for multi-pickup/multi-plant for controller.");
		MassInteractRange = ((BaseUnityPlugin)this).Config.Bind<float>("Farm Assist - Pickup", "MassInteractRange", 5f, "Range of mass pickup.");
		AutoReplant = ((BaseUnityPlugin)this).Config.Bind<bool>("Farm Assist - Pickup", "Auto Replant", true, "When using the mass harvest hotkey on farm crops, immediately replant each harvested crop in the same position if the required seed/crop is available in inventory or nearby chests.");
		FarmAssistChestRange = ((BaseUnityPlugin)this).Config.Bind<float>("Farm Assist - Pickup", "Replant Chest Range", 20f, new ConfigDescription("How far Farm Assist can pull seeds/crops from nearby chests for auto replant.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), new object[0]));
		PlantGridWidth = ((BaseUnityPlugin)this).Config.Bind<int>("Farm Assist - PlantGrid", "PlantGridWidth", 5, "Grid width of auto-plant. Recommend odd-number; default is 5.");
		PlantGridLength = ((BaseUnityPlugin)this).Config.Bind<int>("Farm Assist - PlantGrid", "PlantGridLength", 5, "Grid length of auto-plant. Recommend odd-number; default is 5.");
		IgnoreStamina = ((BaseUnityPlugin)this).Config.Bind<bool>("Farm Assist - Plant", "IgnoreStamina", false, "Ignore stamina requirements when planting extra rows.");
		IgnoreDurability = ((BaseUnityPlugin)this).Config.Bind<bool>("Farm Assist - Plant", "IgnoreDurability", false, "Ignore cultivator durability when planting extra rows.");
		GridAnchorWidth = ((BaseUnityPlugin)this).Config.Bind<bool>("Farm Assist - PlantGrid", "GridAnchorWidth", true, "Planting grid anchor point (width). Enabled extends left/right from crosshair; disable to anchor at the side.");
		GridAnchorLength = ((BaseUnityPlugin)this).Config.Bind<bool>("Farm Assist - PlantGrid", "GridAnchorLength", true, "Planting grid anchor point (length). Enabled extends forward/backward from crosshair; disable to anchor at the side.");
		NonPlantFloraSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Farm Assist - PlantGrid", "NonPlantFloraSpacing", 1f, new ConfigDescription("Grid spacing used for Plant Everything flora that do not have Valheim's Plant component.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 4f), new object[0]));
		for (int i = 0; i < VanillaPickables.Length; i++)
		{
			string text = VanillaPickables[i];
			PickableToggles[text] = ((BaseUnityPlugin)this).Config.Bind<bool>("Pickables", text, true, "Allow Lootheim to auto-harvest this vanilla Pickable. OFF is a hard block.");
		}
		CacheMembers();
		_harmony = new Harmony("Lootheim.Valheim");
		_harmony.PatchAll(typeof(LootheimPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Lootheim v1.5.4 loaded. Farm Assist mass harvest auto-replant is enabled.");
	}

	private void OnDestroy()
	{
		ClearGridPreview();
		RestorePickupRadius();
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
		Instance = null;
	}

	private void Update()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			RestorePickupRadius();
			return;
		}
		if (!Enabled.Value)
		{
			RestorePickupRadius();
			return;
		}
		ApplyPickupRadius(localPlayer);
		if (AutoHarvestEnabled.Value && Time.time >= _nextHarvestScan)
		{
			_nextHarvestScan = Time.time + 0.2f;
			RunAutoHarvest(localPlayer, Mathf.Clamp(AutoHarvestRadius.Value, 0.5f, 50f));
		}
		if (MiningAuraEnabled.Value && Time.time >= _nextMiningAuraScan)
		{
			_nextMiningAuraScan = Time.time + 0.15f;
			if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))
			{
				HandleMiningAura(localPlayer, Mathf.Clamp(MiningAuraRadius.Value, 1f, 30f));
			}
		}
	}

	private static void CacheMembers()
	{
		_pickablePickedField = AccessTools.Field(typeof(Pickable), "m_picked");
		_pickableAmountField = AccessTools.Field(typeof(Pickable), "m_amount");
		_playerAutoPickupRangeField = AccessTools.Field(typeof(Player), "m_autoPickupRange");
		MethodInfo[] methods = typeof(Pickable).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		for (int i = 0; i < methods.Length; i++)
		{
			if (!(methods[i].Name != "Interact"))
			{
				ParameterInfo[] parameters = methods[i].GetParameters();
				if (parameters.Length > 0 && typeof(Humanoid).IsAssignableFrom(parameters[0].ParameterType))
				{
					_pickableInteractMethod = methods[i];
					break;
				}
			}
		}
	}

	private static bool IsPickableEnabled(string prefab)
	{
		if (string.IsNullOrEmpty(prefab))
		{
			return false;
		}
		if (!PickableToggles.TryGetValue(prefab, out var value))
		{
			return false;
		}
		return value?.Value ?? false;
	}

	private static void RunAutoHarvest(Player player, float radius)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		Collider[] array;
		try
		{
			array = Physics.OverlapSphere(((Component)player).transform.position, radius, -1, (QueryTriggerInteraction)2);
		}
		catch
		{
			return;
		}
		SeenPickables.Clear();
		foreach (Collider val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Pickable val2 = null;
			try
			{
				val2 = ((Component)val).GetComponentInParent<Pickable>();
			}
			catch
			{
			}
			if (!((Object)(object)val2 == (Object)null) && !SeenPickables.Contains(val2))
			{
				SeenPickables.Add(val2);
				string prefab = NormalizePrefabName(((Object)((Component)val2).gameObject).name);
				if (IsPickableEnabled(prefab) && !IsAlreadyPicked(val2))
				{
					TryInteractWithPickable(val2, player);
				}
			}
		}
	}

	internal static bool IsAlreadyPicked(Pickable pickable)
	{
		if ((Object)(object)pickable == (Object)null || _pickablePickedField == null)
		{
			return false;
		}
		try
		{
			return Convert.ToBoolean(_pickablePickedField.GetValue(pickable));
		}
		catch
		{
			return false;
		}
	}

	private static bool TryInteractWithPickable(Pickable pickable, Player player)
	{
		if ((Object)(object)pickable == (Object)null || (Object)(object)player == (Object)null || _pickableInteractMethod == null)
		{
			return false;
		}
		try
		{
			ParameterInfo[] parameters = _pickableInteractMethod.GetParameters();
			object[] array = new object[parameters.Length];
			for (int i = 0; i < parameters.Length; i++)
			{
				Type parameterType = parameters[i].ParameterType;
				if (typeof(Humanoid).IsAssignableFrom(parameterType))
				{
					array[i] = player;
				}
				else if (parameterType == typeof(bool))
				{
					array[i] = false;
				}
				else if (parameterType == typeof(int))
				{
					array[i] = 0;
				}
				else if (parameterType == typeof(float))
				{
					array[i] = 0f;
				}
				else
				{
					array[i] = null;
				}
			}
			if (!(_pickableInteractMethod.Invoke(pickable, array) is bool result))
			{
				return true;
			}
			return result;
		}
		catch
		{
			return false;
		}
	}

	private static void ApplyPickupRadius(Player player)
	{
		if ((Object)(object)player == (Object)null || _playerAutoPickupRangeField == null)
		{
			return;
		}
		try
		{
			if ((Object)(object)Instance._trackedPlayer != (Object)(object)player)
			{
				Instance.RestorePickupRadius();
				Instance._trackedPlayer = player;
			}
			if (!Instance._hasOriginalPickupRange)
			{
				Instance._originalPickupRange = Convert.ToSingle(_playerAutoPickupRangeField.GetValue(player));
				Instance._hasOriginalPickupRange = true;
			}
			_playerAutoPickupRangeField.SetValue(player, Mathf.Clamp(PickupRadius.Value, 2f, 50f));
		}
		catch
		{
		}
	}

	private void RestorePickupRadius()
	{
		if (!_hasOriginalPickupRange || (Object)(object)_trackedPlayer == (Object)null || _playerAutoPickupRangeField == null)
		{
			_trackedPlayer = null;
			_hasOriginalPickupRange = false;
			return;
		}
		try
		{
			_playerAutoPickupRangeField.SetValue(_trackedPlayer, _originalPickupRange);
		}
		catch
		{
		}
		_trackedPlayer = null;
		_hasOriginalPickupRange = false;
	}

	private static int GetResourceMultiplier()
	{
		if (Enabled == null || ResourceMultiplierEnabled == null || ResourceMultiplier == null || !Enabled.Value || !ResourceMultiplierEnabled.Value)
		{
			return 1;
		}
		return Mathf.Clamp(ResourceMultiplier.Value, 1, 20);
	}

	private static bool CallOriginatesFromLootheim()
	{
		try
		{
			StackTrace stackTrace = new StackTrace();
			StackFrame[] frames = stackTrace.GetFrames();
			if (frames == null)
			{
				return false;
			}
			for (int i = 0; i < frames.Length; i++)
			{
				MethodBase method = frames[i].GetMethod();
				if (!(method == null))
				{
					string name = method.Name;
					Type declaringType = method.DeclaringType;
					string text = ((declaringType == null) ? "" : declaringType.FullName);
					if (string.Equals(name, "RunAutoHarvest", StringComparison.Ordinal) || string.Equals(name, "RunFarmAssist", StringComparison.Ordinal))
					{
						return true;
					}
					if (!string.IsNullOrEmpty(text) && (text.StartsWith("LootheimStaticHarvest.", StringComparison.OrdinalIgnoreCase) || text.IndexOf("Lootheim.StaticHarvest", StringComparison.OrdinalIgnoreCase) >= 0))
					{
						return true;
					}
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static bool CallOriginatesFromFarmAssist()
	{
		try
		{
			StackTrace stackTrace = new StackTrace();
			StackFrame[] frames = stackTrace.GetFrames();
			if (frames == null)
			{
				return false;
			}
			for (int i = 0; i < frames.Length; i++)
			{
				MethodBase method = frames[i].GetMethod();
				if (!(method == null) && (string.Equals(method.Name, "RunFarmAssist", StringComparison.Ordinal) || string.Equals(method.Name, "RunGridPlant", StringComparison.Ordinal)))
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static bool IsResourceHarvestDropCall()
	{
		try
		{
			StackTrace stackTrace = new StackTrace();
			StackFrame[] frames = stackTrace.GetFrames();
			if (frames == null)
			{
				return false;
			}
			for (int i = 0; i < frames.Length; i++)
			{
				MethodBase method = frames[i].GetMethod();
				if (!(method == null) && !(method.DeclaringType == null))
				{
					string fullName = method.DeclaringType.FullName;
					if (!string.IsNullOrEmpty(fullName) && (fullName.IndexOf("TreeBase", StringComparison.OrdinalIgnoreCase) >= 0 || fullName.IndexOf("TreeLog", StringComparison.OrdinalIgnoreCase) >= 0 || fullName.IndexOf("MineRock", StringComparison.OrdinalIgnoreCase) >= 0 || fullName.IndexOf("Destructible", StringComparison.OrdinalIgnoreCase) >= 0 || fullName.IndexOf("Beehive", StringComparison.OrdinalIgnoreCase) >= 0 || fullName.IndexOf("SapCollector", StringComparison.OrdinalIgnoreCase) >= 0))
					{
						return true;
					}
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static void HandleMiningAura(Player player, float radius)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null || !IsPickaxeEquipped(player))
		{
			return;
		}
		Collider[] array;
		try
		{
			array = Physics.OverlapSphere(((Component)player).transform.position, radius, -1, (QueryTriggerInteraction)2);
		}
		catch
		{
			return;
		}
		HashSet<Component> hashSet = new HashSet<Component>();
		foreach (Collider val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Component val2 = null;
			try
			{
				val2 = (Component)(object)((Component)val).GetComponentInParent<MineRock5>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = (Component)(object)((Component)val).GetComponentInParent<MineRock>();
				}
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = (Component)(object)((Component)val).GetComponentInParent<Destructible>();
				}
			}
			catch
			{
			}
			if (!((Object)(object)val2 == (Object)null) && !hashSet.Contains(val2))
			{
				hashSet.Add(val2);
				if (!(val2 is Destructible) || IsResourceDestructible((Destructible)(object)((val2 is Destructible) ? val2 : null)))
				{
					TryOneShotMine(player, val2, val);
				}
			}
		}
	}

	private static bool IsPickaxeEquipped(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		try
		{
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			if (currentWeapon == null || currentWeapon.m_shared == null)
			{
				return false;
			}
			if (currentWeapon.m_shared.m_damages.m_pickaxe > 0f)
			{
				return true;
			}
			string name = currentWeapon.m_shared.m_name;
			return !string.IsNullOrEmpty(name) && name.IndexOf("pickaxe", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		catch
		{
			return false;
		}
	}

	private static bool IsResourceDestructible(Destructible destructible)
	{
		if ((Object)(object)destructible == (Object)null)
		{
			return false;
		}
		string text = NormalizePrefabName(((Object)((Component)destructible).gameObject).name);
		string text2 = text.ToLowerInvariant();
		if (!text2.Contains("rock") && !text2.Contains("stone") && !text2.Contains("copper") && !text2.Contains("silver") && !text2.Contains("obsidian") && !text2.Contains("iron") && !text2.Contains("flametal") && !text2.Contains("marble") && !text2.Contains("meteor") && !text2.Contains("deposit"))
		{
			return text2.Contains("mine");
		}
		return true;
	}

	private static void TryOneShotMine(Player player, Component target, Collider collider)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Expected O, but got Unknown
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: 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_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)
		if ((Object)(object)player == (Object)null || (Object)(object)target == (Object)null)
		{
			return;
		}
		try
		{
			HitData val = new HitData();
			val.m_damage.m_pickaxe = 1000000f;
			val.m_toolTier = 99;
			Vector3 point;
			if (!((Object)(object)collider != (Object)null))
			{
				point = target.transform.position;
			}
			else
			{
				Bounds bounds = collider.bounds;
				point = ((Bounds)(ref bounds)).center;
			}
			val.m_point = point;
			val.m_hitCollider = collider;
			Vector3 dir = target.transform.position - ((Component)player).transform.position;
			if (((Vector3)(ref dir)).sqrMagnitude > 0.001f)
			{
				((Vector3)(ref dir)).Normalize();
			}
			val.m_dir = dir;
			val.SetAttacker((Character)(object)player);
			MethodInfo[] methods = ((object)target).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo.Name != "Damage"))
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 1 && parameters[0].ParameterType == typeof(HitData))
					{
						methodInfo.Invoke(target, new object[1] { val });
						break;
					}
				}
			}
		}
		catch
		{
		}
	}

	private static void RunFarmAssist(Player player, float radius)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: 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_0134: Unknown result type (might be due to invalid IL or missing references)
		Collider[] array;
		try
		{
			array = Physics.OverlapSphere(((Component)player).transform.position, radius, -1, (QueryTriggerInteraction)2);
		}
		catch
		{
			return;
		}
		HashSet<Pickable> hashSet = new HashSet<Pickable>();
		foreach (Collider val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Pickable val2 = null;
			try
			{
				val2 = ((Component)val).GetComponentInParent<Pickable>();
			}
			catch
			{
			}
			if (!((Object)(object)val2 == (Object)null) && !hashSet.Contains(val2))
			{
				string key = NormalizePrefabName(((Object)((Component)val2).gameObject).name);
				if (FarmCrops.ContainsKey(key) && !IsAlreadyPicked(val2))
				{
					hashSet.Add(val2);
				}
			}
		}
		int num = 0;
		int num2 = 0;
		foreach (Pickable item in hashSet)
		{
			if ((Object)(object)item == (Object)null)
			{
				continue;
			}
			string key2 = NormalizePrefabName(((Object)((Component)item).gameObject).name);
			if (!FarmCrops.TryGetValue(key2, out var value))
			{
				continue;
			}
			Vector3 position = ((Component)item).transform.position;
			Quaternion rotation = ((Component)item).transform.rotation;
			if (!TryInteractWithPickable(item, player))
			{
				continue;
			}
			num++;
			if (AutoReplant.Value && ConsumeOneResource(player, value.ResourcePrefab))
			{
				if (SpawnSapling(value.SaplingPrefab, position, rotation))
				{
					num2++;
				}
				else
				{
					RefundOneResource(player, value.ResourcePrefab);
				}
			}
		}
		if (num > 0)
		{
			ShowCenterMessage("Farm Assist: harvested " + num + (AutoReplant.Value ? (", replanted " + num2) : ""));
		}
	}

	private static bool IsFarmAssistPressedThisFrame()
	{
		//IL_000e: 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_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		if (FarmAssistHotkey == null)
		{
			return false;
		}
		KeyboardShortcut value = FarmAssistHotkey.Value;
		KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
		if ((int)mainKey == 0)
		{
			return false;
		}
		if (!Input.GetKeyDown(mainKey))
		{
			return false;
		}
		IEnumerable<KeyCode> modifiers = ((KeyboardShortcut)(ref value)).Modifiers;
		if (modifiers != null)
		{
			foreach (KeyCode item in modifiers)
			{
				if (!Input.GetKey(item))
				{
					return false;
				}
			}
		}
		return true;
	}

	private void HandleGridPreviewAndPlacement(Player player)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: 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)
		if ((Object)(object)player == (Object)null || !FarmAssistEnabled.Value)
		{
			ClearGridPreview();
			return;
		}
		KeyboardShortcut value = GridPlantHotkey.Value;
		KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
		if ((int)mainKey == 0 || !Input.GetKey(mainKey))
		{
			ClearGridPreview();
			return;
		}
		GameObject placementGhost = GetPlacementGhost(player);
		if ((Object)(object)placementGhost == (Object)null)
		{
			ClearGridPreview();
			return;
		}
		string b = NormalizePrefabName(((Object)placementGhost).name);
		CropInfo cropInfo = null;
		foreach (KeyValuePair<string, CropInfo> farmCrop in FarmCrops)
		{
			if (string.Equals(NormalizePrefabName(farmCrop.Value.SaplingPrefab), b, StringComparison.OrdinalIgnoreCase))
			{
				cropInfo = farmCrop.Value;
				break;
			}
		}
		if (cropInfo == null)
		{
			ClearGridPreview();
			return;
		}
		_gridPreviewActive = true;
		_gridPreviewSaplingPrefab = cropInfo.SaplingPrefab;
		_gridPreviewResourcePrefab = cropInfo.ResourcePrefab;
		UpdateGridPreview(player, placementGhost, Mathf.Clamp(GridPlantLength.Value, 1, 30), Mathf.Clamp(GridPlantWidth.Value, 1, 30), Mathf.Clamp(GridPlantSpacing.Value, 1.1f, 4f));
		if (Input.GetMouseButtonDown(0))
		{
			PlaceCurrentGrid(player, placementGhost, cropInfo, Mathf.Clamp(GridPlantLength.Value, 1, 30), Mathf.Clamp(GridPlantWidth.Value, 1, 30), Mathf.Clamp(GridPlantSpacing.Value, 1.1f, 4f));
		}
	}

	private void UpdateGridPreview(Player player, GameObject placementGhost, int length, int width, float spacing)
	{
		//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_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: 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_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: 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_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: 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_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: 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_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_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: 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_01e9: 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)
		if ((Object)(object)player == (Object)null || (Object)(object)placementGhost == (Object)null)
		{
			return;
		}
		int num = length * width;
		while (_gridPreviewGhosts.Count < num)
		{
			GameObject val = null;
			try
			{
				val = Object.Instantiate<GameObject>(placementGhost);
				((Object)val).name = "LootheimGridPreview";
				DisablePreviewBehaviours(val);
			}
			catch
			{
			}
			_gridPreviewGhosts.Add(val);
			_gridPreviewValid.Add(item: false);
		}
		while (_gridPreviewGhosts.Count > num)
		{
			int num2 = _gridPreviewGhosts.Count - 1;
			GameObject val2 = _gridPreviewGhosts[num2];
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)val2);
			}
			_gridPreviewGhosts.RemoveAt(num2);
			if (_gridPreviewValid.Count > num2)
			{
				_gridPreviewValid.RemoveAt(num2);
			}
		}
		while (_gridPreviewValid.Count < num)
		{
			_gridPreviewValid.Add(item: false);
		}
		Vector3 position = placementGhost.transform.position;
		Quaternion rotation = placementGhost.transform.rotation;
		Vector3 val3 = Vector3.ProjectOnPlane(placementGhost.transform.forward, Vector3.up);
		Vector3 normalized = ((Vector3)(ref val3)).normalized;
		if (((Vector3)(ref normalized)).sqrMagnitude < 0.01f)
		{
			Vector3 val4 = Vector3.ProjectOnPlane(((Component)player).transform.forward, Vector3.up);
			normalized = ((Vector3)(ref val4)).normalized;
		}
		Vector3 val5 = Vector3.Cross(Vector3.up, normalized);
		Vector3 normalized2 = ((Vector3)(ref val5)).normalized;
		int num3 = 0;
		for (int i = 0; i < length; i++)
		{
			for (int j = 0; j < width; j++)
			{
				GameObject val6 = _gridPreviewGhosts[num3];
				Vector3 position2 = position + normalized * ((float)i * spacing) + normalized2 * ((float)j * spacing);
				position2 = SnapPlantToGround(position2);
				bool flag = IsPlantPositionClear(player, position2, Mathf.Min(0.55f, spacing * 0.35f));
				_gridPreviewValid[num3] = flag;
				if ((Object)(object)val6 != (Object)null)
				{
					val6.transform.position = position2;
					val6.transform.rotation = rotation;
					SetPreviewValidityVisual(val6, flag);
					if (!val6.activeSelf)
					{
						val6.SetActive(true);
					}
				}
				num3++;
			}
		}
	}

	private static void DisablePreviewBehaviours(GameObject preview)
	{
		if ((Object)(object)preview == (Object)null)
		{
			return;
		}
		try
		{
			Collider[] componentsInChildren = preview.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
		}
		catch
		{
		}
		try
		{
			MonoBehaviour[] componentsInChildren2 = preview.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren2)
			{
				if ((Object)(object)val != (Object)null)
				{
					((Behaviour)val).enabled = false;
				}
			}
		}
		catch
		{
		}
	}

	private static bool IsPlantPositionClear(Player player, Vector3 position, float radius)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: 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_0010: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Collider[] array = Physics.OverlapSphere(position + Vector3.up * 0.35f, Mathf.Max(0.25f, radius), -1, (QueryTriggerInteraction)1);
			foreach (Collider val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Heightmap componentInParent = ((Component)val).GetComponentInParent<Heightmap>();
				if ((Object)(object)componentInParent != (Object)null || ((Object)(object)player != (Object)null && ((Component)val).transform.IsChildOf(((Component)player).transform)))
				{
					continue;
				}
				Transform val2 = ((Component)val).transform;
				bool flag = false;
				while ((Object)(object)val2 != (Object)null)
				{
					if ((Object)(object)((Component)val2).gameObject != (Object)null && ((Object)((Component)val2).gameObject).name == "LootheimGridPreview")
					{
						flag = true;
						break;
					}
					val2 = val2.parent;
				}
				if (!flag)
				{
					return false;
				}
			}
		}
		catch
		{
			return false;
		}
		return true;
	}

	private static void SetPreviewValidityVisual(GameObject preview, bool valid)
	{
		//IL_006c: 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)
		if ((Object)(object)preview == (Object)null)
		{
			return;
		}
		try
		{
			Renderer[] componentsInChildren = preview.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Material material = val.material;
				if (!((Object)(object)material == (Object)null))
				{
					if (valid)
					{
						material.color = new Color(0.35f, 1f, 0.35f, 0.55f);
					}
					else
					{
						material.color = new Color(1f, 0.15f, 0.15f, 0.65f);
					}
				}
			}
		}
		catch
		{
		}
	}

	private void ClearGridPreview()
	{
		for (int i = 0; i < _gridPreviewGhosts.Count; i++)
		{
			GameObject val = _gridPreviewGhosts[i];
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
		_gridPreviewGhosts.Clear();
		_gridPreviewValid.Clear();
		_gridPreviewActive = false;
		_gridPreviewSaplingPrefab = null;
		_gridPreviewResourcePrefab = null;
	}

	private static void PlaceCurrentGrid(Player player, GameObject placementGhost, CropInfo selectedCrop, int length, int width, float spacing)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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_002d: 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_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_0047: 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_007a: 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)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: 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_0066: 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_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: 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_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: 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_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: 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_0123: 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_012b: 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)
		if ((Object)(object)player == (Object)null || (Object)(object)placementGhost == (Object)null || selectedCrop == null)
		{
			return;
		}
		Vector3 position = placementGhost.transform.position;
		Quaternion rotation = placementGhost.transform.rotation;
		Vector3 val = Vector3.ProjectOnPlane(placementGhost.transform.forward, Vector3.up);
		Vector3 normalized = ((Vector3)(ref val)).normalized;
		if (((Vector3)(ref normalized)).sqrMagnitude < 0.01f)
		{
			Vector3 val2 = Vector3.ProjectOnPlane(((Component)player).transform.forward, Vector3.up);
			normalized = ((Vector3)(ref val2)).normalized;
		}
		Vector3 val3 = Vector3.Cross(Vector3.up, normalized);
		Vector3 normalized2 = ((Vector3)(ref val3)).normalized;
		int num = 0;
		int num2 = length * width;
		for (int i = 0; i < length; i++)
		{
			for (int j = 0; j < width; j++)
			{
				if (!ConsumeOneResource(player, selectedCrop.ResourcePrefab))
				{
					ShowCenterMessage("Grid Plant: planted " + num + "/" + num2 + " (out of resources in inventory/chests)");
					return;
				}
				Vector3 position2 = position + normalized * ((float)i * spacing) + normalized2 * ((float)j * spacing);
				position2 = SnapPlantToGround(position2);
				if (!IsPlantPositionClear(player, position2, Mathf.Min(0.55f, spacing * 0.35f)))
				{
					RefundOneResource(player, selectedCrop.ResourcePrefab);
				}
				else if (SpawnSapling(selectedCrop.SaplingPrefab, position2, rotation))
				{
					num++;
				}
				else
				{
					RefundOneResource(player, selectedCrop.ResourcePrefab);
				}
			}
		}
		ShowCenterMessage("Grid Plant: planted " + num + "/" + num2);
	}

	private static GameObject GetPlacementGhost(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		try
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(Player), "m_placementGhost");
			if (fieldInfo != null)
			{
				object? value = fieldInfo.GetValue(player);
				return (GameObject)((value is GameObject) ? value : null);
			}
		}
		catch
		{
		}
		return null;
	}

	private static Vector3 SnapPlantToGround(Vector3 position)
	{
		//IL_0000: 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_0133: 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_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: 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_006e: 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_0125: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: 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_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Heightmap val = Heightmap.FindHeightmap(position);
			if ((Object)(object)val != (Object)null)
			{
				float num = 0f;
				MethodInfo methodInfo = AccessTools.Method(typeof(Heightmap), "GetHeight", new Type[2]
				{
					typeof(Vector3),
					typeof(float).MakeByRefType()
				}, (Type[])null);
				if (methodInfo != null)
				{
					object[] array = new object[2] { position, num };
					if (!(methodInfo.Invoke(val, array) is int num2) || num2 != 0)
					{
						position.y = Convert.ToSingle(array[1]);
						return position;
					}
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Heightmap), "GetWorldHeight", new Type[1] { typeof(Vector3) }, (Type[])null);
				if (methodInfo2 != null)
				{
					object obj = methodInfo2.Invoke(val, new object[1] { position });
					if (obj != null)
					{
						position.y = Convert.ToSingle(obj);
						return position;
					}
				}
			}
		}
		catch
		{
		}
		try
		{
			RaycastHit[] array2 = Physics.RaycastAll(position + Vector3.up * 20f, Vector3.down, 50f, -1, (QueryTriggerInteraction)1);
			float num3 = float.NegativeInfinity;
			bool flag = false;
			for (int i = 0; i < array2.Length; i++)
			{
				Collider collider = ((RaycastHit)(ref array2[i])).collider;
				if (!((Object)(object)collider == (Object)null))
				{
					Heightmap componentInParent = ((Component)collider).GetComponentInParent<Heightmap>();
					if (!((Object)(object)componentInParent == (Object)null) && (!flag || ((RaycastHit)(ref array2[i])).point.y > num3))
					{
						flag = true;
						num3 = ((RaycastHit)(ref array2[i])).point.y;
					}
				}
			}
			if (flag)
			{
				position.y = num3;
			}
		}
		catch
		{
		}
		return position;
	}

	internal static bool ConsumeOneResource(Player player, string resourcePrefab)
	{
		if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(resourcePrefab))
		{
			return false;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (TryConsumeFromInventory(inventory, resourcePrefab))
		{
			return true;
		}
		RefreshNearbyContainers(player);
		for (int i = 0; i < CachedNearbyContainers.Count; i++)
		{
			Container val = CachedNearbyContainers[i];
			if (!((Object)(object)val == (Object)null))
			{
				Inventory val2 = null;
				try
				{
					val2 = val.GetInventory();
				}
				catch
				{
				}
				if (val2 != null && TryConsumeFromInventory(val2, resourcePrefab))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static bool TryConsumeFromInventory(Inventory inventory, string resourcePrefab)
	{
		if (inventory == null)
		{
			return false;
		}
		try
		{
			List<ItemData> allItems = inventory.GetAllItems();
			for (int i = 0; i < allItems.Count; i++)
			{
				ItemData val = allItems[i];
				if (val == null || (Object)(object)val.m_dropPrefab == (Object)null)
				{
					continue;
				}
				string a = NormalizePrefabName(((Object)val.m_dropPrefab).name);
				if (string.Equals(a, resourcePrefab, StringComparison.OrdinalIgnoreCase) && val.m_stack > 0)
				{
					val.m_stack--;
					if (val.m_stack <= 0)
					{
						RemoveInventoryItemReflective(inventory, val);
					}
					else
					{
						NotifyInventoryChanged(inventory);
					}
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static void RefreshNearbyContainers(Player player)
	{
		//IL_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_0050: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		float time = Time.time;
		Vector3 position = ((Component)player).transform.position;
		Vector3 val = position - _lastContainerRefreshPosition;
		bool flag = ((Vector3)(ref val)).sqrMagnitude > 4f;
		if (time < _nextContainerRefresh && !flag)
		{
			return;
		}
		_nextContainerRefresh = time + 0.5f;
		_lastContainerRefreshPosition = position;
		CachedNearbyContainers.Clear();
		float num = ((FarmAssistChestRange == null) ? 20f : Mathf.Clamp(FarmAssistChestRange.Value, 1f, 50f));
		float num2 = num * num;
		List<Container> list = new List<Container>();
		foreach (Container knownContainer in KnownContainers)
		{
			if ((Object)(object)knownContainer == (Object)null)
			{
				list.Add(knownContainer);
				continue;
			}
			try
			{
				Vector3 val2 = ((Component)knownContainer).transform.position - position;
				if (((Vector3)(ref val2)).sqrMagnitude <= num2)
				{
					CachedNearbyContainers.Add(knownContainer);
				}
			}
			catch
			{
			}
		}
		for (int i = 0; i < list.Count; i++)
		{
			KnownContainers.Remove(list[i]);
		}
	}

	internal static void RefundOneResource(Player player, string resourcePrefab)
	{
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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)
		if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(resourcePrefab))
		{
			return;
		}
		GameObject networkPrefab = GetNetworkPrefab(resourcePrefab);
		if ((Object)(object)networkPrefab == (Object)null)
		{
			return;
		}
		ItemDrop component = networkPrefab.GetComponent<ItemDrop>();
		if ((Object)(object)component == (Object)null || component.m_itemData == null)
		{
			return;
		}
		try
		{
			ItemData val = component.m_itemData.Clone();
			val.m_stack = 1;
			if (((Humanoid)player).GetInventory().AddItem(val))
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(networkPrefab, ((Component)player).transform.position + Vector3.up, Quaternion.identity);
			if ((Object)(object)val2 != (Object)null)
			{
				ItemDrop component2 = val2.GetComponent<ItemDrop>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.m_itemData.m_stack = 1;
				}
			}
		}
		catch
		{
		}
	}

	internal static bool SpawnSapling(string prefabName, Vector3 position, Quaternion rotation)
	{
		//IL_01cd: 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_00ba: 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_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(prefabName))
		{
			return false;
		}
		try
		{
			object zNetSceneInstance = GetZNetSceneInstance();
			if (zNetSceneInstance != null)
			{
				MethodInfo[] methods = typeof(ZNetScene).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != "Instantiate")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 3 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(Quaternion))
					{
						object obj = methodInfo.Invoke(zNetSceneInstance, new object[3] { prefabName, position, rotation });
						if (obj is GameObject)
						{
							FinalizeSpawnedPlant((GameObject)((obj is GameObject) ? obj : null));
							return true;
						}
					}
					if (parameters.Length != 3 || !(parameters[0].ParameterType == typeof(GameObject)) || !(parameters[1].ParameterType == typeof(Vector3)) || !(parameters[2].ParameterType == typeof(Quaternion)))
					{
						continue;
					}
					GameObject networkPrefab = GetNetworkPrefab(prefabName);
					if (!((Object)(object)networkPrefab == (Object)null))
					{
						object obj2 = methodInfo.Invoke(zNetSceneInstance, new object[3] { networkPrefab, position, rotation });
						if (obj2 is GameObject)
						{
							FinalizeSpawnedPlant((GameObject)((obj2 is GameObject) ? obj2 : null));
							return true;
						}
					}
				}
			}
		}
		catch
		{
		}
		GameObject networkPrefab2 = GetNetworkPrefab(prefabName);
		if ((Object)(object)networkPrefab2 == (Object)null)
		{
			return false;
		}
		try
		{
			GameObject val = Object.Instantiate<GameObject>(networkPrefab2, position, rotation);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			FinalizeSpawnedPlant(val);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static object GetZNetSceneInstance()
	{
		try
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "instance");
			if (fieldInfo != null)
			{
				object value = fieldInfo.GetValue(null);
				if (value != null)
				{
					return value;
				}
			}
		}
		catch
		{
		}
		try
		{
			PropertyInfo property = typeof(ZNetScene).GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetValue(null, null);
			}
		}
		catch
		{
		}
		return null;
	}

	private static void FinalizeSpawnedPlant(GameObject planted)
	{
		if ((Object)(object)planted == (Object)null)
		{
			return;
		}
		try
		{
			ZNetView component = planted.GetComponent<ZNetView>();
			if (!((Object)(object)component != (Object)null))
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(ZNetView), "IsOwner", (Type[])null, (Type[])null);
			bool flag = false;
			if (methodInfo != null)
			{
				object obj = methodInfo.Invoke(component, null);
				if (obj is bool)
				{
					flag = (bool)obj;
				}
			}
			if (!flag)
			{
				MethodInfo methodInfo2 = AccessTools.Method(typeof(ZNetView), "ClaimOwnership", (Type[])null, (Type[])null);
				if (methodInfo2 != null)
				{
					methodInfo2.Invoke(component, null);
				}
			}
		}
		catch
		{
		}
	}

	private static GameObject GetNetworkPrefab(string prefabName)
	{
		if (string.IsNullOrEmpty(prefabName))
		{
			return null;
		}
		try
		{
			Type typeFromHandle = typeof(ZNetScene);
			FieldInfo fieldInfo = AccessTools.Field(typeFromHandle, "instance");
			object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
			if (obj == null)
			{
				PropertyInfo property = typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					obj = property.GetValue(null, null);
				}
			}
			if (obj == null)
			{
				return null;
			}
			MethodInfo methodInfo = AccessTools.Method(typeFromHandle, "GetPrefab", new Type[1] { typeof(string) }, (Type[])null);
			if (methodInfo == null)
			{
				return null;
			}
			object? obj2 = methodInfo.Invoke(obj, new object[1] { prefabName });
			return (GameObject)((obj2 is GameObject) ? obj2 : null);
		}
		catch
		{
			return null;
		}
	}

	private static void RemoveInventoryItemReflective(Inventory inventory, ItemData item)
	{
		if (inventory == null || item == null)
		{
			return;
		}
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[1] { typeof(ItemData) }, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(inventory, new object[1] { item });
			}
		}
		catch
		{
		}
		NotifyInventoryChanged(inventory);
	}

	private static void NotifyInventoryChanged(Inventory inventory)
	{
		if (inventory == null)
		{
			return;
		}
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(inventory, null);
			}
		}
		catch
		{
		}
	}

	private static void ShowCenterMessage(string text)
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		try
		{
			MethodInfo[] methods = typeof(Character).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "Message")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length < 2 || parameters[0].ParameterType != typeof(MessageType) || parameters[1].ParameterType != typeof(string))
				{
					continue;
				}
				object[] array = new object[parameters.Length];
				array[0] = (object)(MessageType)2;
				array[1] = text;
				for (int j = 2; j < array.Length; j++)
				{
					Type parameterType = parameters[j].ParameterType;
					if (parameterType == typeof(int))
					{
						array[j] = 0;
					}
					else if (parameterType == typeof(float))
					{
						array[j] = 0f;
					}
					else if (parameterType == typeof(bool))
					{
						array[j] = false;
					}
					else
					{
						array[j] = null;
					}
				}
				methodInfo.Invoke(localPlayer, array);
				break;
			}
		}
		catch
		{
		}
	}

	internal static string NormalizePrefabName(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return "";
		}
		string text = value.Trim();
		if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase))
		{
			text = text.Substring(0, text.Length - "(Clone)".Length).Trim();
		}
		return text;
	}
}
[HarmonyPatch]
internal static class FarmAssistPickup
{
	internal static int MassHarvestFrame = -1;

	private static readonly FieldInfo InteractMaskField = AccessTools.Field(typeof(Player), "m_interactMask");

	private static readonly MethodInfo ExtractMethod = AccessTools.Method(typeof(Beehive), "Extract", (Type[])null, (Type[])null);

	private static bool FarmAssistHotkeyPressed
	{
		get
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			if (LootheimPlugin.MassActionHotkey == null || LootheimPlugin.ControllerPickupHotkey == null)
			{
				return false;
			}
			KeyboardShortcut value = LootheimPlugin.MassActionHotkey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			KeyboardShortcut value2 = LootheimPlugin.ControllerPickupHotkey.Value;
			KeyCode mainKey2 = ((KeyboardShortcut)(ref value2)).MainKey;
			if ((int)mainKey == 0 || !Input.GetKey(mainKey))
			{
				if ((int)mainKey2 != 0)
				{
					return Input.GetKey(mainKey2);
				}
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Player), "Interact")]
	[HarmonyPrefix]
	private static void Prefix(Player __instance, GameObject go, bool hold, bool alt)
	{
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: 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)
		if (LootheimPlugin.Enabled == null || !LootheimPlugin.Enabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)go == (Object)null || ((Character)__instance).InAttack() || ((Character)__instance).InDodge() || hold || !FarmAssistHotkeyPressed)
		{
			return;
		}
		Interactable componentInParent = go.GetComponentInParent<Interactable>();
		Pickable val = (Pickable)(object)((componentInParent is Pickable) ? componentInParent : null);
		if ((Object)(object)val != (Object)null)
		{
			MassHarvestFrame = Time.frameCount;
			int num = -1;
			try
			{
				if (InteractMaskField != null)
				{
					num = (int)InteractMaskField.GetValue(__instance);
				}
			}
			catch
			{
			}
			Collider[] array = Physics.OverlapSphere(go.transform.position, LootheimPlugin.MassInteractRange.Value, num);
			foreach (Collider val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null))
				{
					Pickable componentInParent2 = ((Component)val2).gameObject.GetComponentInParent<Pickable>();
					if (!((Object)(object)componentInParent2 == (Object)null) && !((Object)(object)componentInParent2 == (Object)(object)val) && (Object)(object)componentInParent2.m_itemPrefab != (Object)null && (Object)(object)val.m_itemPrefab != (Object)null && ((Object)componentInParent2.m_itemPrefab).name == ((Object)val.m_itemPrefab).name)
					{
						componentInParent2.Interact((Humanoid)(object)__instance, false, alt);
					}
				}
			}
			return;
		}
		Beehive val3 = (Beehive)(object)((componentInParent is Beehive) ? componentInParent : null);
		if (!((Object)(object)val3 != (Object)null))
		{
			return;
		}
		int num2 = -1;
		try
		{
			if (InteractMaskField != null)
			{
				num2 = (int)InteractMaskField.GetValue(__instance);
			}
		}
		catch
		{
		}
		Collider[] array2 = Physics.OverlapSphere(go.transform.position, LootheimPlugin.MassInteractRange.Value, num2);
		foreach (Collider val4 in array2)
		{
			if ((Object)(object)val4 == (Object)null || (Object)(object)((Component)val4).gameObject == (Object)null)
			{
				continue;
			}
			Beehive componentInParent3 = ((Component)val4).gameObject.GetComponentInParent<Beehive>();
			if ((Object)(object)componentInParent3 == (Object)null || (Object)(object)componentInParent3 == (Object)(object)val3 || !PrivateArea.CheckAccess(((Component)componentInParent3).transform.position, 0f, true, false))
			{
				continue;
			}
			try
			{
				if (ExtractMethod != null)
				{
					ExtractMethod.Invoke(componentInParent3, null);
				}
			}
			catch
			{
			}
		}
	}
}
[HarmonyPatch(typeof(Pickable), "Interact", new Type[]
{
	typeof(Humanoid),
	typeof(bool),
	typeof(bool)
})]
internal static class FarmAssistMassReplantPatch
{
	private sealed class ReplantState
	{
		internal Player Player;

		internal LootheimPlugin.CropInfo Crop;

		internal Vector3 Position;

		internal Quaternion Rotation;
	}

	private static void Prefix(Pickable __instance, Humanoid character, ref ReplantState __state)
	{
		//IL_00b0: 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_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)
		__state = null;
		if ((Object)(object)__instance == (Object)null || (Object)(object)character == (Object)null || LootheimPlugin.Enabled == null || !LootheimPlugin.Enabled.Value || LootheimPlugin.AutoReplant == null || !LootheimPlugin.AutoReplant.Value || FarmAssistPickup.MassHarvestFrame != Time.frameCount)
		{
			return;
		}
		Player val = (Player)(object)((character is Player) ? character : null);
		if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !LootheimPlugin.IsAlreadyPicked(__instance))
		{
			string key = LootheimPlugin.NormalizePrefabName(((Object)((Component)__instance).gameObject).name);
			if (LootheimPlugin.FarmCrops.TryGetValue(key, out var value) && value != null)
			{
				__state = new ReplantState
				{
					Player = val,
					Crop = value,
					Position = ((Component)__instance).transform.position,
					Rotation = ((Component)__instance).transform.rotation
				};
			}
		}
	}

	private static void Postfix(bool __result, ReplantState __state)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		if (__result && __state != null && !((Object)(object)__state.Player == (Object)null) && __state.Crop != null && LootheimPlugin.ConsumeOneResource(__state.Player, __state.Crop.ResourcePrefab) && !LootheimPlugin.SpawnSapling(__state.Crop.SaplingPrefab, __state.Position, __state.Rotation))
		{
			LootheimPlugin.RefundOneResource(__state.Player, __state.Crop.ResourcePrefab);
		}
	}
}
[HarmonyPatch]
internal static class FarmAssistPlant
{
	private static readonly FieldInfo NoPlacementCostField = AccessTools.Field(typeof(Player), "m_noPlacementCost");

	private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost");

	private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces");

	private static readonly MethodInfo GetRightItemMethod = AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null);

	private static Vector3 PlacedPosition;

	private static Quaternion PlacedRotation;

	private static Piece PlacedPiece;

	private static bool PlaceSuccessful;

	private static int? FarmRotation;

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

	private static GameObject[] PlacementGhosts = (GameObject[])(object)new GameObject[1];

	private static Piece FakeResourcePiece;

	private static bool IsHotKeyPressed
	{
		get
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0040: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			if (LootheimPlugin.Enabled == null || !LootheimPlugin.Enabled.Value || LootheimPlugin.MassActionHotkey == null || LootheimPlugin.ControllerPickupHotkey == null)
			{
				return false;
			}
			KeyboardShortcut value = LootheimPlugin.MassActionHotkey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			KeyboardShortcut value2 = LootheimPlugin.ControllerPickupHotkey.Value;
			KeyCode mainKey2 = ((KeyboardShortcut)(ref value2)).MainKey;
			if ((int)mainKey == 0 || !Input.GetKey(mainKey))
			{
				if ((int)mainKey2 != 0)
				{
					return Input.GetKey(mainKey2);
				}
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	[HarmonyPrefix]
	private static void TryPlacePiecePrefix(int ___m_placeRotation)
	{
		if (IsHotKeyPressed && !FarmRotation.HasValue)
		{
			FarmRotation = ___m_placeRotation;
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	private static void TryPlacePiecePostfix(Player __instance, ref bool __result, Piece piece, ref int ___m_placeRotation)
	{
		//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_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		PlaceSuccessful = __result;
		if (__result)
		{
			GameObject val = null;
			try
			{
				if (PlacementGhostField != null)
				{
					object? value = PlacementGhostField.GetValue(__instance);
					val = (GameObject)((value is GameObject) ? value : null);
				}
			}
			catch
			{
			}
			if ((Object)(object)val != (Object)null)
			{
				PlacedPosition = val.transform.position;
				PlacedRotation = val.transform.rotation;
				PlacedPiece = piece;
			}
		}
		if (IsHotKeyPressed && FarmRotation.HasValue)
		{
			___m_placeRotation = FarmRotation.Value;
		}
	}

	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	[HarmonyPrefix]
	private static void UpdatePlacementPrefix(bool takeInput, float dt, ref int ___m_placeRotation)
	{
		PlaceSuccessful = false;
		if (IsHotKeyPressed && FarmRotation.HasValue)
		{
			___m_placeRotation = FarmRotation.Value;
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	private static void UpdatePlacementPostfix(Player __instance, bool takeInput, float dt, int ___m_placeRotation)
	{
		//IL_0096: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: 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)
		if (IsHotKeyPressed)
		{
			FarmRotation = ___m_placeRotation;
		}
		if (!PlaceSuccessful || (Object)(object)PlacedPiece == (Object)null)
		{
			return;
		}
		Plant component = ((Component)PlacedPiece).gameObject.GetComponent<Plant>();
		if ((!IsCultivatorPlacement(__instance, ((Component)PlacedPiece).gameObject) && (Object)(object)component == (Object)null) || !IsHotKeyPressed)
		{
			return;
		}
		Heightmap val = Heightmap.FindHeightmap(PlacedPosition);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		PieceTable val2 = null;
		try
		{
			if (BuildPiecesField != null)
			{
				object? value = BuildPiecesField.GetValue(__instance);
				val2 = (PieceTable)((value is PieceTable) ? value : null);
			}
		}
		catch
		{
		}
		List<Vector3> list = BuildPlantingGridPositions(PlacedPosition, ((Component)PlacedPiece).gameObject, PlacedRotation);
		for (int i = 0; i < list.Count; i++)
		{
			Vector3 val3 = list[i];
			if ((PlacedPiece.m_cultivatedGroundOnly && !val.IsCultivated(val3)) || PlacedPosition == val3)
			{
				continue;
			}
			ItemData rightItem = GetRightItem(__instance);
			if (rightItem == null)
			{
				continue;
			}
			if (!LootheimPlugin.IgnoreStamina.Value && !((Character)__instance).HaveStamina(rightItem.m_shared.m_attack.m_attackStamina))
			{
				if ((Object)(object)Hud.instance != (Object)null)
				{
					Hud.instance.StaminaBarUppgradeFlash();
				}
				break;
			}
			bool flag = false;
			try
			{
				if (NoPlacementCostField != null)
				{
					flag = (bool)NoPlacementCostField.GetValue(__instance);
				}
			}
			catch
			{
			}
			if (!flag && !__instance.HaveRequirements(PlacedPiece, (RequirementMode)0))
			{
				break;
			}
			if (!HasGrowSpace(val3, ((Component)PlacedPiece).gameObject))
			{
				continue;
			}
			GameObject val4 = Object.Instantiate<GameObject>(((Component)PlacedPiece).gameObject, val3, PlacedRotation);
			Piece component2 = val4.GetComponent<Piece>();
			if ((Object)(object)component2 != (Object)null)
			{
				SetPieceCreatorSafe(component2, __instance);
			}
			PlacedPiece.m_placeEffect.Create(val3, PlacedRotation, val4.transform, 1f, -1, default(ZDOID));
			if ((Object)(object)Game.instance != (Object)null)
			{
				Game.instance.IncrementPlayerStat((PlayerStatType)2, 1f, false);
			}
			__instance.ConsumeResources(PlacedPiece.m_resources, 0, -1, 1);
			if (!LootheimPlugin.IgnoreStamina.Value)
			{
				((Character)__instance).UseStamina(rightItem.m_shared.m_attack.m_attackStamina);
			}
			if ((Object)(object)val2 != (Object)null)
			{
				((Character)__instance).RaiseSkill(val2.m_skill, 1f);
			}
			if (!LootheimPlugin.IgnoreDurability.Value && rightItem.m_shared.m_useDurability)
			{
				rightItem.m_durability -= rightItem.m_shared.m_useDurabilityDrain;
				if (rightItem.m_durability <= 0f)
				{
					break;
				}
			}
		}
	}

	private static void SetPieceCreatorSafe(Piece piece, Player player)
	{
		if ((Object)(object)piece == (Object)null || (Object)(object)player == (Object)null)
		{
			return;
		}
		try
		{
			MethodInfo[] methods = typeof(Piece).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			long playerID = player.GetPlayerID();
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "SetCreator")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(long))
				{
					methodInfo.Invoke(piece, new object[1] { playerID });
					break;
				}
				if (parameters.Length != 2 || !(parameters[0].ParameterType == typeof(long)))
				{
					continue;
				}
				object obj = null;
				try
				{
					Type type = Type.GetType("Splatform.PlatformManager, assembly_utils", throwOnError: false);
					if (type != null)
					{
						PropertyInfo property = type.GetProperty("DistributionPlatform", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
						object obj2 = ((property == null) ? null : property.GetValue(null, null));
						if (obj2 != null)
						{
							PropertyInfo property2 = obj2.GetType().GetProperty("LocalUser", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
							object obj3 = ((property2 == null) ? null : property2.GetValue(obj2, null));
							if (obj3 != null)
							{
								PropertyInfo property3 = obj3.GetType().GetProperty("PlatformUserID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
								if (property3 != null)
								{
									obj = property3.GetValue(obj3, null);
								}
							}
						}
					}
				}
				catch
				{
				}
				if (obj != null && parameters[1].ParameterType.IsInstanceOfType(obj))
				{
					methodInfo.Invoke(piece, new object[2] { playerID, obj });
					break;
				}
			}
		}
		catch
		{
		}
	}

	private static bool IsCultivatorPlacement(Player player, GameObject placementObject)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)placementObject == (Object)null)
		{
			return false;
		}
		ItemData rightItem = GetRightItem(player);
		if (rightItem == null || rightItem.m_shared == null)
		{
			return false;
		}
		if ((Object)(object)rightItem.m_shared.m_buildPieces != (Object)null)
		{
			try
			{
				List<GameObject> pieces = rightItem.m_shared.m_buildPieces.m_pieces;
				if (pieces != null)
				{
					string text = ((Object)placementObject).name.Replace("(Clone)", "");
					for (int i = 0; i < pieces.Count; i++)
					{
						GameObject val = pieces[i];
						if ((Object)(object)val != (Object)null && ((Object)val).name == text)
						{
							string text2 = rightItem.m_shared.m_name ?? "";
							return text2.IndexOf("cultivator", StringComparison.OrdinalIgnoreCase) >= 0;
						}
					}
				}
			}
			catch
			{
			}
		}
		string text3 = rightItem.m_shared.m_name ?? "";
		return text3.IndexOf("cultivator", StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private static float GetFarmAssistSpacing(GameObject placementObject)
	{
		if ((Object)(object)placementObject == (Object)null)
		{
			return 1f;
		}
		Plant component = placementObject.GetComponent<Plant>();
		if ((Object)(object)component != (Object)null)
		{
			return Mathf.Max(0.5f, component.m_growRadius * 2f);
		}
		float num = ((LootheimPlugin.NonPlantFloraSpacing == null) ? 1f : LootheimPlugin.NonPlantFloraSpacing.Value);
		return Mathf.Clamp(num, 0.5f, 4f);
	}

	private static ItemData GetRightItem(Player player)
	{
		if ((Object)(object)player == (Object)null || GetRightItemMethod == null)
		{
			return null;
		}
		try
		{
			object? obj = GetRightItemMethod.Invoke(player, new object[0]);
			return (ItemData)((obj is ItemData) ? obj : null);
		}
		catch
		{
			return null;
		}
	}

	private static List<Vector3> BuildPlantingGridPositions(Vector3 originPos, GameObject placementObject, Quaternion rotation)
	{
		//IL_0032: 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_0038: Unknown result type (might be due to invalid IL or missing references)
		//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: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: 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_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_0058: 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_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: 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_00d6: 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)
		//IL_00da: 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_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: 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_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		float farmAssistSpacing = GetFarmAssistSpacing(placementObject);
		int num = Mathf.Max(1, LootheimPlugin.PlantGridWidth.Value);
		int num2 = Mathf.Max(1, LootheimPlugin.PlantGridLength.Value);
		List<Vector3> list = new List<Vector3>(num * num2);
		Vector3 val = rotation * Vector3.left * farmAssistSpacing;
		Vector3 val2 = rotation * Vector3.forward * farmAssistSpacing;
		Vector3 val3 = originPos;
		if (LootheimPlugin.GridAnchorLength.Value)
		{
			val3 -= val2 * (float)(num2 / 2);
		}
		if (LootheimPlugin.GridAnchorWidth.Value)
		{
			val3 -= val * (float)(num / 2);
		}
		for (int i = 0; i < num2; i++)
		{
			Vector3 val4 = val3;
			for (int j = 0; j < num; j++)
			{
				try
				{
					if ((Object)(object)ZoneSystem.instance != (Object)null)
					{
						val4.y = ZoneSystem.instance.GetGroundHeight(val4);
					}
				}
				catch
				{
				}
				list.Add(val4);
				val4 += val;
			}
			val3 += val2;
		}
		return list;
	}

	private static bool HasGrowSpace(Vector3 newPos, GameObject go)
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)go == (Object)null)
		{
			return true;
		}
		Plant component = go.GetComponent<Plant>();
		float num;
		if ((Object)(object)component != (Object)null)
		{
			num = Mathf.Max(0.25f, component.m_growRadius);
		}
		else
		{
			float farmAssistSpacing = GetFarmAssistSpacing(go);
			num = Mathf.Clamp(farmAssistSpacing * 0.4f, 0.25f, 1.5f);
		}
		Collider[] array = Physics.OverlapSphere(newPos + Vector3.up * 0.25f, num, PlantSpaceMask, (QueryTriggerInteraction)1);
		if (array == null || array.Length == 0)
		{
			return true;
		}
		foreach (Collider val in array)
		{
			if (!((Object)(object)val == (Object)null))
			{
				Heightmap componentInParent = ((Component)val).GetComponentInParent<Heightmap>();
				if (!((Object)(object)componentInParent != (Object)null) && !((Object)(object)((Component)val).transform == (Object)(object)go.transform) && !((Component)val).transform.IsChildOf(go.transform))
				{
					return false;
				}
			}
		}
		return true;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(Player), "SetupPlacementGhost")]
	private static void SetupPlacementGhostPrefix(Player __instance, int ___m_placeRotation)
	{
		if (IsHotKeyPressed && !FarmRotation.HasValue)
		{
			FarmRotation = ___m_placeRotation;
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Player), "SetupPlacementGhost")]
	private static void SetupPlacementGhostPostfix(Player __instance, ref int ___m_placeRotation)
	{
		if (IsHotKeyPressed && FarmRotation.HasValue)
		{
			___m_placeRotation = FarmRotation.Value;
		}
		DestroyGhosts();
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	private static void UpdatePlacementGhostPostfix(Player __instance, bool flashGuardStone)
	{
		//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_0179: 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_01ba: 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_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: 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)
		GameObject val = null;
		try
		{
			if (PlacementGhostField != null)
			{
				object? value = PlacementGhostField.GetValue(__instance);
				val = (GameObject)((value is GameObject) ? value : null);
			}
		}
		catch
		{
		}
		if ((Object)(object)val == (Object)null || !val.activeSelf)
		{
			SetGhostsActive(active: false);
			return;
		}
		if (!IsHotKeyPressed)
		{
			SetGhostsActive(active: false);
			return;
		}
		Plant component = val.GetComponent<Plant>();
		if (!IsCultivatorPlacement(__instance, val) && (Object)(object)component == (Object)null)
		{
			SetGhostsActive(active: false);
			return;
		}
		if (!EnsureGhostsBuilt(__instance))
		{
			SetGhostsActive(active: false);
			return;
		}
		Piece component2 = val.GetComponent<Piece>();
		if ((Object)(object)component2 == (Object)null || (Object)(object)FakeResourcePiece == (Object)null)
		{
			return;
		}
		Requirement val2 = ((IEnumerable<Requirement>)component2.m_resources).FirstOrDefault((Func<Requirement, bool>)((Requirement r) => r != null && (Object)(object)r.m_resItem != (Object)null && r.m_amount > 0));
		if (val2 == null)
		{
			return;
		}
		FakeResourcePiece.m_resources[0].m_resItem = val2.m_resItem;
		FakeResourcePiece.m_resources[0].m_amount = val2.m_amount;
		float num = __instance.GetStamina();
		ItemData rightItem = GetRightItem(__instance);
		if (rightItem == null)
		{
			return;
		}
		Heightmap val3 = Heightmap.FindHeightmap(val.transform.position);
		if ((Object)(object)val3 == (Object)null)
		{
			return;
		}
		List<Vector3> list = BuildPlantingGridPositions(val.transform.position, val, val.transform.rotation);
		for (int num2 = 0; num2 < PlacementGhosts.Length && num2 < list.Count; num2++)
		{
			Vector3 val4 = list[num2];
			GameObject val5 = PlacementGhosts[num2];
			if ((Object)(object)val5 == (Object)null)
			{
				continue;
			}
			if (val.transform.position == val4)
			{
				val5.SetActive(false);
				continue;
			}
			Requirement obj2 = FakeResourcePiece.m_resources[0];
			obj2.m_amount += val2.m_amount;
			val5.transform.position = val4;
			val5.transform.rotation = val.transform.rotation;
			val5.SetActive(true);
			bool invalidPlacementHeightlight = false;
			if (component2.m_cultivatedGroundOnly && !val3.IsCultivated(val4))
			{
				invalidPlacementHeightlight = true;
			}
			else if (!HasGrowSpace(val4, val))
			{
				invalidPlacementHeightlight = true;
			}
			else if (!LootheimPlugin.IgnoreStamina.Value && num < rightItem.m_shared.m_attack.m_attackStamina)
			{
				if ((Object)(object)Hud.instance != (Object)null)
				{
					Hud.instance.StaminaBarUppgradeFlash();
				}
				invalidPlacementHeightlight = true;
			}
			else
			{
				bool flag = false;
				try
				{
					if (NoPlacementCostField != null)
					{
						flag = (bool)NoPlacementCostField.GetValue(__instance);
					}
				}
				catch
				{
				}
				if (!flag && !__instance.HaveRequirements(FakeResourcePiece, (RequirementMode)0))
				{
					invalidPlacementHeightlight = true;
				}
			}
			num -= rightItem.m_shared.m_attack.m_attackStamina;
			Piece component3 = val5.GetComponent<Piece>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.SetInvalidPlacementHeightlight(invalidPlacementHeightlight);
			}
		}
	}

	private static bool EnsureGhostsBuilt(Player player)
	{
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Expected O, but got Unknown
		int num = Mathf.Max(1, LootheimPlugin.PlantGridWidth.Value) * Mathf.Max(1, LootheimPlugin.PlantGridLength.Value);
		if (PlacementGhosts == null || PlacementGhosts.Length == 0 || (Object)(object)PlacementGhosts[0] == (Object)null || PlacementGhosts.Length != num)
		{
			DestroyGhosts();
			if (PlacementGhosts == null || PlacementGhosts.Length != num)
			{
				PlacementGhosts = (GameObject[])(object)new GameObject[num];
			}
			PieceTable val = null;
			try
			{
				if (BuildPiecesField != null)
				{
					object? value = BuildPiecesField.GetValue(player);
					val = (PieceTable)((value is PieceTable) ? value : null);
				}
			}
			catch
			{
			}
			GameObject val2 = (((Object)(object)val == (Object)null) ? null : val.GetSelectedPrefab());
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			Piece component = val2.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && component.m_repairPiece)
			{
				return false;
			}
			for (int i = 0; i < PlacementGhosts.Length; i++)
			{
				PlacementGhosts[i] = SetupMyGhost(player, val2);
			}
		}
		if ((Object)(object)FakeResourcePiece == (Object)null)
		{
			if (PlacementGhosts == null || PlacementGhosts.Length == 0 || (Object)(object)PlacementGhosts[0] == (Object)null)
			{
				return false;
			}
			FakeResourcePiece = PlacementGhosts[0].GetComponent<Piece>();
			if ((Object)(object)FakeResourcePiece == (Object)null)
			{
				return false;
			}
			FakeResourcePiece.m_dlc = string.Empty;
			FakeResourcePiece.m_resources = (Requirement[])(object)new Requirement[1]
			{
				new Requirement()
			};
		}
		return true;
	}

	private static void DestroyGhosts()
	{
		if (PlacementGhosts != null)
		{
			for (int i = 0; i < PlacementGhosts.Length; i++)
			{
				if ((Object)(object)PlacementGhosts[i] != (Object)null)
				{
					Object.Destroy((Object)(object)PlacementGhosts[i]);
					PlacementGhosts[i] = null;
				}
			}
		}
		FakeResourcePiece = null;
	}

	private static void SetGhostsActive(bool active)
	{
		if (PlacementGhosts == null)
		{
			return;
		}
		for (int i = 0; i < PlacementGhosts.Length; i++)
		{
			if ((Object)(object)PlacementGhosts[i] != (Object)null)
			{
				PlacementGhosts[i].SetActive(active);
			}
		}
	}

	private static GameObject SetupMyGhost(Player player, GameObject prefab)
	{
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Expected O, but got Unknown
		ZNetView.m_forceDisableInit = true;
		GameObject val = Object.Instantiate<GameObject>(prefab);
		ZNetView.m_forceDisableInit = false;
		((Object)val).name = ((Object)prefab).name;
		Joint[] componentsInChildren = val.GetComponentsInChildren<Joint>();
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.Destroy((Object)(object)componentsInChildren[i]);
		}
		Rigidbody[] componentsInChildren2 = val.GetComponentsInChildren<Rigidbody>();
		for (int j = 0; j < componentsInChildren2.Length; j++)
		{
			Object.Destroy((Object)(object)componentsInChildren2[j]);
		}
		int layer = LayerMask.NameToLayer("ghost");
		Transform[] componentsInChildren3 = val.GetComponentsInChildren<Transform>();
		for (int k = 0; k < componentsInChildren3.Length; k++)
		{
			((Component)componentsInChildren3[k]).gameObject.layer = layer;
		}
		TerrainModifier[] componentsInChildren4 = val.GetComponentsInChildren<TerrainModifier>();
		for (int l = 0; l < componentsInChildren4.Length; l++)
		{
			Object.Destroy((Object)(object)componentsInChildren4[l]);
		}
		GuidePoint[] componentsInChildren5 = val.GetComponentsInChildren<GuidePoint>();
		for (int m = 0; m < componentsInChildren5.Length; m++)
		{
			Object.Destroy((Object)(object)componentsInChildren5[m]);
		}
		Light[] componentsInChildren6 = val.GetComponentsInChildren<Light>();
		for (int n = 0; n < componentsInChildren6.Length; n++)
		{
			Object.Destroy((Object)(object)componentsInChildren6[n]);
		}
		Transform val2 = val.transform.Find("_GhostOnly");
		if ((Object)(object)val2 != (Object)null)
		{
			((Component)val2).gameObject.SetActive(true);
		}
		MeshRenderer[] componentsInChildren7 = val.GetComponentsInChildren<MeshRenderer>();
		foreach (MeshRenderer val3 in componentsInChildren7)
		{
			if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Renderer)val3).sharedMaterial == (Object)null))
			{
				Material[] sharedMaterials = ((Renderer)val3).sharedMaterials;
				for (int num2 = 0; num2 < sharedMaterials.Length; num2++)
				{
					Material val4 = new Material(sharedMaterials[num2]);
					val4.SetFloat("_RippleDistance", 0f);
					val4.SetFloat("_ValueNoise", 0f);
					sharedMaterials[num2] = val4;
				}
				((Renderer)val3).sharedMaterials = sharedMaterials;
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
			}
		}
		return val;
	}
}