Decompiled source of LetsBuild v0.6.4

plugins/LetsBuild.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DezzyCode")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("DezzyCode")]
[assembly: AssemblyDescription("A creative builder's hammer, precision building, and grid planting.")]
[assembly: AssemblyFileVersion("0.6.4.0")]
[assembly: AssemblyInformationalVersion("0.6.4+b7227102362cc88e48c647f158b8ae3fbdbc8943")]
[assembly: AssemblyProduct("Lets Build")]
[assembly: AssemblyTitle("LetsBuild")]
[assembly: AssemblyVersion("0.6.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LetsBuild
{
	[HarmonyPatch]
	internal static class BuildCamera
	{
		private const float Speed = 10f;

		private const float MaxPitch = 89f;

		private static readonly MethodInfo PlayerTakesInput = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null);

		private static readonly FieldRef<Character, float> MaxAirAltitude = AccessTools.FieldRefAccess<Character, float>("m_maxAirAltitude");

		private static bool _loose;

		private static Vector3 _position;

		private static float _yaw;

		private static float _pitch;

		private static Vector3 _start;

		private static readonly List<Renderer> Hidden = new List<Renderer>();

		private static readonly List<Collider> Disabled = new List<Collider>();

		private static bool _flightReading;

		public static void Tick(Player player)
		{
			if (_loose && ((Object)(object)player == (Object)null || ((Character)player).IsDead() || !CreativeMode.Active))
			{
				Fix(player);
			}
			else
			{
				if ((Object)(object)player == (Object)null || !CreativeMode.Active)
				{
					return;
				}
				if (Keys.Down(Settings.CameraKey) && Listening(player))
				{
					if (_loose)
					{
						Fix(player);
					}
					else
					{
						Loosen(player);
					}
				}
				if (_loose && Listening(player) && !Hud.IsPieceSelectionVisible() && !Hud.InRadial())
				{
					Fly(Time.unscaledDeltaTime);
				}
			}
		}

		private static bool Listening(Player player)
		{
			if (!(PlayerTakesInput == null))
			{
				return (bool)PlayerTakesInput.Invoke(player, null);
			}
			return true;
		}

		private static void Loosen(Player player)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_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_003f: 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_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)
			Transform val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform : null);
			if (!((Object)(object)val == (Object)null))
			{
				_position = val.position;
				Quaternion rotation = val.rotation;
				Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
				_yaw = eulerAngles.y;
				_pitch = Mathf.Clamp(Mathf.DeltaAngle(0f, eulerAngles.x), -89f, 89f);
				_start = ((Component)player).transform.position;
				Hide(player);
				_loose = true;
				((Character)player).Message((MessageType)1, "$lb_camera_loose", 0, (Sprite)null, false);
			}
		}

		private static void Fix(Player player)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			_loose = false;
			if ((Object)(object)player == (Object)null)
			{
				Hidden.Clear();
				Disabled.Clear();
				return;
			}
			Show();
			if (!player.InDebugFlyMode())
			{
				Teleport(player, _start);
				MaxAirAltitude.Invoke((Character)(object)player) = _start.y;
			}
			((Character)player).Message((MessageType)1, "$lb_camera_fixed", 0, (Sprite)null, false);
		}

		private static void Fly(float dt)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0084: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_010d: 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_0118: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = ZInput.GetMouseDelta() * PlayerController.m_mouseSens;
			if (PlayerController.m_invertMouse)
			{
				val.y = 0f - val.y;
			}
			_yaw += val.x;
			_pitch = Mathf.Clamp(_pitch - val.y, -89f, 89f);
			Quaternion val2 = Quaternion.Euler(_pitch, _yaw, 0f);
			Vector3 val3 = Vector3.zero;
			if (ZInput.GetButton("Forward"))
			{
				val3 += val2 * Vector3.forward;
			}
			if (ZInput.GetButton("Backward"))
			{
				val3 += val2 * Vector3.back;
			}
			if (ZInput.GetButton("Left"))
			{
				val3 += val2 * Vector3.left;
			}
			if (ZInput.GetButton("Right"))
			{
				val3 += val2 * Vector3.right;
			}
			if (ZInput.GetButton("Jump"))
			{
				val3 += Vector3.up;
			}
			if (ZInput.GetButton("Crouch"))
			{
				val3 += Vector3.down;
			}
			if (((Vector3)(ref val3)).sqrMagnitude > 1f)
			{
				((Vector3)(ref val3)).Normalize();
			}
			_position += val3 * (10f * dt);
		}

		private static void Hide(Player player)
		{
			Hidden.Clear();
			Renderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<Renderer>();
			foreach (Renderer val in componentsInChildren)
			{
				if (val.enabled)
				{
					val.enabled = false;
					Hidden.Add(val);
				}
			}
			Disabled.Clear();
			Collider[] componentsInChildren2 = ((Component)player).GetComponentsInChildren<Collider>();
			foreach (Collider val2 in componentsInChildren2)
			{
				if (val2.enabled && !val2.isTrigger)
				{
					val2.enabled = false;
					Disabled.Add(val2);
				}
			}
		}

		private static void Show()
		{
			foreach (Renderer item in Hidden)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.enabled = true;
				}
			}
			foreach (Collider item2 in Disabled)
			{
				if ((Object)(object)item2 != (Object)null)
				{
					item2.enabled = true;
				}
			}
			Hidden.Clear();
			Disabled.Clear();
		}

		private static void Carry(Player player)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			if (!((Object)(object)((Character)player).m_eye == (Object)null))
			{
				Vector3 val = ((Character)player).m_eye.position - ((Component)player).transform.position;
				Teleport(player, _position - val);
				MaxAirAltitude.Invoke((Character)(object)player) = ((Component)player).transform.position.y;
			}
		}

		private static void Teleport(Player player, Vector3 position)
		{
			//IL_0006: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			((Component)player).transform.position = position;
			Rigidbody component = ((Component)player).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.position = position;
				component.linearVelocity = Vector3.zero;
				component.useGravity = false;
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		[HarmonyPostfix]
		private static void Place(GameCamera __instance)
		{
			//IL_000e: 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)
			if (_loose)
			{
				((Component)__instance).transform.position = _position;
				((Component)__instance).transform.rotation = Quaternion.Euler(_pitch, _yaw, 0f);
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					Carry(localPlayer);
				}
			}
		}

		[HarmonyPatch(typeof(Character), "UpdateDebugFly")]
		[HarmonyPrefix]
		private static void FlightReads(Character __instance)
		{
			_flightReading = _loose && (Object)(object)__instance == (Object)(object)Player.m_localPlayer;
		}

		[HarmonyPatch(typeof(Character), "UpdateDebugFly")]
		[HarmonyFinalizer]
		private static void FlightDone()
		{
			_flightReading = false;
		}

		[HarmonyPatch(typeof(Player), "TakeInput")]
		[HarmonyPrefix]
		private static bool FlightInput(ref bool __result)
		{
			if (!_flightReading)
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(PlayerController), "TakeInput")]
		[HarmonyPrefix]
		private static bool CharacterInput(ref bool __result)
		{
			if (!_loose)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	internal static class CreativeHammer
	{
		public const string PrefabName = "LetsBuild_Hammer";

		public const string NameToken = "$lb_hammer";

		private const string IconFile = "hammer.png";

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Create;
		}

		public static bool IsHammer(ItemData item)
		{
			if (item?.m_shared != null)
			{
				return item.m_shared.m_name == "$lb_hammer";
			}
			return false;
		}

		private static void Create()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Create;
			ItemConfig val = new ItemConfig();
			val.Name = "$lb_hammer";
			val.Description = "$lb_hammer_desc";
			val.CraftingStation = CraftingStations.Workbench;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[1]
			{
				new RequirementConfig
				{
					Item = "Wood",
					Amount = 1,
					Recover = true
				}
			};
			ItemConfig val2 = val;
			CustomItem val3 = (Settings.Craftable.Value ? new CustomItem("LetsBuild_Hammer", "Hammer", val2) : new CustomItem("LetsBuild_Hammer", "Hammer"));
			if ((Object)(object)val3.ItemPrefab == (Object)null)
			{
				Log.Warning("Could not clone the vanilla hammer; the builder's hammer is unavailable.");
				return;
			}
			SharedData shared = val3.ItemDrop.m_itemData.m_shared;
			shared.m_name = "$lb_hammer";
			shared.m_description = "$lb_hammer_desc";
			shared.m_useDurability = false;
			Sprite val4 = LoadIcon();
			if ((Object)(object)val4 != (Object)null)
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { val4 };
			}
			ItemManager.Instance.AddItem(val3);
			Log.Info(Settings.Craftable.Value ? "Builder's hammer registered, craftable at the workbench." : "Builder's hammer registered; spawn it with \"spawn LetsBuild_Hammer\".");
		}

		private static Sprite LoadIcon()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00d0: 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)
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = ((directoryName != null) ? Path.Combine(directoryName, "hammer.png") : null);
			if (text == null || !File.Exists(text))
			{
				Log.Warning("hammer.png is not next to the DLL; the hammer keeps the vanilla icon.");
				return null;
			}
			MethodInfo methodInfo = AccessTools.Method("UnityEngine.ImageConversion:LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, (Type[])null);
			if (methodInfo == null)
			{
				Log.Warning("Cannot decode hammer.png; the hammer keeps the vanilla icon.");
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!(bool)methodInfo.Invoke(null, new object[2]
			{
				val,
				File.ReadAllBytes(text)
			}))
			{
				Object.Destroy((Object)(object)val);
				Log.Warning("hammer.png could not be decoded; the hammer keeps the vanilla icon.");
				return null;
			}
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}
	}
	[HarmonyPatch]
	internal static class CreativeMode
	{
		private static bool _active;

		private static bool _hadCheats;

		private static bool _hadDebug;

		private static bool _hadFly;

		private static bool _hadFreeBuild;

		private static bool _flyOffPending;

		private static bool _silent;

		public static bool Active => _active;

		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		[HarmonyPostfix]
		private static void Equipped(Humanoid __instance, ItemData item, bool __result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if (__result && IsOurs(__instance, item))
			{
				Enter((Player)__instance);
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
		[HarmonyPostfix]
		private static void Unequipped(Humanoid __instance, ItemData item)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			if (IsOurs(__instance, item))
			{
				Leave((Player)__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "OnDestroy")]
		[HarmonyPrefix]
		private static void PlayerGone(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && _active)
			{
				_active = false;
				_flyOffPending = false;
				Terminal.m_cheat = _hadCheats;
				Player.m_debugMode = _hadDebug;
				Log.Info("Creative mode off; the world closed while the hammer was held.");
			}
		}

		[HarmonyPatch(typeof(Player), "Message")]
		[HarmonyPrefix]
		private static bool Quiet()
		{
			return !_silent;
		}

		private static bool IsOurs(Humanoid humanoid, ItemData item)
		{
			if ((Object)(object)humanoid == (Object)(object)Player.m_localPlayer)
			{
				return CreativeHammer.IsHammer(item);
			}
			return false;
		}

		private static void Enter(Player player)
		{
			if (_active)
			{
				return;
			}
			if (Settings.AdminOnly.Value && !IsAdmin())
			{
				((Character)player).Message((MessageType)2, "$lb_admin_only", 0, (Sprite)null, false);
				return;
			}
			_hadCheats = Terminal.m_cheat;
			_hadDebug = Player.m_debugMode;
			_hadFly = player.InDebugFlyMode();
			_hadFreeBuild = player.NoCostCheat();
			_flyOffPending = false;
			_active = true;
			Terminal.m_cheat = true;
			Player.m_debugMode = true;
			Silently(delegate
			{
				player.SetNoPlacementCost(true);
				if (!_hadFly && Settings.Fly.Value)
				{
					player.ToggleDebugFly();
				}
			});
			((Character)player).Message((MessageType)1, "$lb_creative_on", 0, (Sprite)null, false);
			Log.Info("Creative mode on (was: cheats " + _hadCheats + ", debug " + _hadDebug + ", fly " + _hadFly + ", free build " + _hadFreeBuild + ").");
		}

		private static void Leave(Player player)
		{
			if (!_active)
			{
				return;
			}
			_active = false;
			Terminal.m_cheat = _hadCheats;
			Player.m_debugMode = _hadDebug;
			Silently(delegate
			{
				player.SetNoPlacementCost(_hadFreeBuild);
			});
			if (player.InDebugFlyMode() == _hadFly)
			{
				((Character)player).Message((MessageType)1, "$lb_creative_off", 0, (Sprite)null, false);
				Log.Info("Creative mode off.");
			}
			else if (((Character)player).IsOnGround())
			{
				Silently(delegate
				{
					player.ToggleDebugFly();
				});
				((Character)player).Message((MessageType)1, "$lb_creative_off", 0, (Sprite)null, false);
				Log.Info("Creative mode off.");
			}
			else
			{
				_flyOffPending = true;
				((Character)player).Message((MessageType)1, "$lb_fly_until_landed", 0, (Sprite)null, false);
				Log.Info("Creative mode off; flight stays until you land.");
			}
		}

		public static void Tick(Player player)
		{
			if (!_flyOffPending || (Object)(object)player == (Object)null)
			{
				return;
			}
			if (_active)
			{
				_flyOffPending = false;
			}
			else
			{
				if (!((Character)player).IsOnGround())
				{
					return;
				}
				_flyOffPending = false;
				if (player.InDebugFlyMode() != _hadFly)
				{
					Silently(delegate
					{
						player.ToggleDebugFly();
					});
					((Character)player).Message((MessageType)1, "$lb_creative_off", 0, (Sprite)null, false);
					Log.Info("Landed; flight off.");
				}
			}
		}

		private static void Silently(Action action)
		{
			_silent = true;
			try
			{
				action();
			}
			finally
			{
				_silent = false;
			}
		}

		private static bool IsAdmin()
		{
			if (!((Object)(object)ZNet.instance == (Object)null))
			{
				return SynchronizationManager.Instance.PlayerIsAdmin;
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class HammerKeeper
	{
		private const string Key = "LetsBuild.Hammers";

		[HarmonyPatch(typeof(Player), "Save")]
		[HarmonyPrefix]
		private static void Remember(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				int num = Count(((Humanoid)__instance).GetInventory());
				if (num > 0)
				{
					__instance.m_customData["LetsBuild.Hammers"] = num.ToString(CultureInfo.InvariantCulture);
				}
				else
				{
					__instance.m_customData.Remove("LetsBuild.Hammers");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		[HarmonyPostfix]
		private static void Restore(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !__instance.m_customData.TryGetValue("LetsBuild.Hammers", out var value) || !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return;
			}
			Inventory inventory = ((Humanoid)__instance).GetInventory();
			int num = result - Count(inventory);
			if (num <= 0)
			{
				return;
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("LetsBuild_Hammer") : null);
			if ((Object)(object)val == (Object)null)
			{
				Log.Warning("A builder's hammer is missing from the inventory, but the item is not registered.");
				return;
			}
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				if (!inventory.AddItem(val, 1))
				{
					break;
				}
				num2++;
			}
			if (num2 > 0)
			{
				Log.Info("Restored " + num2 + " builder's hammer(s) lost while the mod was not loaded.");
				((Character)__instance).Message((MessageType)2, "$lb_hammer_restored", 0, (Sprite)null, false);
			}
			if (num2 < num)
			{
				((Character)__instance).Message((MessageType)2, "$lb_hammer_no_room", 0, (Sprite)null, false);
			}
		}

		private static int Count(Inventory inventory)
		{
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (CreativeHammer.IsHammer(allItem))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}
	}
	[HarmonyPatch]
	internal static class HintPanel
	{
		private sealed class Line
		{
			public string Text;

			public string[] Keys;

			public bool Combination;
		}

		private sealed class Row
		{
			public GameObject Root;

			public TMP_Text Label;

			public readonly List<GameObject> Parts = new List<GameObject>();

			public string Shape;
		}

		private const float LineSpacing = 4f;

		private const float BarGap = 14f;

		private const float PartSpacing = 6f;

		private static RectTransform _panel;

		private static Image _picture;

		private static GameObject _labelTemplate;

		private static GameObject _keyTemplate;

		private static readonly List<Row> Rows = new List<Row>();

		private static readonly List<Line> Lines = new List<Line>();

		[HarmonyPatch(typeof(KeyHints), "Start")]
		[HarmonyPostfix]
		private static void Build(KeyHints __instance)
		{
			try
			{
				Create(__instance);
			}
			catch (Exception ex)
			{
				_panel = null;
				Log.Warning("Key hints could not be built from the game's hint bar: " + ex.Message);
			}
		}

		private static void Create(KeyHints vanilla)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: 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)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			Rows.Clear();
			GameObject buildHints = vanilla.m_buildHints;
			UIInputHint val = (((Object)(object)buildHints != (Object)null) ? buildHints.GetComponent<UIInputHint>() : null);
			Transform val2 = (((Object)(object)val != (Object)null && (Object)(object)val.m_mouseKeyboardHint != (Object)null) ? val.m_mouseKeyboardHint.transform : null);
			Transform val3 = (((Object)(object)val2 != (Object)null) ? val2.Find("Place") : null);
			Transform val4 = (((Object)(object)val3 != (Object)null) ? val3.Find("Text") : null);
			Transform val5 = (((Object)(object)val3 != (Object)null) ? val3.Find("key_bkg") : null);
			if ((Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val5.Find("Key") == (Object)null)
			{
				Log.Warning("The game's build hints are not built as expected; key hints are off.");
				return;
			}
			Transform val6 = LastEntry(val2);
			Transform val7 = (((Object)(object)val6 != (Object)null) ? LastVisible(val6) : buildHints.transform);
			GameObject val8 = new GameObject("LetsBuild_KeyHints", new Type[1] { typeof(RectTransform) });
			_panel = (RectTransform)val8.transform;
			((Transform)_panel).SetParent(val7, false);
			Vector3 lossyScale = buildHints.transform.lossyScale;
			Vector3 lossyScale2 = val7.lossyScale;
			((Transform)_panel).localScale = new Vector3(Mathf.Approximately(lossyScale2.x, 0f) ? 1f : (lossyScale.x / lossyScale2.x), Mathf.Approximately(lossyScale2.y, 0f) ? 1f : (lossyScale.y / lossyScale2.y), 1f);
			_panel.anchorMin = new Vector2(1f, 1f);
			_panel.anchorMax = new Vector2(1f, 1f);
			_panel.pivot = new Vector2(1f, 0f);
			_panel.anchoredPosition = new Vector2(0f, 14f);
			Log.Info("Key hints hang on \"" + (((Object)(object)val6 != (Object)null) ? (((Object)val6).name + "/") : "") + ((Object)val7).name + "\".");
			_picture = ((Component)val7).GetComponent<Image>();
			val8.AddComponent<LayoutElement>().ignoreLayout = true;
			VerticalLayoutGroup obj = val8.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).childAlignment = (TextAnchor)8;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 4f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			ContentSizeFitter obj2 = val8.AddComponent<ContentSizeFitter>();
			obj2.horizontalFit = (FitMode)2;
			obj2.verticalFit = (FitMode)2;
			_labelTemplate = Template(((Component)val4).gameObject, "label");
			_keyTemplate = Template(((Component)val5).gameObject, "key");
			val8.SetActive(false);
		}

		private static Transform LastVisible(Transform entry)
		{
			for (int num = entry.childCount - 1; num >= 0; num--)
			{
				Transform child = entry.GetChild(num);
				if (((Component)child).gameObject.activeSelf && child is RectTransform && (Object)(object)((Component)child).GetComponent<Graphic>() != (Object)null)
				{
					return child;
				}
			}
			return entry;
		}

		private static Transform LastEntry(Transform keyboard)
		{
			for (int num = keyboard.childCount - 1; num >= 0; num--)
			{
				Transform child = keyboard.GetChild(num);
				if (((Component)child).gameObject.activeSelf && child is RectTransform)
				{
					return child;
				}
			}
			return null;
		}

		private static GameObject Template(GameObject source, string name)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0053: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(source, (Transform)(object)_panel, false);
			((Object)val).name = "template_" + name;
			Localize[] componentsInChildren = val.GetComponentsInChildren<Localize>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			RectTransform val2 = (RectTransform)source.transform;
			RectTransform val3 = (RectTransform)val.transform;
			Rect rect = val2.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			val3.anchorMin = new Vector2(0.5f, 0.5f);
			val3.anchorMax = new Vector2(0.5f, 0.5f);
			val3.pivot = new Vector2(0.5f, 0.5f);
			val3.sizeDelta = size;
			val.SetActive(false);
			return val;
		}

		public static void Tick()
		{
			if ((Object)(object)_panel == (Object)null)
			{
				return;
			}
			AlignToPicture();
			Collect();
			bool flag = Lines.Count > 0;
			if (((Component)_panel).gameObject.activeSelf != flag)
			{
				((Component)_panel).gameObject.SetActive(flag);
			}
			if (!flag)
			{
				return;
			}
			while (Rows.Count < Lines.Count)
			{
				Rows.Add(NewRow());
			}
			bool flag2 = false;
			for (int i = 0; i < Rows.Count; i++)
			{
				Row row = Rows[i];
				bool flag3 = i < Lines.Count;
				if (row.Root.activeSelf != flag3)
				{
					row.Root.SetActive(flag3);
					flag2 = true;
				}
				if (flag3 && Fill(row, Lines[i]))
				{
					flag2 = true;
				}
			}
			if (flag2)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(_panel);
			}
		}

		private static void AlignToPicture()
		{
			//IL_0025: 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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_picture == (Object)null || (Object)(object)_panel == (Object)null)
			{
				return;
			}
			Rect rect = ((Graphic)_picture).rectTransform.rect;
			if (((Rect)(ref rect)).width <= 0f || ((Rect)(ref rect)).height <= 0f)
			{
				return;
			}
			Image picture = _picture;
			_picture = null;
			float num = ((Rect)(ref rect)).xMin;
			float num2 = ((Rect)(ref rect)).width;
			Sprite val = (((Object)(object)picture.overrideSprite != (Object)null) ? picture.overrideSprite : picture.sprite);
			Rect rect2;
			if ((Object)(object)val != (Object)null && picture.preserveAspect)
			{
				rect2 = val.rect;
				if (((Rect)(ref rect2)).height > 0f)
				{
					rect2 = val.rect;
					float width = ((Rect)(ref rect2)).width;
					rect2 = val.rect;
					float num3 = width / ((Rect)(ref rect2)).height;
					float num4 = ((Rect)(ref rect)).height * num3;
					if (num4 < ((Rect)(ref rect)).width)
					{
						num = ((Rect)(ref rect)).xMin + (((Rect)(ref rect)).width - num4) * ((Graphic)picture).rectTransform.pivot.x;
						num2 = num4;
					}
				}
			}
			float num5 = 0f;
			if ((Object)(object)val != (Object)null)
			{
				rect2 = val.rect;
				if (((Rect)(ref rect2)).width > 0f)
				{
					float num6 = float.MinValue;
					Vector2[] array;
					try
					{
						array = val.vertices;
					}
					catch (Exception)
					{
						array = (Vector2[])(object)new Vector2[0];
					}
					Vector2[] array2 = array;
					foreach (Vector2 val2 in array2)
					{
						num6 = Mathf.Max(num6, val2.x);
					}
					if (num6 > float.MinValue)
					{
						float num7 = num6 * val.pixelsPerUnit + val.pivot.x;
						rect2 = val.rect;
						num5 = Mathf.Clamp01(1f - num7 / ((Rect)(ref rect2)).width);
					}
				}
			}
			float num8 = num + num2 * (1f - num5);
			float num9 = Mathf.Min(0f, num8 - ((Rect)(ref rect)).xMax);
			_panel.anchoredPosition = new Vector2(num9, _panel.anchoredPosition.y);
			string[] obj = new string[13]
			{
				"Key hints aligned to the drawn mouse: rect ",
				((Rect)(ref rect)).width.ToString("0.#"),
				" x ",
				((Rect)(ref rect)).height.ToString("0.#"),
				", preserve aspect ",
				picture.preserveAspect.ToString(),
				", sprite ",
				null,
				null,
				null,
				null,
				null,
				null
			};
			object obj2;
			if (!((Object)(object)val != (Object)null))
			{
				obj2 = "none";
			}
			else
			{
				rect2 = val.rect;
				string text = ((Rect)(ref rect2)).width.ToString();
				rect2 = val.rect;
				obj2 = text + " x " + ((Rect)(ref rect2)).height;
			}
			obj[7] = (string)obj2;
			obj[8] = ", right margin in sprite ";
			obj[9] = (num5 * 100f).ToString("0");
			obj[10] = " %, offset ";
			obj[11] = num9.ToString("0.#");
			obj[12] = ".";
			Log.Info(string.Concat(obj));
		}

		private static Row NewRow()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			GameObject val = new GameObject("line", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_panel, false);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((LayoutGroup)obj).childAlignment = (TextAnchor)5;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			ContentSizeFitter obj2 = val.AddComponent<ContentSizeFitter>();
			obj2.horizontalFit = (FitMode)2;
			obj2.verticalFit = (FitMode)2;
			return new Row
			{
				Root = val,
				Label = NewLabel(val.transform)
			};
		}

		private static TMP_Text NewLabel(Transform parent)
		{
			GameObject val = Object.Instantiate<GameObject>(_labelTemplate, parent, false);
			((Object)val).name = "text";
			val.SetActive(true);
			ContentSizeFitter[] components = val.GetComponents<ContentSizeFitter>();
			for (int i = 0; i < components.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)components[i]);
			}
			TMP_Text component = val.GetComponent<TMP_Text>();
			component.textWrappingMode = (TextWrappingModes)0;
			return component;
		}

		private static bool SetText(TMP_Text label, string text)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			if (label.text == text)
			{
				return false;
			}
			label.text = text;
			Vector2 preferredValues = label.GetPreferredValues(text);
			label.rectTransform.sizeDelta = new Vector2(Mathf.Ceil(preferredValues.x), Mathf.Max(label.rectTransform.sizeDelta.y, preferredValues.y));
			return true;
		}

		private static bool Fill(Row row, Line line)
		{
			bool result = SetText(row.Label, line.Text);
			string text = (line.Combination ? "+" : "|") + string.Join("\u0001", line.Keys);
			if (text == row.Shape)
			{
				return result;
			}
			row.Shape = text;
			foreach (GameObject part in row.Parts)
			{
				part.SetActive(false);
				Object.Destroy((Object)(object)part);
			}
			row.Parts.Clear();
			for (int i = 0; i < line.Keys.Length; i++)
			{
				if (i > 0 && line.Combination)
				{
					TMP_Text val = NewLabel(row.Root.transform);
					val.text = "";
					SetText(val, "+");
					row.Parts.Add(((Component)val).gameObject);
				}
				GameObject val2 = Object.Instantiate<GameObject>(_keyTemplate, row.Root.transform, false);
				((Object)val2).name = "key";
				val2.SetActive(true);
				((Component)val2.transform.Find("Key")).GetComponent<TMP_Text>().text = line.Keys[i];
				row.Parts.Add(val2);
			}
			return true;
		}

		private static void Collect()
		{
			Lines.Clear();
			Player localPlayer = Player.m_localPlayer;
			if (!Settings.ShowKeyHints.Value || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || !((Character)localPlayer).InPlaceMode() || Hud.IsPieceSelectionVisible() || !Keys.GameHasInput(localPlayer))
			{
				return;
			}
			Piece val = PlayerAccess.SelectedPiece(localPlayer);
			if ((Object)(object)val != (Object)null && PlantGrid.IsPlantPiece(val))
			{
				if (Settings.PlantingEnabled.Value)
				{
					PlantLines();
				}
			}
			else if (Settings.PrecisionEnabled.Value && PrecisionBuild.HoldsHammer(localPlayer))
			{
				PrecisionLines();
			}
			if (CreativeMode.Active)
			{
				Add("$lb_camera_toggle", Settings.CameraKey);
			}
		}

		private static void PlantLines()
		{
			int num = Mathf.Max(1, PlantGrid.PlannedCount);
			Either("$lb_rows: " + Settings.Rows.Value, Settings.MoreRowsKey, Settings.FewerRowsKey);
			Either("$lb_columns: " + Settings.Columns.Value + "  (" + num + " $lb_plants)", Settings.MoreColumnsKey, Settings.FewerColumnsKey);
			Add("$lb_plant_snap: " + Texts.OnOff(Settings.SnapToPlants.Value), Settings.GridKey);
			if (Settings.BulkHarvest.Value)
			{
				List<string> list = new List<string>(Parts(Settings.BulkHarvestModifier)) { Texts.T("$KEY_Use") };
				Lines.Add(new Line
				{
					Text = Texts.T("$lb_bulk_harvest"),
					Keys = list.ToArray(),
					Combination = true
				});
			}
			if (!string.IsNullOrEmpty(PlantGrid.MainReason))
			{
				Lines.Add(new Line
				{
					Text = "<color=#ff7a6a>" + Texts.T(PlantGrid.MainReason) + "</color>",
					Keys = new string[0]
				});
			}
		}

		private static void PrecisionLines()
		{
			bool value = Settings.GridActive.Value;
			Add("$lb_grid: " + Texts.OnOff(value), Settings.GridKey);
			if (value)
			{
				Add("$lb_grid_size: " + PrecisionBuild.Metres(Settings.GridSize.Value), Settings.GridSizeKey);
				Add("$lb_rotation_step: " + PrecisionBuild.Degrees(Settings.RotationStep.Value), Settings.RotationKey);
				Add("$lb_snap_target: " + Texts.T(Settings.SnapToCellCenters.Value ? "$lb_snap_centres" : "$lb_snap_corners"), Settings.SnapTargetKey);
			}
		}

		private static void Add(string text, ConfigEntry<KeyboardShortcut> entry)
		{
			Lines.Add(new Line
			{
				Text = Texts.T(text),
				Keys = Parts(entry),
				Combination = true
			});
		}

		private static void Either(string text, ConfigEntry<KeyboardShortcut> first, ConfigEntry<KeyboardShortcut> second)
		{
			List<string> list = new List<string>();
			list.Add(string.Join(" + ", Parts(first)));
			list.Add(string.Join(" + ", Parts(second)));
			Lines.Add(new Line
			{
				Text = Texts.T(text),
				Keys = list.ToArray(),
				Combination = false
			});
		}

		private static string[] Parts(ConfigEntry<KeyboardShortcut> entry)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = entry.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
			{
				return new string[1] { "-" };
			}
			List<string> list = new List<string>();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				list.Add(KeyName(modifier));
			}
			list.Add(KeyName(((KeyboardShortcut)(ref value)).MainKey));
			return list.ToArray();
		}

		private unsafe static string KeyName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected I4, but got Unknown
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected I4, but got Unknown
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_005a: 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_0072: Expected I4, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Invalid comparison between Unknown and I4
			//IL_0134: 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_0124: Invalid comparison between Unknown and I4
			if ((int)key <= 32)
			{
				if ((int)key == 13)
				{
					return Texts.T("$button_return");
				}
				if ((int)key == 32)
				{
					return Texts.T("$button_space");
				}
			}
			else
			{
				switch (key - 273)
				{
				case 0:
					return Texts.T("$lb_key_up");
				case 1:
					return Texts.T("$lb_key_down");
				case 3:
					return Texts.T("$lb_key_left");
				case 2:
					return Texts.T("$lb_key_right");
				}
				switch (key - 303)
				{
				case 1:
					return Texts.T("$button_lshift");
				case 0:
					return Texts.T("$button_rshift");
				case 5:
					return Texts.T("$button_lalt");
				case 4:
					return Texts.T("$button_ralt");
				case 3:
					return Texts.T("$button_lctrl");
				case 2:
					return Texts.T("$button_rctrl");
				}
				switch (key - 323)
				{
				case 0:
					return Texts.T("$button_mouse0");
				case 1:
					return Texts.T("$button_mouse1");
				case 2:
					return Texts.T("$button_mouse2");
				}
			}
			if ((int)key >= 97 && (int)key <= 122)
			{
				return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			}
			return ZInput.KeyCodeToDisplayName(key);
		}
	}
	internal static class Keys
	{
		private static readonly MethodInfo PlayerTakesInput = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null);

		public static bool Down(ConfigEntry<KeyboardShortcut> entry)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = entry.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return false;
			}
			return ModifiersHeld(value);
		}

		public static bool Held(ConfigEntry<KeyboardShortcut> entry)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = entry.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKey(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return false;
			}
			return ModifiersHeld(value);
		}

		private static bool ModifiersHeld(KeyboardShortcut shortcut)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return false;
				}
			}
			return true;
		}

		public static bool GameHasInput(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!(PlayerTakesInput == null))
			{
				return (bool)PlayerTakesInput.Invoke(player, null);
			}
			return true;
		}
	}
	internal static class Log
	{
		private static ManualLogSource _source;

		public static void Init(ManualLogSource source)
		{
			_source = source;
		}

		public static void Info(string message)
		{
			ManualLogSource source = _source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Warning(string message)
		{
			ManualLogSource source = _source;
			if (source != null)
			{
				source.LogWarning((object)message);
			}
		}
	}
	[HarmonyPatch]
	internal static class GrowthInfo
	{
		private static readonly MethodInfo SincePlanted = AccessTools.Method(typeof(Plant), "TimeSincePlanted", (Type[])null, (Type[])null);

		private static readonly MethodInfo GrowTime = AccessTools.Method(typeof(Plant), "GetGrowTime", (Type[])null, (Type[])null);

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

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

		[HarmonyPatch(typeof(Plant), "GetHoverText")]
		[HarmonyPostfix]
		private static void PlantText(Plant __instance, ref string __result)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!Settings.ShowGrowthInfo.Value || string.IsNullOrEmpty(__result) || (int)__instance.GetStatus() != 0 || SincePlanted == null || GrowTime == null)
			{
				return;
			}
			ZNetView val = PlantView.Invoke(__instance);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				double num = (double)SincePlanted.Invoke(__instance, null);
				float num2 = (float)GrowTime.Invoke(__instance, null);
				if (!(num2 <= 0f))
				{
					double num3 = (double)num2 - num;
					int num4 = Mathf.Clamp((int)(num / (double)num2 * 100.0), 0, 100);
					string text = ((num3 > 0.0) ? (num4 + " % " + Texts.T("$lb_grown") + ", " + Texts.T("$lb_ready_in") + " " + Duration(num3)) : ("100 % " + Texts.T("$lb_grown") + ", " + Texts.T("$lb_ready")));
					__result = __result + "\n<color=#c8c8c8>" + text + "</color>";
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "GetHoverText")]
		[HarmonyPostfix]
		private static void PickableText(Pickable __instance, ref string __result)
		{
			if (!Settings.ShowGrowthInfo.Value || !__instance.GetPicked() || __instance.m_respawnTimeMinutes <= 0f)
			{
				return;
			}
			ZNetView val = PickableView.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return;
			}
			long num = val.GetZDO().GetLong(ZDOVars.s_pickedTime, 0L);
			if (num > 1)
			{
				TimeSpan timeSpan = ZNet.instance.GetTime() - new DateTime(num);
				double num2 = (double)__instance.m_respawnTimeMinutes * 60.0 - timeSpan.TotalSeconds;
				if (!(num2 <= 0.0))
				{
					string text = Localization.instance.Localize(__instance.GetHoverName());
					__result = text + "\n<color=#c8c8c8>" + Texts.T("$lb_grows_back_in") + " " + Duration(num2) + "</color>";
				}
			}
		}

		private static string Duration(double seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(Math.Max(0.0, seconds));
			if (timeSpan.TotalHours >= 1.0)
			{
				return (int)timeSpan.TotalHours + " h " + timeSpan.Minutes.ToString("00") + " min";
			}
			if (timeSpan.TotalMinutes >= 1.0)
			{
				return (int)timeSpan.TotalMinutes + " min";
			}
			return timeSpan.Seconds + " s";
		}
	}
	[HarmonyPatch]
	internal static class Harvest
	{
		private static readonly MethodInfo HoneyLevel = AccessTools.Method(typeof(Beehive), "GetHoneyLevel", (Type[])null, (Type[])null);

		private static readonly Dictionary<string, Piece> SeedFor = new Dictionary<string, Piece>();

		private static ObjectDB _mappedFrom;

		private static bool _bulk;

		public static void Tick(Player player)
		{
			if ((Object)(object)player != (Object)null && Keys.GameHasInput(player) && Keys.Down(Settings.ReplantKey))
			{
				Settings.ReplantOnHarvest.Value = !Settings.ReplantOnHarvest.Value;
				((Character)player).Message((MessageType)1, "$lb_replant: " + Texts.OnOff(Settings.ReplantOnHarvest.Value), 0, (Sprite)null, false);
			}
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		[HarmonyPrefix]
		private static void BeforePick(Pickable __instance, out bool __state)
		{
			__state = Ripe(__instance);
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		[HarmonyPostfix]
		private static void AfterPick(Pickable __instance, Humanoid character, bool repeat, bool __state)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!__state)
			{
				return;
			}
			Player val = (Player)(object)((character is Player) ? character : null);
			if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
			{
				if (Settings.ReplantOnHarvest.Value)
				{
					Replant(val, __instance);
				}
				if (!repeat && !_bulk)
				{
					Bulk(val, ((Component)__instance).transform.position, Utils.GetPrefabName(((Component)__instance).gameObject));
				}
			}
		}

		[HarmonyPatch(typeof(Beehive), "Interact")]
		[HarmonyPrefix]
		private static void BeforeHive(Beehive __instance, out bool __state)
		{
			__state = Honey(__instance) > 0;
		}

		[HarmonyPatch(typeof(Beehive), "Interact")]
		[HarmonyPostfix]
		private static void AfterHive(Beehive __instance, Humanoid character, bool repeat, bool __state)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (__state && !repeat && !_bulk)
			{
				Player val = (Player)(object)((character is Player) ? character : null);
				if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
				{
					Bulk(val, ((Component)__instance).transform.position, Utils.GetPrefabName(((Component)__instance).gameObject));
				}
			}
		}

		private static bool Ripe(Pickable pickable)
		{
			if ((Object)(object)pickable != (Object)null && !pickable.GetPicked())
			{
				return pickable.GetEnabled == 1;
			}
			return false;
		}

		private static int Honey(Beehive hive)
		{
			if (!(HoneyLevel != null))
			{
				return 0;
			}
			return (int)HoneyLevel.Invoke(hive, null);
		}

		private static void Bulk(Player player, Vector3 centre, string kind)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!Settings.BulkHarvest.Value || !Keys.Held(Settings.BulkHarvestModifier))
			{
				return;
			}
			bool value = Settings.HarvestSameKindOnly.Value;
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			_bulk = true;
			try
			{
				Collider[] array = Physics.OverlapSphere(centre, Settings.HarvestRadius.Value, -1, (QueryTriggerInteraction)2);
				foreach (Collider val in array)
				{
					Pickable componentInParent = ((Component)val).GetComponentInParent<Pickable>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						if (hashSet.Add(((Object)((Component)componentInParent).gameObject).GetInstanceID()) && Ripe(componentInParent) && Harvestable(componentInParent) && (!value || Utils.GetPrefabName(((Component)componentInParent).gameObject) == kind))
						{
							componentInParent.Interact((Humanoid)(object)player, false, false);
							num++;
						}
						continue;
					}
					Beehive componentInParent2 = ((Component)val).GetComponentInParent<Beehive>();
					if ((Object)(object)componentInParent2 != (Object)null && hashSet.Add(((Object)((Component)componentInParent2).gameObject).GetInstanceID()) && Honey(componentInParent2) > 0 && (!value || Utils.GetPrefabName(((Component)componentInParent2).gameObject) == kind))
					{
						componentInParent2.Interact((Humanoid)(object)player, false, false);
						num++;
					}
				}
			}
			finally
			{
				_bulk = false;
			}
			if (num > 0)
			{
				Log.Info("Bulk harvest picked " + num + " more.");
			}
		}

		private static bool Harvestable(Pickable pickable)
		{
			if (!IsGrowing(pickable))
			{
				return pickable.m_harvestable;
			}
			return true;
		}

		public static bool IsGrowing(Pickable pickable)
		{
			string prefabName = Utils.GetPrefabName(((Component)pickable).gameObject);
			if (!SeedMap().ContainsKey(prefabName))
			{
				return Plantables.IsWildPlant(prefabName);
			}
			return true;
		}

		private static void Replant(Player player, Pickable pickable)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (!SeedMap().TryGetValue(Utils.GetPrefabName(((Component)pickable).gameObject), out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)pickable).transform.position;
			if (Location.IsInsideNoBuildLocation(position) || !PrivateArea.CheckAccess(position, 0f, false, false))
			{
				return;
			}
			bool flag = player.NoCostCheat();
			if (flag || player.HaveRequirements(value, (RequirementMode)0))
			{
				bool flag2 = (((Humanoid)player).GetInventory().ItemCheated(value.m_resources, -1, true) || flag) && !PlayerProfile.s_bypassCheatChecks;
				if (!flag && !ZoneSystem.instance.GetGlobalKey(value.FreeBuildKey()))
				{
					player.ConsumeResources(value.m_resources, 0, -1, 1);
				}
				Quaternion val = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
				player.PlacePiece(value, position, val, false, flag2);
			}
		}

		private static Dictionary<string, Piece> SeedMap()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)_mappedFrom)
			{
				return SeedFor;
			}
			SeedFor.Clear();
			_mappedFrom = instance;
			GameObject itemPrefab = instance.GetItemPrefab("Cultivator");
			PieceTable val = ((!((Object)(object)itemPrefab != (Object)null)) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces);
			if ((Object)(object)val == (Object)null)
			{
				Log.Warning("Cultivator piece table not found; replanting is unavailable.");
				return SeedFor;
			}
			foreach (GameObject piece in val.m_pieces)
			{
				Plant val2 = (((Object)(object)piece != (Object)null) ? piece.GetComponent<Plant>() : null);
				Piece val3 = (((Object)(object)piece != (Object)null) ? piece.GetComponent<Piece>() : null);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
				{
					continue;
				}
				GameObject[] grownPrefabs = val2.m_grownPrefabs;
				foreach (GameObject val4 in grownPrefabs)
				{
					if ((Object)(object)val4 != (Object)null && (Object)(object)val4.GetComponent<Pickable>() != (Object)null && !SeedFor.ContainsKey(((Object)val4).name))
					{
						SeedFor[((Object)val4).name] = val3;
					}
				}
			}
			return SeedFor;
		}
	}
	[HarmonyPatch]
	internal static class Plantables
	{
		private enum Kind
		{
			Bush,
			Mushroom,
			Flower
		}

		private sealed class SaplingDef
		{
			public string Name;

			public string Token;

			public Biome Home;

			public string[] Grows;

			public (string item, int amount)[] Cost;

			public bool TolerateHeat;
		}

		private static readonly Dictionary<string, Kind> Wild = new Dictionary<string, Kind>
		{
			{
				"RaspberryBush",
				Kind.Bush
			},
			{
				"BlueberryBush",
				Kind.Bush
			},
			{
				"CloudberryBush",
				Kind.Bush
			},
			{
				"LingonberryBush",
				Kind.Bush
			},
			{
				"Pickable_Mushroom",
				Kind.Mushroom
			},
			{
				"Pickable_Mushroom_yellow",
				Kind.Mushroom
			},
			{
				"Pickable_Mushroom_blue",
				Kind.Mushroom
			},
			{
				"Pickable_Thistle",
				Kind.Flower
			},
			{
				"Pickable_Dandelion",
				Kind.Flower
			},
			{
				"Pickable_SmokePuff",
				Kind.Flower
			},
			{
				"Pickable_Fiddlehead",
				Kind.Flower
			}
		};

		private const Biome Temperate = (Biome)25;

		private static readonly SaplingDef[] Saplings = new SaplingDef[4]
		{
			new SaplingDef
			{
				Name = "LetsBuild_Sapling_Ancient",
				Token = "lb_sapling_ancient",
				Home = (Biome)2,
				Grows = new string[1] { "SwampTree1" },
				Cost = new(string, int)[1] { ("AncientSeed", 1) }
			},
			new SaplingDef
			{
				Name = "LetsBuild_Sapling_Ygga",
				Token = "lb_sapling_ygga",
				Home = (Biome)512,
				Grows = new string[3] { "YggaShoot1", "YggaShoot2", "YggaShoot3" },
				Cost = new(string, int)[1] { ("Sap", 1) }
			},
			new SaplingDef
			{
				Name = "LetsBuild_Sapling_AutumnBirch",
				Token = "lb_sapling_autumnbirch",
				Home = (Biome)0,
				Grows = new string[2] { "Birch1_aut", "Birch2_aut" },
				Cost = new(string, int)[1] { ("BirchSeeds", 1) }
			},
			new SaplingDef
			{
				Name = "LetsBuild_Sapling_Ashwood",
				Token = "lb_sapling_ashwood",
				Home = (Biome)32,
				Grows = new string[4] { "AshlandsTree3", "AshlandsTree4", "AshlandsTree5", "AshlandsTree6_big" },
				Cost = new(string, int)[2]
				{
					("BeechSeeds", 1),
					("SulfurStone", 1)
				},
				TolerateHeat = true
			}
		};

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

		private static readonly List<Piece> OurSaplings = new List<Piece>();

		private static readonly Dictionary<string, bool> CropCache = new Dictionary<string, bool>();

		private static readonly Dictionary<Piece, bool> CultivatedOnly = new Dictionary<Piece, bool>();

		public static bool IsWildPlant(string prefabName)
		{
			return Wild.ContainsKey(prefabName);
		}

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += CreateSaplings;
			PieceManager.OnPiecesRegistered += ApplyWildPlants;
			Settings.File.SettingChanged += delegate(object _, SettingChangedEventArgs e)
			{
				if (Settings.IsServerRule(e.ChangedSetting))
				{
					ApplyAll();
				}
			};
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				ApplyAll();
			};
		}

		private static void ApplyAll()
		{
			ApplyWildPlants();
			ApplySaplings();
		}

		private static void ApplyWildPlants()
		{
			//IL_0192: 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_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Expected O, but got Unknown
			PieceTable val = CultivatorTable();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Piece val2 = PieceOf("sapling_carrot");
			foreach (KeyValuePair<string, Kind> item in Wild)
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(item.Key);
				Pickable val3 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Pickable>() : null);
				ItemDrop val4 = (((Object)(object)val3 != (Object)null && (Object)(object)val3.m_itemPrefab != (Object)null) ? val3.m_itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val4 == (Object)null)
				{
					Log.Warning("Cannot make " + item.Key + " plantable; the game has no such pickable.");
					continue;
				}
				Piece val5 = prefab.GetComponent<Piece>();
				bool flag = (Object)(object)val5 != (Object)null;
				if ((Object)(object)val5 == (Object)null)
				{
					val5 = prefab.AddComponent<Piece>();
				}
				if (OurWildPieces.Add(item.Key))
				{
					Log.Info("Plantable: " + item.Key + (flag ? " (had a piece already)" : "") + ", grows back after " + val3.m_respawnTimeMinutes + " min.");
				}
				string name = val4.m_itemData.m_shared.m_name;
				val5.m_name = ((item.Value == Kind.Bush) ? (name + " ($lb_bush)") : name);
				val5.m_description = "$lb_wild_plant_desc";
				val5.m_icon = val4.m_itemData.GetIcon();
				val5.m_category = (PieceCategory)0;
				val5.m_groundOnly = true;
				val5.m_clipEverything = true;
				val5.m_randomInitBuildRotation = true;
				val5.m_canBeRemoved = true;
				if ((Object)(object)val2 != (Object)null)
				{
					val5.m_placeEffect = val2.m_placeEffect;
				}
				val5.m_resources = (Requirement[])(object)new Requirement[1]
				{
					new Requirement
					{
						m_resItem = val4,
						m_amount = Cost(item.Value),
						m_recover = false
					}
				};
				bool flag2 = val.m_pieces.Contains(prefab);
				if (Settings.PlantWildPlants.Value && !flag2)
				{
					val.m_pieces.Add(prefab);
				}
				else if (!Settings.PlantWildPlants.Value && flag2)
				{
					val.m_pieces.Remove(prefab);
				}
			}
		}

		private static int Cost(Kind kind)
		{
			return kind switch
			{
				Kind.Bush => Settings.BushCost.Value, 
				Kind.Mushroom => Settings.MushroomCost.Value, 
				_ => Settings.FlowerCost.Value, 
			};
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		[HarmonyPostfix]
		private static void OnlyPlanted(Piece piece, ref bool __result)
		{
			if (__result && (Object)(object)piece != (Object)null && OurWildPieces.Contains(Utils.GetPrefabName(((Component)piece).gameObject)) && !piece.IsPlacedByPlayer())
			{
				__result = false;
			}
		}

		private static void CreateSaplings()
		{
			//IL_0153: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Expected O, but got Unknown
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= CreateSaplings;
			SaplingDef[] saplings = Saplings;
			foreach (SaplingDef saplingDef in saplings)
			{
				List<GameObject> list = new List<GameObject>();
				string[] grows = saplingDef.Grows;
				foreach (string text in grows)
				{
					GameObject prefab = PrefabManager.Instance.GetPrefab(text);
					if ((Object)(object)prefab != (Object)null)
					{
						list.Add(prefab);
					}
					else
					{
						Log.Warning(saplingDef.Name + ": the game has no " + text + ".");
					}
				}
				ItemDrop val = ItemOf(saplingDef.Cost[0].item);
				if (list.Count == 0 || (Object)(object)val == (Object)null)
				{
					Log.Warning(saplingDef.Name + " not created; its tree or seed is missing.");
					continue;
				}
				GameObject val2 = PrefabManager.Instance.CreateClonedPrefab(saplingDef.Name, "Beech_Sapling");
				Plant val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Plant>() : null);
				if ((Object)(object)val3 == (Object)null)
				{
					Log.Warning(saplingDef.Name + " not created; the beech sapling could not be copied.");
					continue;
				}
				val3.m_name = "$" + saplingDef.Token;
				val3.m_grownPrefabs = list.ToArray();
				val3.m_biome = (Biome)(saplingDef.Home | 0x19);
				val3.m_tolerateHeat = saplingDef.TolerateHeat;
				List<RequirementConfig> list2 = new List<RequirementConfig>();
				(string, int)[] cost = saplingDef.Cost;
				for (int j = 0; j < cost.Length; j++)
				{
					var (item, amount) = cost[j];
					list2.Add(new RequirementConfig
					{
						Item = item,
						Amount = amount,
						Recover = true
					});
				}
				CustomPiece val4 = new CustomPiece(val2, false, new PieceConfig
				{
					Name = "$" + saplingDef.Token,
					Description = "$" + saplingDef.Token + "_desc",
					PieceTable = PieceTables.Cultivator,
					Category = PieceCategories.Misc,
					Icon = val.m_itemData.GetIcon(),
					Requirements = list2.ToArray()
				});
				if (PieceManager.Instance.AddPiece(val4))
				{
					OurSaplings.Add(val4.Piece);
				}
			}
			ApplySaplings();
			Log.Info(OurSaplings.Count + " new saplings registered.");
		}

		private static void ApplySaplings()
		{
			foreach (Piece ourSapling in OurSaplings)
			{
				if ((Object)(object)ourSapling != (Object)null)
				{
					ourSapling.m_enabled = Settings.ExtraSaplings.Value;
				}
			}
		}

		public static Biome Biome(Plant plant)
		{
			//IL_003c: 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)
			bool flag = IsCrop(plant);
			if ((flag && Settings.CropsAnyBiome.Value) || (!flag && Settings.SaplingsAnyBiome.Value))
			{
				return (Biome)895;
			}
			return Original(plant)?.m_biome ?? plant.m_biome;
		}

		public static bool NeedsCultivation(Plant plant)
		{
			if (Settings.NeedCultivatedGround.Value)
			{
				return Original(plant)?.m_needCultivatedGround ?? plant.m_needCultivatedGround;
			}
			return false;
		}

		private static Plant Original(Plant plant)
		{
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(Utils.GetPrefabName(((Component)plant).gameObject)) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<Plant>();
		}

		private static bool IsCrop(Plant plant)
		{
			string prefabName = Utils.GetPrefabName(((Component)plant).gameObject);
			if (!CropCache.TryGetValue(prefabName, out var value))
			{
				value = plant.m_grownPrefabs != null && plant.m_grownPrefabs.Length != 0 && (Object)(object)plant.m_grownPrefabs[0] != (Object)null && (Object)(object)plant.m_grownPrefabs[0].GetComponent<Pickable>() != (Object)null;
				CropCache[prefabName] = value;
			}
			return value;
		}

		[HarmonyPatch(typeof(Plant), "UpdateHealth")]
		[HarmonyPrefix]
		private static void Rules(Plant __instance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			__instance.m_biome = Biome(__instance);
			__instance.m_needCultivatedGround = NeedsCultivation(__instance);
		}

		[HarmonyPatch(typeof(Plant), "HaveRoof")]
		[HarmonyPrefix]
		private static bool Roof(ref bool __result)
		{
			if (Settings.NeedOpenSky.Value)
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(Plant), "HaveGrowSpace")]
		[HarmonyPrefix]
		private static bool Space(ref bool __result)
		{
			if (Settings.NeedGrowSpace.Value)
			{
				return true;
			}
			__result = true;
			return false;
		}

		[HarmonyPatch(typeof(Plant), "GetGrowTime")]
		[HarmonyPostfix]
		private static void GrowTime(Plant __instance, ref float __result)
		{
			__result *= (IsCrop(__instance) ? Settings.CropGrowTime.Value : Settings.SaplingGrowTime.Value);
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		[HarmonyPrefix]
		private static void GroundRule(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Piece val = PlayerAccess.SelectedPiece(__instance);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponent<Plant>() == (Object)null))
			{
				if (!CultivatedOnly.TryGetValue(val, out var value))
				{
					value = val.m_cultivatedGroundOnly;
					CultivatedOnly[val] = value;
				}
				bool cultivatedGroundOnly = (val.m_cultivatedGroundOnly = value && Settings.NeedCultivatedGround.Value);
				GameObject val2 = PlayerAccess.Ghost.Invoke(__instance);
				Piece val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Piece>() : null);
				if ((Object)(object)val3 != (Object)null)
				{
					val3.m_cultivatedGroundOnly = cultivatedGroundOnly;
				}
			}
		}

		private static PieceTable CultivatorTable()
		{
			ItemDrop val = ItemOf("Cultivator");
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.m_itemData.m_shared.m_buildPieces;
		}

		private static ItemDrop ItemOf(string name)
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(name) : null);
			if ((Object)(object)val == (Object)null)
			{
				val = PrefabManager.Instance.GetPrefab(name);
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<ItemDrop>();
		}

		private static Piece PieceOf(string name)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(name);
			if (!((Object)(object)prefab != (Object)null))
			{
				return null;
			}
			return prefab.GetComponent<Piece>();
		}
	}
	[HarmonyPatch]
	internal static class PlantGrid
	{
		private struct Extra
		{
			public GameObject Ghost;

			public float Yaw;

			public Vector3 Position;

			public Quaternion Rotation;

			public bool Valid;
		}

		private struct Job
		{
			public Piece Piece;

			public Vector3 Position;

			public Quaternion Rotation;
		}

		private static readonly List<Extra> Extras = new List<Extra>();

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

		private static int _sourceId;

		private static int _sourceFrame;

		private static int _placeMask;

		private static float _gridAngle;

		private static bool _angleSet;

		private static int _lastCounter;

		private static float _lastStep;

		private static bool _counterReset = true;

		public static int PlannedCount { get; private set; }

		public static string MainReason { get; private set; } = "";

		public static bool IsPlantPiece(Piece piece)
		{
			if ((Object)(object)piece != (Object)null)
			{
				if (!((Object)(object)((Component)piece).GetComponent<Plant>() != (Object)null))
				{
					return (Object)(object)((Component)piece).GetComponent<Pickable>() != (Object)null;
				}
				return true;
			}
			return false;
		}

		private static bool Active(Player player)
		{
			if (Settings.PlantingEnabled.Value && (Object)(object)player != (Object)null && ((Character)player).InPlaceMode())
			{
				return IsPlantPiece(PlayerAccess.SelectedPiece(player));
			}
			return false;
		}

		public static void Tick(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				Jobs.Clear();
				return;
			}
			if (Active(player) && Keys.GameHasInput(player) && !Hud.IsPieceSelectionVisible())
			{
				ReadKeys(player);
			}
			PlaceQueued(player);
		}

		private static void ReadKeys(Player player)
		{
			if (Keys.Down(Settings.MoreRowsKey))
			{
				Resize(player, Settings.Rows, 1);
			}
			if (Keys.Down(Settings.FewerRowsKey))
			{
				Resize(player, Settings.Rows, -1);
			}
			if (Keys.Down(Settings.MoreColumnsKey))
			{
				Resize(player, Settings.Columns, 1);
			}
			if (Keys.Down(Settings.FewerColumnsKey))
			{
				Resize(player, Settings.Columns, -1);
			}
			if (Keys.Down(Settings.GridKey))
			{
				Settings.SnapToPlants.Value = !Settings.SnapToPlants.Value;
				((Character)player).Message((MessageType)1, "$lb_plant_snap: " + Texts.OnOff(Settings.SnapToPlants.Value), 0, (Sprite)null, false);
			}
		}

		private static void Resize(Player player, ConfigEntry<int> entry, int delta)
		{
			int value = Settings.MaxPlantsPerClick.Value;
			int num = ((entry == Settings.Rows) ? Settings.Columns.Value : Settings.Rows.Value);
			int num2 = Mathf.Clamp(entry.Value + delta, 1, 50);
			if (num2 * num > value)
			{
				num2 = Mathf.Max(1, value / Mathf.Max(1, num));
			}
			entry.Value = num2;
			((Character)player).Message((MessageType)1, "$lb_rows " + Settings.Rows.Value + "  ×  $lb_columns " + Settings.Columns.Value, 0, (Sprite)null, false);
		}

		private static void PlaceQueued(Player player)
		{
			int value = Settings.PlantsPerFrame.Value;
			while (value-- > 0 && Jobs.Count > 0)
			{
				Job job = Jobs.Peek();
				if (!PlaceOne(player, job))
				{
					Jobs.Clear();
					break;
				}
				Jobs.Dequeue();
			}
		}

		private static bool PlaceOne(Player player, Job job)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			if (((Character)player).IsDead() || !((Character)player).InPlaceMode() || (Object)(object)job.Piece == (Object)null)
			{
				return false;
			}
			if (Location.IsInsideNoBuildLocation(job.Position) || !PrivateArea.CheckAccess(job.Position, 0f, false, false))
			{
				return true;
			}
			bool flag = player.NoCostCheat();
			if (!flag && !player.HaveRequirements(job.Piece, (RequirementMode)0))
			{
				((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false);
				return false;
			}
			ItemData rightItem = PlayerAccess.GetRightItem(player);
			if (rightItem == null)
			{
				return false;
			}
			float buildStamina = PlayerAccess.GetBuildStamina(player);
			if (Settings.PlantingUsesStamina.Value && !((Character)player).HaveStamina(buildStamina))
			{
				Hud.instance.StaminaBarEmptyFlash();
				((Character)player).Message((MessageType)1, "$lb_planting_stopped", 0, (Sprite)null, false);
				return false;
			}
			if (Settings.PlantingUsesDurability.Value && rightItem.m_shared.m_useDurability && rightItem.m_durability <= 0f)
			{
				((Character)player).Message((MessageType)1, "$lb_planting_stopped", 0, (Sprite)null, false);
				return false;
			}
			bool flag2 = (((Humanoid)player).GetInventory().ItemCheated(job.Piece.m_resources, -1, true) || flag) && !PlayerProfile.s_bypassCheatChecks;
			if (!flag && !ZoneSystem.instance.GetGlobalKey(job.Piece.FreeBuildKey()))
			{
				player.ConsumeResources(job.Piece.m_resources, 0, -1, 1);
			}
			player.PlacePiece(job.Piece, job.Position, job.Rotation, false, flag2);
			if (Settings.PlantingUsesStamina.Value)
			{
				((Character)player).UseStamina(buildStamina);
			}
			if (Settings.PlantingUsesDurability.Value && rightItem.m_shared.m_useDurability)
			{
				rightItem.m_durability = Mathf.Max(0f, rightItem.m_durability - PlayerAccess.GetPlaceDurability(player, rightItem) * Game.m_durabilityRate);
			}
			PieceTable val = PlayerAccess.BuildPieces.Invoke(player);
			if ((Object)(object)val != (Object)null && (int)val.m_skill != 0)
			{
				((Character)player).RaiseSkill(val.m_skill, 1f);
			}
			return true;
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		[HarmonyPostfix]
		private static void AfterGhost(Player __instance)
		{
			//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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			_placeMask = PlayerAccess.PlaceRayMask.Invoke(__instance);
			GameObject val = PlayerAccess.Ghost.Invoke(__instance);
			Piece val2 = PlayerAccess.SelectedPiece(__instance);
			if (!Active(__instance) || (Object)(object)val == (Object)null || !val.activeSelf || (int)PlayerAccess.Status.Invoke(__instance) == 12)
			{
				HideExtras();
				PlannedCount = 0;
				MainReason = "";
				return;
			}
			TrackTurn(__instance);
			float spacing = PlantRules.Spacing(((Component)val2).gameObject);
			float lift = GhostLift(val);
			Directions(val, out var forward, out var right);
			bool moved = false;
			if (Settings.SnapToPlants.Value && !AltHeld() && TrySnap(val, spacing, lift, out var forward2, out var right2, out var step))
			{
				moved = true;
				forward = forward2;
				right = right2;
				spacing = step;
			}
			RecheckMain(__instance, val, val2, moved);
			LayOut(__instance, val, val2, spacing, lift, forward, right);
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		[HarmonyPostfix]
		private static void Placed(Player __instance, Piece piece, bool __result)
		{
			//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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Active(__instance))
			{
				return;
			}
			foreach (Extra extra in Extras)
			{
				if ((Object)(object)extra.Ghost != (Object)null && extra.Ghost.activeSelf && extra.Valid)
				{
					Jobs.Enqueue(new Job
					{
						Piece = piece,
						Position = extra.Position,
						Rotation = extra.Rotation
					});
				}
			}
		}

		private static bool TrySnap(GameObject ghost, float spacing, float lift, out Vector3 forward, out Vector3 right, out float step)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: 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_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: 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_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			Directions(ghost, out forward, out right);
			step = spacing;
			Vector3 position = ghost.transform.position;
			List<Transform> list = PlantsAround(position, spacing * 2.5f + 1f);
			if (list.Count == 0)
			{
				return false;
			}
			Transform val = null;
			float num = float.MaxValue;
			foreach (Transform item in list)
			{
				float num2 = FlatDistance(item.position, position);
				if (num2 < num)
				{
					num = num2;
					val = item;
				}
			}
			step = Mathf.Max(spacing, PlantRules.Spacing(((Component)val).gameObject));
			if (num > step * 2f)
			{
				return false;
			}
			foreach (Transform item2 in PlantsAround(val.position, step * 1.3f))
			{
				if (!((Object)(object)item2 == (Object)(object)val) && Mathf.Abs(FlatDistance(item2.position, val.position) - step) <= step * 0.25f)
				{
					Vector3 val2 = item2.position - val.position;
					val2.y = 0f;
					forward = ((Vector3)(ref val2)).normalized;
					right = Vector3.Cross(Vector3.up, forward);
					break;
				}
			}
			FaceGhost(ghost, ref forward, ref right);
			Vector3 val3 = position - val.position;
			val3.y = 0f;
			int num3 = Mathf.RoundToInt(Vector3.Dot(val3, forward) / step);
			int num4 = Mathf.RoundToInt(Vector3.Dot(val3, right) / step);
			if (num3 == 0 && num4 == 0)
			{
				float num5 = Vector3.Dot(val3, forward);
				float num6 = Vector3.Dot(val3, right);
				if (Mathf.Abs(num5) >= Mathf.Abs(num6))
				{
					num3 = ((num5 >= 0f) ? 1 : (-1));
				}
				else
				{
					num4 = ((num6 >= 0f) ? 1 : (-1));
				}
			}
			Vector3 val4 = val.position + forward * ((float)num3 * step) + right * ((float)num4 * step);
			if (FlatDistance(val4, position) > step * 1.5f || !Ground(val4, out var ground, out var _))
			{
				return false;
			}
			ghost.transform.position = ground + Vector3.up * lift;
			return true;
		}

		private static List<Transform> PlantsAround(Vector3 centre, float radius)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			List<Transform> list = new List<Transform>();
			HashSet<int> hashSet = new HashSet<int>();
			int num = LayerMask.NameToLayer("ghost");
			Collider[] array = Physics.OverlapSphere(centre, radius, -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if (((Component)val).gameObject.layer == num)
				{
					continue;
				}
				Component componentInParent = (Component)(object)((Component)val).GetComponentInParent<Plant>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					componentInParent = (Component)(object)((Component)val).GetComponentInParent<Pickable>();
				}
				if ((Object)(object)componentInParent == (Object)null || !hashSet.Add(((Object)componentInParent.gameObject).GetInstanceID()))
				{
					continue;
				}
				Pickable val2 = (Pickable)(object)((componentInParent is Pickable) ? componentInParent : null);
				if (val2 == null || Harvest.IsGrowing(val2))
				{
					ZNetView component = componentInParent.GetComponent<ZNetView>();
					if (component != null && component.IsValid())
					{
						list.Add(componentInParent.transform);
					}
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(Player), "PlacePiece")]
		[HarmonyPostfix]
		private static void GameRandomised()
		{
			_counterReset = true;
		}

		[HarmonyPatch(typeof(Player), "SetupPlacementGhost")]
		[HarmonyPostfix]
		private static void GhostRebuilt()
		{
			_counterReset = true;
		}

		private static void TrackTurn(Player player)
		{
			if (!_angleSet && (Object)(object)GameCamera.instance != (Object)null)
			{
				_gridAngle = 0f;
				_angleSet = true;
			}
			int num = PlayerAccess.Rotation.Invoke(player);
			float num2 = PlayerAccess.RotationDegrees.Invoke(player);
			if (_counterReset || !Mathf.Approximately(num2, _lastStep))
			{
				_counterReset = false;
			}
			else if (num != _lastCounter)
			{
				_gridAngle += (float)(num - _lastCounter) * num2;
			}
			_lastCounter = num;
			_lastStep = num2;
		}

		private static Vector3 GridFacing()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return Quaternion.Euler(0f, _gridAngle, 0f) * Vector3.forward;
		}

		private static void FaceGhost(GameObject ghost, ref Vector3 forward, ref Vector3 right)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_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_0048: 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_0052: 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_0067: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = GridFacing();
			Vector3 val2 = forward;
			float num = float.MinValue;
			Vector3[] array = (Vector3[])(object)new Vector3[4]
			{
				forward,
				-forward,
				right,
				-right
			};
			foreach (Vector3 val3 in array)
			{
				float num2 = Vector3.Dot(val3, ((Vector3)(ref val)).normalized);
				if (num2 > num)
				{
					num = num2;
					val2 = val3;
				}
			}
			forward = val2;
			right = Vector3.Cross(Vector3.up, forward);
		}

		private static void Directions(GameObject ghost, out Vector3 forward, out Vector3 right)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_004d: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (Settings.AlignToWorld.Value)
			{
				forward = Vector3.forward;
				right = Vector3.Cross(Vector3.up, forward);
				FaceGhost(ghost, ref forward, ref right);
			}
			else
			{
				forward = GridFacing();
				right = Vector3.Cross(Vector3.up, forward);
			}
		}

		private static void RecheckMain(Player player, GameObject ghost, Piece piece, bool moved)
		{
			//IL_000c: 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_0018: 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_0028: Invalid comparison between Unknown and I4
			//IL_001c: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected I4, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Invalid comparison between Unknown and I4
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0083: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			PlacementStatus val = PlayerAccess.Status.Invoke(player);
			Vector3 position = ghost.transform.position;
			if (moved && IsPositional(val))
			{
				val = (PlacementStatus)0;
			}
			if ((int)val == 0 && moved)
			{
				Ground(position, out var _, out var heightmap);
				val = PlacementRules(piece, position, heightmap);
			}
			MainReason = "";
			if ((int)val == 0 && Settings.PreventInvalidPlanting.Value)
			{
				Status val2 = PlantRules.Check(((Component)piece).gameObject, position);
				if ((int)val2 != 0)
				{
					val = (PlacementStatus)1;
					MainReason = PlantRules.Reason(val2);
				}
				else if (PlantRules.Occupied(((Component)piece).gameObject, position))
				{
					val = (PlacementStatus)1;
					MainReason = PlantRules.Reason((Status)2);
				}
			}
			PlayerAccess.Status.Invoke(player) = (PlacementStatus)(int)val;
			Piece component = ghost.GetComponent<Piece>();
			if (component != null)
			{
				component.SetInvalidPlacementHeightlight((int)val > 0);
			}
		}

		private static bool IsPositional(PlacementStatus status)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if ((int)status != 9 && (int)status != 10 && (int)status != 3 && (int)status != 4)
			{
				return (int)status == 8;
			}
			return true;
		}

		private static PlacementStatus PlacementRules(Piece piece, Vector3 position, Heightmap heightmap)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0048: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: 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_006e: 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_007d: Invalid comparison between Unkno