Decompiled source of BuildCameraPlus v1.6.2

BuildCameraPlus.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.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 BuildCameraPlus
{
	[HarmonyPatch]
	internal static class AreaDestroy
	{
		private const float Touch = 0.1f;

		private static ConfigEntry<bool> enabled;

		private static ConfigEntry<bool> includeWorld;

		private static ConfigEntry<KeyCode> holdKey;

		private static ConfigEntry<int> maxPieces;

		private static int mask;

		private static readonly FieldRef<Player, Piece> Hovering = AccessTools.FieldRefAccess<Player, Piece>("m_hoveringPiece");

		internal static void Bind(ConfigFile c)
		{
			enabled = Cfg.Add(c, "07 Area Destroy", "Enabled", value: false, "Hold the key below and remove (middle mouse button) to remove a whole structure: the piece you aim at and everything connected to it.");
			holdKey = Cfg.Add<KeyCode>(c, "07 Area Destroy", "HoldKey", (KeyCode)91, "Keep this key held while you remove, so a whole structure is never removed by accident.");
			maxPieces = Cfg.Add(c, "07 Area Destroy", "MaxPieces", 300, "The most pieces one removal may take, a safety limit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 2000));
			includeWorld = Cfg.Add(c, "07 Area Destroy", "IncludeWorldStructures", value: true, "Also remove pieces of structures that were generated with the world (villages, ruins) even where the game normally does not let you.");
		}

		internal static bool Held()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.modEnabled.Value && enabled.Value)
			{
				return ZInput.GetKey(holdKey.Value, false);
			}
			return false;
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Structure(Player __instance, ref bool __result)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Held())
			{
				return true;
			}
			__result = Destroy(__instance);
			return false;
		}

		private static bool Destroy(Player p)
		{
			//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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			Piece val = Hovering.Invoke(p);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			WearNTear component = ((Component)val).GetComponent<WearNTear>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			if (mask == 0)
			{
				mask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vehicle" });
			}
			List<WearNTear> list = new List<WearNTear> { component };
			HashSet<WearNTear> hashSet = new HashSet<WearNTear> { component };
			for (int i = 0; i < list.Count; i++)
			{
				if (list.Count >= maxPieces.Value)
				{
					break;
				}
				Collider[] componentsInChildren = ((Component)list[i]).GetComponentsInChildren<Collider>();
				foreach (Collider val2 in componentsInChildren)
				{
					if (val2.isTrigger)
					{
						continue;
					}
					Bounds bounds = val2.bounds;
					Collider[] array = Physics.OverlapBox(((Bounds)(ref bounds)).center, ((Bounds)(ref bounds)).extents + Vector3.one * 0.1f, Quaternion.identity, mask);
					for (int k = 0; k < array.Length; k++)
					{
						WearNTear componentInParent = ((Component)array[k]).GetComponentInParent<WearNTear>();
						if ((Object)(object)componentInParent != (Object)null && hashSet.Add(componentInParent) && list.Count < maxPieces.Value)
						{
							list.Add(componentInParent);
						}
					}
				}
			}
			int num = 0;
			foreach (WearNTear item in list)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				Piece component2 = ((Component)item).GetComponent<Piece>();
				ZNetView component3 = ((Component)item).GetComponent<ZNetView>();
				if (!((Object)(object)component2 == (Object)null) && !((Object)(object)component3 == (Object)null) && component3.IsValid() && (component2.m_canBeRemoved || (includeWorld.Value && component2.GetCreator() == 0L)) && PrivateArea.CheckAccess(((Component)item).transform.position, 0f, true, false) && (includeWorld.Value || !Location.IsInsideNoBuildLocation(((Component)item).transform.position)) && component2.CanBeRemoved())
				{
					IRemoved component4 = ((Component)component2).GetComponent<IRemoved>();
					if (component4 != null)
					{
						component4.OnRemoved();
					}
					item.Remove(false);
					num++;
				}
			}
			if (num > 0)
			{
				((Character)p).Message((MessageType)1, "Removed structure: " + num + " pieces", 0, (Sprite)null, false);
			}
			return num > 0;
		}
	}
	[HarmonyPatch]
	internal static class Cam
	{
		private const float GroundClearance = 0.5f;

		internal static bool Active;

		private static bool carry;

		private static Vector3 pos;

		private static Vector3 start;

		private static float yaw;

		private static float pitch;

		private static Vector3? stationPoint;

		private static float vanillaPickup = -1f;

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

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

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

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

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

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

		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly FieldRef<Player, Piece> Hovering = AccessTools.FieldRefAccess<Player, Piece>("m_hoveringPiece");

		private static readonly FieldRef<float> TakeInputDelay = AccessTools.StaticFieldRefAccess<float>(AccessTools.Field(typeof(PlayerController), "takeInputDelay"));

		private static readonly FieldRef<GameCamera, AudioListener> Listener = AccessTools.FieldRefAccess<GameCamera, AudioListener>("m_listner");

		private static readonly KeyCode[][] Groups = new KeyCode[3][]
		{
			(KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)304,
				(KeyCode)303
			},
			(KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)306,
				(KeyCode)305
			},
			(KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)308,
				(KeyCode)307
			}
		};

		internal static void Tick()
		{
			//IL_0089: 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)
			Player localPlayer = Player.m_localPlayer;
			if (Active && (!Plugin.cameraEnabled.Value || !CanStay(localPlayer)))
			{
				Exit(null);
				return;
			}
			if (Active && carry && (Object)(object)localPlayer != (Object)null)
			{
				if (vanillaPickup < 0f)
				{
					vanillaPickup = localPlayer.m_autoPickupRange;
				}
				localPlayer.m_autoPickupRange = Mathf.Max(vanillaPickup, Plugin.pickupRadius.Value);
			}
			if (Plugin.cameraEnabled.Value && !Typing())
			{
				if (Pressed(Plugin.teleportKey.Value))
				{
					Toggle(localPlayer, withCharacter: true);
				}
				else if (Pressed(Plugin.freeKey.Value))
				{
					Toggle(localPlayer, withCharacter: false);
				}
			}
		}

		private static void Toggle(Player p, bool withCharacter)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (Active)
			{
				Exit("Build camera off");
			}
			else
			{
				if ((Object)(object)GameCamera.instance == (Object)null || GameCamera.InFreeFly())
				{
					return;
				}
				if (!Plugin.HoldsCameraTool(p))
				{
					Message("Equip the Builder's Hammer to use the build camera");
					return;
				}
				Transform transform = ((Component)GameCamera.instance).transform;
				pos = transform.position;
				yaw = transform.eulerAngles.y;
				float x = transform.eulerAngles.x;
				pitch = Mathf.Clamp((x > 180f) ? (x - 360f) : x, -89f, 89f);
				start = ((Component)p).transform.position;
				carry = withCharacter;
				if (carry)
				{
					Hide(p);
				}
				Active = true;
				Message(carry ? "Build camera on (character flies along)" : "Build camera on");
			}
		}

		internal static void Exit(string message)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (Active)
			{
				Active = false;
				Player localPlayer = Player.m_localPlayer;
				if (carry && (Object)(object)localPlayer != (Object)null)
				{
					Show();
					Teleport(localPlayer, start);
					MaxAir.Invoke((Character)(object)localPlayer) = start.y;
				}
				if ((Object)(object)localPlayer != (Object)null && vanillaPickup >= 0f)
				{
					localPlayer.m_autoPickupRange = vanillaPickup;
				}
				vanillaPickup = -1f;
				carry = false;
				if (message != null)
				{
					Message(message);
				}
			}
		}

		private static bool CanStay(Player p)
		{
			if ((Object)(object)p != (Object)null && (Object)(object)GameCamera.instance != (Object)null && !GameCamera.InFreeFly() && Plugin.HoldsCameraTool(p) && !((Character)p).IsDead() && !((Character)p).IsTeleporting() && !((Character)p).IsAttached())
			{
				return !((Character)p).InCutscene();
			}
			return false;
		}

		private static void Message(string text)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		internal static bool Typing()
		{
			if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible())
			{
				if ((Object)(object)Hud.instance != (Object)null)
				{
					return Hud.instance.m_buildUi.SearchFieldFocused;
				}
				return false;
			}
			return true;
		}

		internal static bool Pressed(KeyboardShortcut s)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref s)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref s)).MainKey, false))
			{
				return false;
			}
			List<KeyCode> source = ((KeyboardShortcut)(ref s)).Modifiers.ToList();
			int i;
			for (i = 0; i < Groups.Length; i++)
			{
				bool flag = source.Any((KeyCode m) => Groups[i].Contains(m));
				bool flag2 = ZInput.GetKey(Groups[i][0], false) || ZInput.GetKey(Groups[i][1], false);
				if (flag && !flag2)
				{
					return false;
				}
				if (!flag && flag2 && i > 0)
				{
					return false;
				}
			}
			return true;
		}

		private static bool InputFree()
		{
			if (!Typing() && !InventoryGui.IsVisible() && !Minimap.IsOpen() && !StoreGui.IsVisible() && !Hud.IsPieceSelectionVisible())
			{
				return !Hud.InRadial();
			}
			return false;
		}

		private static void Drive(GameCamera cam, float dt)
		{
			//IL_0203: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: 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)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (InputFree())
			{
				Vector2 val = ZInput.GetMouseDelta() * PlayerController.m_mouseSens * Plugin.mouseSensitivity.Value;
				if (PlayerController.m_invertMouse)
				{
					val.y = 0f - val.y;
				}
				yaw = Mathf.Repeat(yaw + val.x, 360f);
				pitch = Mathf.Clamp(pitch - val.y, -89f, 89f);
				Vector3 zero = Vector3.zero;
				if (ZInput.GetButton("Forward"))
				{
					zero.z += 1f;
				}
				if (ZInput.GetButton("Backward"))
				{
					zero.z -= 1f;
				}
				if (ZInput.GetButton("Right"))
				{
					zero.x += 1f;
				}
				if (ZInput.GetButton("Left"))
				{
					zero.x -= 1f;
				}
				if (ZInput.GetButton("Jump"))
				{
					zero.y += 1f;
				}
				if (ZInput.GetButton("Crouch"))
				{
					zero.y -= 1f;
				}
				if (((Vector3)(ref zero)).sqrMagnitude > 1f)
				{
					((Vector3)(ref zero)).Normalize();
				}
				float num = Plugin.speed.Value * (ZInput.GetButton("Run") ? Plugin.runMultiplier.Value : 1f);
				Quaternion val2 = (Plugin.flatMovement.Value ? Quaternion.Euler(0f, yaw, 0f) : Quaternion.Euler(pitch, yaw, 0f));
				pos += (val2 * new Vector3(zero.x, 0f, zero.z) + Vector3.up * zero.y) * (num * dt);
			}
			Clamp();
			((Component)cam).transform.position = pos;
			((Component)cam).transform.rotation = Quaternion.Euler(pitch, yaw, 0f);
			Camera component = ((Component)cam).GetComponent<Camera>();
			if ((Object)(object)component != (Object)null && component.nearClipPlane != cam.m_nearClipPlaneMin)
			{
				component.nearClipPlane = cam.m_nearClipPlaneMin;
			}
			if (carry && (Object)(object)((Character)localPlayer).m_eye != (Object)null)
			{
				Teleport(localPlayer, pos - (((Character)localPlayer).m_eye.position - ((Component)localPlayer).transform.position));
				MaxAir.Invoke((Character)(object)localPlayer) = ((Component)localPlayer).transform.position.y;
				if (Plugin.invincible.Value && ((Character)localPlayer).GetHealth() < ((Character)localPlayer).GetMaxHealth())
				{
					((Character)localPlayer).SetHealth(((Character)localPlayer).GetMaxHealth());
				}
			}
		}

		private static void Clamp()
		{
			//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_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_0027: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = pos - start;
			float value = Plugin.maxDistance.Value;
			if (((Vector3)(ref val)).sqrMagnitude > value * value)
			{
				pos = start + ((Vector3)(ref val)).normalized * value;
			}
			float num = default(float);
			if (Plugin.stayAboveGround.Value && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(pos, ref num) && pos.y < num + 0.5f)
			{
				pos.y = num + 0.5f;
			}
		}

		private static void Teleport(Player p, Vector3 to)
		{
			//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)p).transform.position = to;
			Rigidbody component = ((Component)p).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.position = to;
				component.linearVelocity = Vector3.zero;
				component.useGravity = false;
			}
		}

		private static void Hide(Player p)
		{
			hidden.Clear();
			disabled.Clear();
			Renderer[] componentsInChildren = ((Component)p).GetComponentsInChildren<Renderer>();
			foreach (Renderer val in componentsInChildren)
			{
				if (val.enabled)
				{
					val.enabled = false;
					hidden.Add(val);
				}
			}
			Collider[] componentsInChildren2 = ((Component)p).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();
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		[HarmonyPrefix]
		private static bool CameraPrefix(GameCamera __instance, float dt)
		{
			if (!Active)
			{
				return true;
			}
			Drive(__instance, dt);
			return false;
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateListner")]
		[HarmonyPrefix]
		private static bool ListenerPrefix(GameCamera __instance)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return true;
			}
			AudioListener val = Listener.Invoke(__instance);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).transform.localPosition = Vector3.zero;
			}
			return false;
		}

		private static bool IsLocal(PlayerController c)
		{
			Player component = ((Component)c).GetComponent<Player>();
			if ((Object)(object)component != (Object)null)
			{
				return (Object)(object)component == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		[HarmonyPatch(typeof(PlayerController), "FixedUpdate")]
		[HarmonyPrefix]
		private static bool ControllerFixed(PlayerController __instance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || !IsLocal(__instance))
			{
				return true;
			}
			TakeInputDelay.Invoke() = Mathf.Max(0f, TakeInputDelay.Invoke() - Time.deltaTime);
			Player.m_localPlayer.SetControls(Vector3.zero, false, false, false, false, false, false, false, false, false, false, false);
			return false;
		}

		[HarmonyPatch(typeof(PlayerController), "LateUpdate")]
		[HarmonyPrefix]
		private static bool ControllerLate(PlayerController __instance)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || !IsLocal(__instance))
			{
				return true;
			}
			Player.m_localPlayer.SetMouseLook(Vector2.zero);
			return false;
		}

		[HarmonyPatch(typeof(Player), "OnDamaged")]
		[HarmonyPostfix]
		private static void Damaged(Player __instance)
		{
			if (Active && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && Plugin.exitWhenHit.Value)
			{
				Exit("You were hit: camera back to your character");
			}
		}

		private static bool Applies(Player p)
		{
			if (Active && (Object)(object)p != (Object)null && (Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				return (Object)(object)GameCamera.instance != (Object)null;
			}
			return false;
		}

		private static bool CameraHitWithin(int mask, float reach)
		{
			//IL_000c: 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)
			Transform transform = ((Component)GameCamera.instance).transform;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(transform.position, transform.forward, ref val, 50f, mask))
			{
				return ((RaycastHit)(ref val)).distance <= reach;
			}
			return false;
		}

		private static float Lift(Player p)
		{
			float maxPlaceDistance = p.m_maxPlaceDistance;
			p.m_maxPlaceDistance = 1000f;
			return maxPlaceDistance;
		}

		private static void Restore(Player p, float old)
		{
			if (old >= 0f)
			{
				p.m_maxPlaceDistance = old;
			}
		}

		[HarmonyPatch(typeof(Player), "PieceRayTest")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool PieceRayPrefix(Player __instance, bool water, ref Vector3 point, ref Vector3 normal, ref Piece piece, ref Heightmap heightmap, ref Collider waterSurface, ref bool __result, out float __state)
		{
			//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)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			__state = -1f;
			if (!Applies(__instance))
			{
				return true;
			}
			float num = Plugin.placementReach.Value;
			GameObject val = Ghost.Invoke(__instance);
			Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				num += (float)val2.m_extraPlacementDistance;
			}
			if (!CameraHitWithin(water ? PlaceWaterMask.Invoke(__instance) : PlaceMask.Invoke(__instance), num))
			{
				point = Vector3.zero;
				normal = Vector3.zero;
				piece = null;
				heightmap = null;
				waterSurface = null;
				__result = false;
				return false;
			}
			__state = Lift(__instance);
			return true;
		}

		[HarmonyPatch(typeof(Player), "PieceRayTest")]
		[HarmonyFinalizer]
		private static void PieceRayFinalizer(Player __instance, float __state)
		{
			Restore(__instance, __state);
		}

		[HarmonyPatch(typeof(Player), "UpdateWearNTearHover")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool HoverPrefix(Player __instance, out float __state)
		{
			__state = -1f;
			if (!Applies(__instance) || !((Character)__instance).InPlaceMode())
			{
				return true;
			}
			if (!CameraHitWithin(RemoveMask.Invoke(__instance), Plugin.placementReach.Value))
			{
				Hovering.Invoke(__instance) = null;
				return false;
			}
			__state = Lift(__instance);
			return true;
		}

		[HarmonyPatch(typeof(Player), "UpdateWearNTearHover")]
		[HarmonyFinalizer]
		private static void HoverFinalizer(Player __instance, float __state)
		{
			Restore(__instance, __state);
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool RemovePrefix(Player __instance, ref bool __result, out float __state)
		{
			return RemoveLike(__instance, ref __result, out __state);
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		[HarmonyFinalizer]
		private static void RemoveFinalizer(Player __instance, float __state)
		{
			Restore(__instance, __state);
		}

		[HarmonyPatch(typeof(Player), "CopyPiece")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool CopyPrefix(Player __instance, ref bool __result, out float __state)
		{
			return RemoveLike(__instance, ref __result, out __state);
		}

		[HarmonyPatch(typeof(Player), "CopyPiece")]
		[HarmonyFinalizer]
		private static void CopyFinalizer(Player __instance, float __state)
		{
			Restore(__instance, __state);
		}

		private static bool RemoveLike(Player p, ref bool result, out float state)
		{
			state = -1f;
			if (!Applies(p))
			{
				return true;
			}
			if (!CameraHitWithin(RemoveMask.Invoke(p), Plugin.placementReach.Value))
			{
				result = false;
				return false;
			}
			state = Lift(p);
			return true;
		}

		private static bool Immortal(Character c)
		{
			if (Active && carry && Plugin.invincible.Value && (Object)(object)c != (Object)null)
			{
				return (Object)(object)c == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		[HarmonyPatch(typeof(Character), "ApplyDamage")]
		[HarmonyPrefix]
		private static bool NoDamage(Character __instance)
		{
			return !Immortal(__instance);
		}

		[HarmonyPatch(typeof(Character), "RPC_Damage")]
		[HarmonyPrefix]
		private static bool NoRpcDamage(Character __instance)
		{
			return !Immortal(__instance);
		}

		private static bool StationNear(Player p)
		{
			if (Applies(p))
			{
				return Plugin.stationNearPiece.Value;
			}
			return false;
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		[HarmonyPrefix]
		private static void RequirementsPrefix(Player __instance, RequirementMode mode)
		{
			//IL_0000: 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 ((int)mode == 0 && StationNear(__instance))
			{
				GameObject val = Ghost.Invoke(__instance);
				if ((Object)(object)val != (Object)null)
				{
					stationPoint = val.transform.position;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		[HarmonyFinalizer]
		private static void RequirementsFinalizer()
		{
			stationPoint = null;
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void CanRemovePrefix(Player __instance, Piece piece)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece != (Object)null && StationNear(__instance))
			{
				stationPoint = ((Component)piece).transform.position;
			}
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		[HarmonyFinalizer]
		private static void CanRemoveFinalizer()
		{
			stationPoint = null;
		}

		[HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")]
		[HarmonyPrefix]
		private static void StationPrefix(ref Vector3 point)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (stationPoint.HasValue)
			{
				point = stationPoint.Value;
			}
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;
	}
	internal static class Cfg
	{
		private static int order = 10000;

		internal static ConfigEntry<T> Add<T>(ConfigFile c, string section, string key, T value, string description, AcceptableValueBase range = null)
		{
			//IL_0003: 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_003d: Expected O, but got Unknown
			//IL_003d: Expected O, but got Unknown
			return c.Bind<T>(new ConfigDefinition(section, key), value, new ConfigDescription(description, range, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = order--
				}
			}));
		}
	}
	[HarmonyPatch]
	internal static class Growth
	{
		private const string BonusKey = "BuildCameraPlus_bonus";

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

		private static readonly Dictionary<Plant, float> lastSeen = new Dictionary<Plant, float>();

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

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

		private static bool On
		{
			get
			{
				if (Plugin.modEnabled.Value)
				{
					return Plugin.growthEnabled.Value;
				}
				return false;
			}
		}

		internal static float Speed(Plant plant)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			float num = 1f;
			if (EnvMan.IsWet())
			{
				num *= Plugin.rainMultiplier.Value;
			}
			if (BeesNear(((Component)plant).transform.position))
			{
				num *= Plugin.beeMultiplier.Value;
			}
			return num;
		}

		private static bool BeesNear(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(pos, Plugin.beeRadius.Value);
			for (int i = 0; i < array.Length; i++)
			{
				Beehive componentInParent = ((Component)array[i]).GetComponentInParent<Beehive>();
				if ((Object)(object)componentInParent != (Object)null && (bool)CheckBiome.Invoke(componentInParent, null) && (bool)HaveFreeSpace.Invoke(componentInParent, null))
				{
					return true;
				}
			}
			return false;
		}

		[HarmonyPatch(typeof(Plant), "SUpdate")]
		[HarmonyPrefix]
		private static void Earn(Plant __instance, float time)
		{
			if (!On)
			{
				return;
			}
			ZNetView val = View.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
			{
				return;
			}
			float value;
			bool num = lastSeen.TryGetValue(__instance, out value);
			lastSeen[__instance] = time;
			if (!num)
			{
				return;
			}
			float num2 = time - value;
			if (!(num2 <= 0f) && !(num2 > 60f))
			{
				float num3 = Speed(__instance);
				if (!(num3 <= 1f))
				{
					ZDO zDO = val.GetZDO();
					zDO.Set("BuildCameraPlus_bonus", zDO.GetFloat("BuildCameraPlus_bonus", 0f) + num2 * (num3 - 1f));
				}
			}
		}

		[HarmonyPatch(typeof(Plant), "TimeSincePlanted")]
		[HarmonyPostfix]
		private static void AddBonus(Plant __instance, ref double __result)
		{
			ZNetView val = View.Invoke(__instance);
			if ((Object)(object)val != (Object)null && val.IsValid())
			{
				__result += val.GetZDO().GetFloat("BuildCameraPlus_bonus", 0f);
			}
		}
	}
	[HarmonyPatch]
	internal static class Planting
	{
		private const float DefaultReach = 0.25f;

		private const float HarvestRadius = 5f;

		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

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

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

		private static readonly Func<Humanoid, ItemData> RightItem = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null), (object)null, true);

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

		private static readonly List<GameObject> markers = new List<GameObject>();

		private static int spaceMask;

		private static bool placing;

		internal static void Tick(Player p)
		{
			//IL_0035: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.plantingEnabled.Value)
			{
				HideMarkers(0);
				return;
			}
			bool flag = !Cam.Typing() && !InventoryGui.IsVisible() && !Menu.IsVisible();
			if (flag && Cam.Pressed(Plugin.bulkHarvestKey.Value))
			{
				BulkHarvest(p);
			}
			Piece val = SelectedPlant(p);
			GameObject val2 = Ghost.Invoke(p);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || !val2.activeInHierarchy)
			{
				HideMarkers(0);
				return;
			}
			if (flag)
			{
				ReadKeys(p);
			}
			List<Vector3> list = Layout(val, val2);
			int num = Affordable(p, val) - 1;
			for (int i = 0; i < list.Count; i++)
			{
				GameObject obj = Marker(i);
				obj.transform.position = list[i] + Vector3.up * 0.15f;
				bool flag2 = i < num && Free(((Component)val).GetComponent<Plant>(), list[i]);
				obj.GetComponent<Renderer>().material.color = (flag2 ? new Color(0.3f, 1f, 0.3f, 1f) : new Color(1f, 0.25f, 0.25f, 1f));
				obj.SetActive(true);
			}
			HideMarkers(list.Count);
		}

		private static Piece SelectedPlant(Player p)
		{
			if (!((Character)p).InPlaceMode())
			{
				return null;
			}
			Piece selectedPiece = p.GetSelectedPiece();
			if (!((Object)(object)selectedPiece != (Object)null) || !((Object)(object)((Component)selectedPiece).GetComponent<Plant>() != (Object)null))
			{
				return null;
			}
			return selectedPiece;
		}

		private static void ReadKeys(Player p)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			int num = (Cam.Pressed(Plugin.rowsUpKey.Value) ? 1 : (Cam.Pressed(Plugin.rowsDownKey.Value) ? (-1) : 0));
			int num2 = (Cam.Pressed(Plugin.colsUpKey.Value) ? 1 : (Cam.Pressed(Plugin.colsDownKey.Value) ? (-1) : 0));
			if (num != 0 || num2 != 0)
			{
				Plugin.rows.Value = Mathf.Clamp(Plugin.rows.Value + num, 1, 15);
				Plugin.columns.Value = Mathf.Clamp(Plugin.columns.Value + num2, 1, 15);
				((Character)p).Message((MessageType)2, "Planting " + Plugin.rows.Value + " x " + Plugin.columns.Value, 0, (Sprite)null, false);
			}
		}

		private static float Spacing(Piece piece)
		{
			if (!reach.TryGetValue(((Object)piece).name, out var value))
			{
				value = 0.25f;
			}
			return Mathf.Max(0.4f, ((Component)piece).GetComponent<Plant>().m_growRadius + value);
		}

		private static List<Vector3> Layout(Piece piece, GameObject ghost)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			List<Vector3> list = new List<Vector3>();
			Vector3 val = Flat(ghost.transform.forward);
			Vector3 val2 = Flat(ghost.transform.right);
			float num = Spacing(piece);
			float num2 = ghost.transform.position.y - GroundAt(ghost.transform.position);
			for (int i = 0; i < Plugin.rows.Value; i++)
			{
				for (int j = 0; j < Plugin.columns.Value; j++)
				{
					if (i != 0 || j != 0)
					{
						Vector3 val3 = ghost.transform.position + val * ((float)i * num) + val2 * ((float)j * num);
						val3.y = GroundAt(val3) + num2;
						list.Add(val3);
					}
				}
			}
			return list;
		}

		private static Vector3 Flat(Vector3 v)
		{
			//IL_0022: 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)
			v.y = 0f;
			if (!(((Vector3)(ref v)).sqrMagnitude < 0.0001f))
			{
				return ((Vector3)(ref v)).normalized;
			}
			return Vector3.forward;
		}

		private static float GroundAt(Vector3 pos)
		{
			//IL_001c: 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)
			float result = default(float);
			if (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGroundHeight(pos, ref result))
			{
				return pos.y;
			}
			return result;
		}

		private static bool Free(Plant plant, Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//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_003b: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			Heightmap val = Heightmap.FindHeightmap(pos);
			if ((Object)(object)val == (Object)null || (val.GetBiome(pos, 0.02f, false) & plant.m_biome) == 0)
			{
				return false;
			}
			if (plant.m_needCultivatedGround && !val.IsCultivated(pos))
			{
				return false;
			}
			if (!PrivateArea.CheckAccess(pos, 0f, false, false))
			{
				return false;
			}
			if (spaceMask == 0)
			{
				spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			}
			return Physics.OverlapSphere(pos, plant.m_growRadius, spaceMask).All((Collider c) => (Object)(object)((Component)c).GetComponentInParent<Player>() != (Object)null);
		}

		private static int Affordable(Player p, Piece piece)
		{
			int num = int.MaxValue;
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (val.m_amount > 0)
				{
					num = Math.Min(num, ((Humanoid)p).GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true) / val.m_amount);
				}
			}
			if (num != int.MaxValue)
			{
				return num;
			}
			return 0;
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		[HarmonyPostfix]
		private static void Placed(Player __instance, Piece piece, bool __result)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			if (!__result || placing || !Plugin.modEnabled.Value || !Plugin.plantingEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<Plant>() == (Object)null)
			{
				return;
			}
			GameObject val = Ghost.Invoke(__instance);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Plant component = ((Component)piece).GetComponent<Plant>();
			Quaternion rotation = val.transform.rotation;
			List<Vector3> list = Layout(piece, val);
			int num = Affordable(__instance, piece) - 1;
			MeasureReach(piece, val.transform.position);
			placing = true;
			try
			{
				ItemData val2 = RightItem((Humanoid)(object)__instance);
				float num2 = BuildStamina(__instance);
				int num3 = 0;
				foreach (Vector3 item in list)
				{
					if (num3 >= num || !((Character)__instance).HaveStamina(num2) || (val2 != null && val2.m_shared.m_useDurability && val2.m_durability <= 0f))
					{
						break;
					}
					if (Free(component, item))
					{
						__instance.PlacePiece(piece, item, rotation, false, false);
						__instance.ConsumeResources(piece.m_resources, 0, -1, 1);
						((Character)__instance).UseStamina(num2);
						if (val2 != null && val2.m_shared.m_useDurability)
						{
							val2.m_durability = Mathf.Max(0f, val2.m_durability - PlaceDurability(__instance, val2));
						}
						num3++;
					}
				}
				if (num3 > 0)
				{
					((Character)__instance).Message((MessageType)1, "Planted " + (num3 + 1), 0, (Sprite)null, false);
				}
			}
			finally
			{
				placing = false;
			}
		}

		private static void MeasureReach(Piece piece, Vector3 near)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (reach.ContainsKey(((Object)piece).name))
			{
				return;
			}
			Plant val = (from c in Physics.OverlapSphere(near, 0.6f)
				select ((Component)c).GetComponentInParent<Plant>()).FirstOrDefault((Func<Plant, bool>)((Plant pl) => (Object)(object)pl != (Object)null && ((Object)pl).name.StartsWith(((Object)piece).name)));
			if (!((Object)(object)val == (Object)null))
			{
				float num = 0f;
				Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren<Collider>();
				foreach (Collider val2 in componentsInChildren)
				{
					float num3 = num;
					Bounds bounds = val2.bounds;
					float x = ((Bounds)(ref bounds)).extents.x;
					bounds = val2.bounds;
					float num4 = Mathf.Max(x, ((Bounds)(ref bounds)).extents.z);
					bounds = val2.bounds;
					num = Mathf.Max(num3, num4 + Flat3(((Bounds)(ref bounds)).center - ((Component)val).transform.position));
				}
				reach[((Object)piece).name] = Mathf.Clamp(num, 0.05f, 1f);
			}
		}

		private static float Flat3(Vector3 v)
		{
			v.y = 0f;
			return ((Vector3)(ref v)).magnitude;
		}

		private static void BulkHarvest(Player p)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			GameObject hoverObject = ((Humanoid)p).GetHoverObject();
			Vector3 val = (((Object)(object)hoverObject != (Object)null) ? hoverObject.transform.position : ((Component)p).transform.position);
			int num = 0;
			foreach (Pickable item in (from c in Physics.OverlapSphere(val, 5f)
				select ((Component)c).GetComponentInParent<Pickable>() into x
				where (Object)(object)x != (Object)null
				select x).Distinct().ToList())
			{
				if (item.CanBePicked() && item.Interact((Humanoid)(object)p, false, false))
				{
					num++;
				}
			}
			if (num > 0)
			{
				((Character)p).Message((MessageType)1, "Picked " + num, 0, (Sprite)null, false);
			}
		}

		private static GameObject Marker(int i)
		{
			//IL_001a: 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)
			while (markers.Count <= i)
			{
				GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
				Object.Destroy((Object)(object)val.GetComponent<Collider>());
				val.transform.localScale = Vector3.one * 0.25f;
				val.SetActive(false);
				markers.Add(val);
			}
			return markers[i];
		}

		private static void HideMarkers(int from)
		{
			for (int i = from; i < markers.Count; i++)
			{
				if ((Object)(object)markers[i] != (Object)null)
				{
					markers[i].SetActive(false);
				}
			}
		}
	}
	[BepInPlugin("saymonn.BuildCameraPlus", "BuildCameraPlus", "1.6.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "saymonn.BuildCameraPlus";

		public const string PrefabName = "BuildCameraPlus_Hammer";

		public const string ItemName = "$bcp_hammer";

		internal static ConfigEntry<bool> modEnabled;

		internal static ConfigEntry<bool> hammerEnabled;

		internal static ConfigEntry<bool> cameraEnabled;

		internal static ConfigEntry<bool> repairEnabled;

		internal static ConfigEntry<bool> plantingEnabled;

		internal static ConfigEntry<bool> growthEnabled;

		internal static ConfigEntry<KeyboardShortcut> teleportKey;

		internal static ConfigEntry<KeyboardShortcut> freeKey;

		internal static ConfigEntry<float> speed;

		internal static ConfigEntry<float> runMultiplier;

		internal static ConfigEntry<float> mouseSensitivity;

		internal static ConfigEntry<float> maxDistance;

		internal static ConfigEntry<float> placementReach;

		internal static ConfigEntry<float> repairRadius;

		internal static ConfigEntry<float> pickupRadius;

		internal static ConfigEntry<bool> flatMovement;

		internal static ConfigEntry<bool> stayAboveGround;

		internal static ConfigEntry<bool> stationNearPiece;

		internal static ConfigEntry<bool> exitWhenHit;

		internal static ConfigEntry<bool> invincible;

		internal static ConfigEntry<bool> cameraWithFarmTools;

		internal static ConfigEntry<KeyboardShortcut> rowsUpKey;

		internal static ConfigEntry<KeyboardShortcut> rowsDownKey;

		internal static ConfigEntry<KeyboardShortcut> colsUpKey;

		internal static ConfigEntry<KeyboardShortcut> colsDownKey;

		internal static ConfigEntry<KeyboardShortcut> bulkHarvestKey;

		internal static ConfigEntry<int> rows;

		internal static ConfigEntry<int> columns;

		internal static ConfigEntry<float> rainMultiplier;

		internal static ConfigEntry<float> beeMultiplier;

		internal static ConfigEntry<float> beeRadius;

		private static readonly Func<Humanoid, ItemData> RightItem = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<Humanoid, ItemData> HiddenRightItem = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_hiddenRightItem");

		private void Awake()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_056c: Unknown result type (might be due to invalid IL or missing references)
			modEnabled = Cfg.Add(((BaseUnityPlugin)this).Config, "01 General", "Enabled", value: true, "Master switch. When off, the whole mod is inactive.");
			hammerEnabled = Cfg.Add(((BaseUnityPlugin)this).Config, "02 Hammer", "Craftable", value: true, "The Builder's Hammer can be crafted at the workbench for 1 wood (needs a game restart). Otherwise use the console: spawn BuildCameraPlus_Hammer");
			cameraEnabled = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "Enabled", value: true, "Free build camera with the Builder's Hammer.");
			teleportKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "03 Camera", "TeleportKey", new KeyboardShortcut((KeyCode)98, Array.Empty<KeyCode>()), "Fly the camera and carry your invisible character with it, so you can pick up scattered pieces. Press again to return to where you started.");
			freeKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "03 Camera", "FreeKey", new KeyboardShortcut((KeyCode)98, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Detach only the camera; your character stays where it is.");
			cameraWithFarmTools = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "WorksWithCultivatorAndHoe", value: true, "The camera can also be started with any cultivator or hoe, not only with the Builder's Hammer (area repair stays hammer only).");
			speed = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "Speed", 10f, "Flight speed in metres per second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f));
			runMultiplier = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "RunMultiplier", 3f, "How much faster you fly while holding the Run key (Shift).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f));
			mouseSensitivity = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "MouseSensitivity", 1f, "Multiplies the game's own mouse sensitivity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f));
			flatMovement = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "HorizontalMovement", value: true, "On: forward/back move level with the ground. Off: forward goes where you look, up or down too.");
			maxDistance = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "MaxDistance", 250f, "How far (metres) the camera or character may fly from the spot where you started.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 1000f));
			stayAboveGround = Cfg.Add(((BaseUnityPlugin)this).Config, "03 Camera", "StayAboveGround", value: false, "On: the camera cannot go below the terrain. Off: you can fly under the world (both B and Alt+B).");
			invincible = Cfg.Add(((BaseUnityPlugin)this).Config, "04 Camera - B mode", "InvincibleWhileFlying", value: true, "In the B mode (character flies along) the character takes no damage at all: lava, fire, falling, drowning, monsters.");
			exitWhenHit = Cfg.Add(((BaseUnityPlugin)this).Config, "04 Camera - B mode", "ExitWhenHit", value: true, "If your character takes damage, the camera snaps back.");
			pickupRadius = Cfg.Add(((BaseUnityPlugin)this).Config, "04 Camera - B mode", "PickupRadius", 2f, "In the B mode (character flies along): radius in metres in which the character picks up lying items (leftovers of destroyed pieces and so on). In the game it is 2 m, which is the default here.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f));
			placementReach = Cfg.Add(((BaseUnityPlugin)this).Config, "05 Camera - Building reach", "PlacementReach", 10f, "How far (metres) from the camera you can place, repair and remove pieces.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 50f));
			stationNearPiece = Cfg.Add(((BaseUnityPlugin)this).Config, "05 Camera - Building reach", "WorkbenchNearPiece", value: false, "The crafting station must be near the piece, not near your character.");
			repairEnabled = Cfg.Add(((BaseUnityPlugin)this).Config, "06 Area Repair", "Enabled", value: true, "Repairing a piece with the Builder's Hammer also repairs every damaged piece around it, no crafting station needed.");
			repairRadius = Cfg.Add(((BaseUnityPlugin)this).Config, "06 Area Repair", "Radius", 50f, "Radius in metres around the repaired piece.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f));
			AreaDestroy.Bind(((BaseUnityPlugin)this).Config);
			plantingEnabled = Cfg.Add(((BaseUnityPlugin)this).Config, "08 Planting", "Enabled", value: true, "Plant in rows and columns with the cultivator, and bulk-harvest.");
			rows = Cfg.Add(((BaseUnityPlugin)this).Config, "08 Planting", "Rows", 1, "Current number of rows.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 15));
			columns = Cfg.Add(((BaseUnityPlugin)this).Config, "08 Planting", "Columns", 1, "Current number of columns.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 15));
			rowsUpKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "08 Planting", "RowsUpKey", new KeyboardShortcut((KeyCode)273, Array.Empty<KeyCode>()), "More rows.");
			rowsDownKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "08 Planting", "RowsDownKey", new KeyboardShortcut((KeyCode)274, Array.Empty<KeyCode>()), "Fewer rows.");
			colsUpKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "08 Planting", "ColumnsUpKey", new KeyboardShortcut((KeyCode)275, Array.Empty<KeyCode>()), "More columns.");
			colsDownKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "08 Planting", "ColumnsDownKey", new KeyboardShortcut((KeyCode)276, Array.Empty<KeyCode>()), "Fewer columns.");
			bulkHarvestKey = Cfg.Add<KeyboardShortcut>(((BaseUnityPlugin)this).Config, "08 Planting", "BulkHarvestKey", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Pick every ripe plant within 5 m of the one you pick.");
			growthEnabled = Cfg.Add(((BaseUnityPlugin)this).Config, "09 Growth", "Enabled", value: true, "Plants grow faster in rain and near working beehives.");
			rainMultiplier = Cfg.Add(((BaseUnityPlugin)this).Config, "09 Growth", "RainMultiplier", 2f, "Growth speed while it rains on the plant.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f));
			beeMultiplier = Cfg.Add(((BaseUnityPlugin)this).Config, "09 Growth", "BeeMultiplier", 1.5f, "Growth speed within BeeRadius of a working beehive.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f));
			beeRadius = Cfg.Add(((BaseUnityPlugin)this).Config, "09 Growth", "BeeRadius", 20f, "Radius in metres around a beehive.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f));
			AddTranslations();
			Rules.Bind(((BaseUnityPlugin)this).Config);
			PrefabManager.OnVanillaPrefabsAvailable += CreateHammer;
			new Harmony("saymonn.BuildCameraPlus").PatchAll();
		}

		private void Update()
		{
			if (modEnabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Rules.Tick(Player.m_localPlayer);
				Cam.Tick();
				Planting.Tick(Player.m_localPlayer);
			}
		}

		private void OnDestroy()
		{
			Cam.Exit(null);
		}

		internal static bool HoldsHammer(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			ItemData val = RightItem((Humanoid)(object)player) ?? HiddenRightItem.Invoke((Humanoid)(object)player);
			if (val != null)
			{
				return val.m_shared.m_name == "$bcp_hammer";
			}
			return false;
		}

		internal static bool HoldsCameraTool(Player player)
		{
			if (HoldsHammer(player))
			{
				return true;
			}
			if (!cameraWithFarmTools.Value || (Object)(object)player == (Object)null)
			{
				return false;
			}
			ItemData val = RightItem((Humanoid)(object)player) ?? HiddenRightItem.Invoke((Humanoid)(object)player);
			if (val == null)
			{
				return false;
			}
			string name = val.m_shared.m_name;
			if (!(name == "$item_cultivator"))
			{
				return name == "$item_hoe";
			}
			return true;
		}

		private static void AddTranslations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "bcp_hammer", "Builder's Hammer" },
				{ "bcp_hammer_desc", "A hammer that never wears out. B flies the camera with your character, Alt+B only the camera." }
			});
			text = "Polish";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "bcp_hammer", "Młot Wielozadaniowy" },
				{ "bcp_hammer_desc", "Młot, który się nie zużywa. B leci kamerą razem z postacią, Alt+B tylko kamerą." }
			});
		}

		private static void CreateHammer()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= CreateHammer;
			ItemConfig val = new ItemConfig();
			val.Enabled = hammerEnabled.Value;
			val.Name = "$bcp_hammer";
			val.Description = "$bcp_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 = new CustomItem("BuildCameraPlus_Hammer", "Hammer", val2);
			if ((Object)(object)val3.ItemPrefab == (Object)null)
			{
				Logger.LogWarning((object)"Could not clone the vanilla hammer.");
				return;
			}
			SharedData shared = val3.ItemDrop.m_itemData.m_shared;
			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);
		}

		private static Sprite LoadIcon()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "hammer.png");
			if (!File.Exists(path))
			{
				return null;
			}
			MethodInfo methodInfo = AccessTools.Method("UnityEngine.ImageConversion:LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, (Type[])null);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2]
			{
				val,
				File.ReadAllBytes(path)
			}))
			{
				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 AreaRepair
	{
		private static readonly FieldRef<Player, Piece> Hovering = AccessTools.FieldRefAccess<Player, Piece>("m_hoveringPiece");

		private static int mask;

		private static bool repairing;

		private static bool Wanted(Player p)
		{
			if (Plugin.modEnabled.Value && Plugin.repairEnabled.Value && (Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				return Plugin.HoldsHammer(p);
			}
			return false;
		}

		[HarmonyPatch(typeof(Player), "Repair")]
		[HarmonyPrefix]
		private static void Before(Player __instance)
		{
			repairing = Wanted(__instance);
		}

		[HarmonyPatch(typeof(Player), "Repair")]
		[HarmonyFinalizer]
		private static void After()
		{
			repairing = false;
		}

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

		[HarmonyPatch(typeof(Player), "Repair")]
		[HarmonyPostfix]
		private static void Around(Player __instance, ItemData toolItem)
		{
			//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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			if (!Wanted(__instance) || toolItem == null || !((Character)__instance).InPlaceMode())
			{
				return;
			}
			Piece val = Hovering.Invoke(__instance);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (mask == 0)
			{
				mask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vehicle" });
			}
			Vector3 centre = ((Component)val).transform.position;
			HashSet<WearNTear> hashSet = new HashSet<WearNTear>();
			List<WearNTear> list = new List<WearNTear>();
			Collider[] array = Physics.OverlapSphere(centre, Plugin.repairRadius.Value, mask);
			for (int i = 0; i < array.Length; i++)
			{
				WearNTear componentInParent = ((Component)array[i]).GetComponentInParent<WearNTear>();
				if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && !((Object)(object)((Component)componentInParent).gameObject == (Object)(object)((Component)val).gameObject))
				{
					ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null && component.IsValid() && componentInParent.GetHealthPercentage() < 1f)
					{
						list.Add(componentInParent);
					}
				}
			}
			int num = 0;
			foreach (WearNTear item in list.OrderBy(delegate(WearNTear w)
			{
				//IL_0006: 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_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val2 = ((Component)w).transform.position - centre;
				return ((Vector3)(ref val2)).sqrMagnitude;
			}))
			{
				if (PrivateArea.CheckAccess(((Component)item).transform.position, 0f, false, false) && item.Repair())
				{
					num++;
				}
			}
			if (num > 0)
			{
				((Character)__instance).Message((MessageType)1, "Repaired around: " + num, 0, (Sprite)null, false);
			}
		}
	}
	[HarmonyPatch]
	internal static class Rules
	{
		private static ConfigEntry<bool> restrictionsEnabled;

		private static ConfigEntry<bool> extensionEnabled;

		private static ConfigEntry<bool> allowClose;

		private static ConfigEntry<bool> unbreakable;

		private static ConfigEntry<bool> buildRangeEnabled;

		private static ConfigEntry<bool> freeBuildStamina;

		private static ConfigEntry<bool> freeRemoveStamina;

		private static ConfigEntry<bool> noWorkbench;

		private static ConfigEntry<bool> noStonecutter;

		private static ConfigEntry<bool> noForge;

		private static ConfigEntry<bool> autoRemove;

		private static ConfigEntry<float> buildRange;

		private static ConfigEntry<float> extensionDistance;

		private static readonly Dictionary<PlacementStatus, ConfigEntry<bool>> ignored = new Dictionary<PlacementStatus, ConfigEntry<bool>>();

		private static CraftingStation anyStation;

		private const float VanillaDistance = 5f;

		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly FieldRef<Player, PlacementStatus> Status = AccessTools.FieldRefAccess<Player, PlacementStatus>("m_placementStatus");

		private static readonly Action<Player, bool> SetGhostValid = AccessTools.MethodDelegate<Action<Player, bool>>(AccessTools.Method(typeof(Player), "SetPlacementGhostValid", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<List<StationExtension>> AllExtensions = AccessTools.StaticFieldRefAccess<List<StationExtension>>(AccessTools.Field(typeof(StationExtension), "m_allExtensions"));

		private static ConfigEntry<bool> missingStation;

		private static readonly FieldRef<CraftingStation, float> BuiltRange = AccessTools.FieldRefAccess<CraftingStation, float>("m_buildRange");

		private static readonly FieldRef<CraftingStation, CircleProjector> RangeCircle = AccessTools.FieldRefAccess<CraftingStation, CircleProjector>("m_areaMarkerCircle");

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

		private static int removedFrame = -1;

		private static float removeKeyTime = -10f;

		private static bool Master
		{
			get
			{
				if (Plugin.modEnabled.Value)
				{
					return restrictionsEnabled.Value;
				}
				return false;
			}
		}

		private static float Distance
		{
			get
			{
				if (!Plugin.modEnabled.Value || !extensionEnabled.Value)
				{
					return 5f;
				}
				return extensionDistance.Value;
			}
		}

		internal static void Bind(ConfigFile c)
		{
			restrictionsEnabled = Cfg.Add(c, "10 Build Restrictions", "Enabled", value: false, "Build where the game normally refuses. Only the rules you switch on below are ignored.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)1, "IgnoreInvalidPlacement", "Place pieces where the game says \"Invalid placement\": overlapping pieces, a campfire on a wooden floor, steep slopes.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)2, "IgnorePlayerInTheWay", "Build even when a player stands where the piece goes.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)3, "IgnoreNoBuildZones", "Build in protected places like the trader's camp and boss altars.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)5, "IgnoreSpaceNeeded", "Build pieces that need free space around them (beds, portals) in tight spots.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)6, "IgnoreTeleportAreas", "Place pieces that are normally only allowed in special teleport areas anywhere.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)7, "IgnoreExtensionWithoutStation", "Build station upgrades without their crafting station nearby.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)8, "IgnoreBiomeRestrictions", "Build pieces that are limited to certain biomes anywhere.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)9, "IgnoreCultivatedGround", "Plant crops and saplings without cultivated ground.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)10, "IgnoreDirtRequirement", "Place pieces that need dirt or grass on any ground.");
			Rule(c, "10 Build Restrictions", (PlacementStatus)11, "IgnoreDungeonRestrictions", "Build inside dungeons and crypts.");
			missingStation = Cfg.Add(c, "10 Build Restrictions", "IgnoreMissingWorkbench", value: false, "Build without a workbench (or other station a piece needs) nearby.");
			extensionEnabled = Cfg.Add(c, "11 Station Extension Range", "Enabled", value: true, "Station upgrades (chopping block, tanning rack, bellows...) may be further from their crafting station.");
			extensionDistance = Cfg.Add(c, "11 Station Extension Range", "Distance", 30f, "How far (metres) an upgrade may be from its station. Normal is 5.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f));
			allowClose = Cfg.Add(c, "11 Station Extension Range", "AllowExtensionsNextToEachOther", value: true, "Upgrades of the same kind can be built close together (normally blocked).");
			extensionEnabled.SettingChanged += delegate
			{
				ApplyExtensions();
			};
			extensionDistance.SettingChanged += delegate
			{
				ApplyExtensions();
			};
			buildRangeEnabled = Cfg.Add(c, "12 Station Build Range", "Enabled", value: true, "Crafting stations (stonecutter, workbench, forge...) count for building from further away.");
			buildRange = Cfg.Add(c, "12 Station Build Range", "Distance", 100f, "How far (metres) from a station you can still build the pieces that need it, e.g. stone walls near the stonecutter. Never less than the station's own range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f));
			noWorkbench = Cfg.Add(c, "13 Station Requirement", "NoWorkbenchNeeded", value: false, "Pieces that need a workbench (wood) can be built and removed without one nearby. Off: the workbench is required.");
			noStonecutter = Cfg.Add(c, "13 Station Requirement", "NoStonecutterNeeded", value: false, "Pieces that need a stonecutter (stone) can be built and removed without one nearby. Off: the stonecutter is required.");
			noForge = Cfg.Add(c, "13 Station Requirement", "NoForgeNeeded", value: false, "Pieces that need a forge (iron) can be built and removed without one nearby. Off: the forge is required.");
			freeBuildStamina = Cfg.Add(c, "14 Building Helpers", "NoStaminaWhenBuilding", value: false, "Building and repairing cost no stamina.");
			freeRemoveStamina = Cfg.Add(c, "14 Building Helpers", "NoStaminaWhenRemoving", value: false, "Removing (destroying) pieces costs no stamina.");
			autoRemove = Cfg.Add(c, "14 Building Helpers", "AutoRemove", value: false, "Hold the middle mouse button (the remove button) with a building tool and pieces under the crosshair are removed one after another, no repeated clicking.");
			unbreakable = Cfg.Add(c, "14 Building Helpers", "UnbreakableStructures", value: false, "Structures never collapse from lack of support: build stone floors and beams in mid-air.");
		}

		private static void Rule(ConfigFile c, string section, PlacementStatus status, string key, string description)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			ignored[status] = Cfg.Add(c, section, key, value: false, description);
		}

		private static bool Ignores(PlacementStatus status)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (Master && ignored.TryGetValue(status, out var value))
			{
				return value.Value;
			}
			return false;
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		[HarmonyPostfix]
		private static void Ghosts(Player __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Ghost.Invoke(__instance) == (Object)null))
			{
				PlacementStatus val = Status.Invoke(__instance);
				if ((int)val != 0 && Ignores(val))
				{
					Status.Invoke(__instance) = (PlacementStatus)0;
					SetGhostValid(__instance, arg2: true);
				}
			}
		}

		[HarmonyPatch(typeof(Location), "IsInsideNoBuildLocation")]
		[HarmonyPostfix]
		private static void NoBuildLocation(ref bool __result)
		{
			if (__result && Ignores((PlacementStatus)3))
			{
				__result = false;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")]
		[HarmonyPostfix]
		private static void AnyStation(string name, ref CraftingStation __result)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			if (!((Object)(object)__result != (Object)null) && Plugin.modEnabled.Value && ((Master && missingStation.Value) || (name == "$piece_workbench" && noWorkbench.Value) || (name == "$piece_stonecutter" && noStonecutter.Value) || (name == "$piece_forge" && noForge.Value)))
			{
				if ((Object)(object)anyStation == (Object)null)
				{
					GameObject val = new GameObject("BuildCameraPlus_AnyStation");
					val.SetActive(false);
					Object.DontDestroyOnLoad((Object)val);
					anyStation = val.AddComponent<CraftingStation>();
				}
				__result = anyStation;
			}
		}

		private static void ApplyExtensions()
		{
			List<StationExtension> list = AllExtensions.Invoke();
			if (list == null)
			{
				return;
			}
			foreach (StationExtension item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.m_maxStationDistance = Distance;
				}
			}
		}

		[HarmonyPatch(typeof(StationExtension), "Awake")]
		[HarmonyPrefix]
		private static void ExtensionAwake(StationExtension __instance)
		{
			__instance.m_maxStationDistance = Distance;
		}

		[HarmonyPatch(typeof(StationExtension), "OtherExtensionInRange")]
		[HarmonyPostfix]
		private static void OtherExtension(ref bool __result)
		{
			if (Plugin.modEnabled.Value && extensionEnabled.Value && allowClose.Value)
			{
				__result = false;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "GetExtensions")]
		[HarmonyPostfix]
		private static void WiderRange(CraftingStation __instance)
		{
			if (Plugin.modEnabled.Value && buildRangeEnabled.Value)
			{
				float num = Mathf.Max(BuiltRange.Invoke(__instance), buildRange.Value);
				BuiltRange.Invoke(__instance) = num;
				CircleProjector val = RangeCircle.Invoke(__instance);
				if ((Object)(object)val != (Object)null)
				{
					val.m_radius = num;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		[HarmonyPostfix]
		private static void Removed(bool __result)
		{
			if (__result)
			{
				removedFrame = Time.frameCount;
			}
		}

		[HarmonyPatch(typeof(Player), "GetBuildStamina")]
		[HarmonyPostfix]
		private static void NoBuildStamina(ref float __result)
		{
			if (Plugin.modEnabled.Value && ((Time.frameCount == removedFrame) ? freeRemoveStamina.Value : freeBuildStamina.Value))
			{
				__result = 0f;
			}
		}

		internal static void Tick(Player p)
		{
			if (Plugin.modEnabled.Value && !((Object)(object)p == (Object)null) && ((Character)p).InPlaceMode())
			{
				if (ZInput.GetButton("Remove") || ZInput.GetButtonUp("Remove"))
				{
					removeKeyTime = Time.time;
				}
				if ((Time.time - removeKeyTime < 0.5f) ? freeRemoveStamina.Value : freeBuildStamina.Value)
				{
					((Character)p).AddStamina(((Character)p).GetMaxStamina());
				}
				if (autoRemove.Value && !AreaDestroy.Held() && ZInput.GetButton("Remove") && !ZInput.GetButton("AltPlace") && !Cam.Typing() && !Hud.IsPieceSelectionVisible() && !InventoryGui.IsVisible())
				{
					RemovePressed.Invoke(p) = Time.time;
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "HaveSupport")]
		[HarmonyPostfix]
		private static void Supported(ref bool __result)
		{
			if (Plugin.modEnabled.Value && unbreakable.Value)
			{
				__result = true;
			}
		}
	}
}