Decompiled source of ZenConstruction v1.1.1

plugins/ZenConstruction.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Zen;
using Zen.Lib;
using Zen.Lib.Config;
using Zen.Lib.Controls;
using ZenConstruction.Section;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenConstruction")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ZenDragon")]
[assembly: AssemblyProduct("ZenConstruction")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.1.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ZenConstruction
{
	internal static class Configs
	{
		public static readonly ConfigEntry<bool> AllowTorchWithHammer;

		public static readonly ConfigEntry<bool> ShowSnapIcon;

		public static readonly ConfigEntry<StringList> RecoverAllMats;

		private static readonly ConfigEntry<bool> BuildFromAttachedCart;

		public static readonly ConfigEntry<bool> ContainerOpenAttached;

		public static readonly ConfigEntry<int> ContainerOpenAttachedMaxDistance;

		public static readonly ConfigEntry<bool> ContainerOpenCraft;

		public static readonly ConfigEntry<bool> ContainerRenameForVehicle;

		public static readonly ConfigEntry<StringList> ContainersIgnored;

		public static readonly ConfigEntry<bool> StationContainerOpen;

		public static readonly ConfigEntry<bool> StationContainerOpenPlayer;

		public static readonly ConfigEntry<StringList> StationsIgnored;

		public static readonly ConfigEntry<float> StationContainerRange;

		public static readonly ConfigEntry<float> StationExtensionDistanceScale;

		public static readonly ConfigEntry<bool> StationContainerHighlight;

		public static readonly ConfigEntry<bool> EnableRotationChange;

		public static readonly ConfigEntry<StringList> RotationSegments;

		public static readonly ConfigEntry<KeyCode> HammerKey;

		public static readonly ConfigEntry<bool> BuildOnScenery;

		public static readonly ConfigEntry<bool> BuildOnSceneryNoTreeSupport;

		public static readonly ConfigEntry<StringList> BuildOnSceneryPrefabs;

		public static readonly ConfigEntry<StringList> NoSupportPrefabs;

		public static readonly ConfigEntry<StringList> NoBuildLocations;

		public static readonly ConfigEntry<float> NoBuildLocationsRadius;

		public static bool CanBuildFromCart
		{
			get
			{
				if (BuildFromAttachedCart.Value)
				{
					return !InventoryGui.IsVisible();
				}
				return false;
			}
		}

		static Configs()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_008c: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Expected O, but got Unknown
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_025f: Expected O, but got Unknown
			//IL_028b: 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_029b: Expected O, but got Unknown
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Expected O, but got Unknown
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Expected O, but got Unknown
			//IL_02bb: Expected O, but got Unknown
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Expected O, but got Unknown
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Expected O, but got Unknown
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Expected O, but got Unknown
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Expected O, but got Unknown
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Expected O, but got Unknown
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Expected O, but got Unknown
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Expected O, but got Unknown
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Expected O, but got Unknown
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Expected O, but got Unknown
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Expected O, but got Unknown
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Expected O, but got Unknown
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Expected O, but got Unknown
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Expected O, but got Unknown
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Expected O, but got Unknown
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Expected O, but got Unknown
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Expected O, but got Unknown
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Expected O, but got Unknown
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Expected O, but got Unknown
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Expected O, but got Unknown
			//IL_0405: Expected O, but got Unknown
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Expected O, but got Unknown
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Expected O, but got Unknown
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0430: Expected O, but got Unknown
			//IL_0430: Unknown result type (might be due to invalid IL or missing references)
			//IL_043b: Expected O, but got Unknown
			//IL_043b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Expected O, but got Unknown
			//IL_0446: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Expected O, but got Unknown
			//IL_0452: Expected O, but got Unknown
			AllowTorchWithHammer = Config.Define<bool>(true, "General", "Allow Torch With Hammer", true, "When enabled allows the a torch to be equipped in the offhand while using the Hammer.\r\n(Vanilla: false)");
			BuildFromAttachedCart = Config.Define<bool>(true, "General", "Build From Attached Cart", true, "When enabled allows using building materials directly from the attached cart.\r\nNOTE: Materials are consumed from the player's inventory before the cart's inventory.\r\n(Vanilla: false)");
			ShowSnapIcon = Config.Define<bool>(true, "General", "Show Snapping Icon", true, "Show snapping icon in the build HUD in all input modes, not just gamepad console 1 or 2.\r\n(Vanilla: false)");
			StringList val = new StringList();
			((List<string>)val).Add("piece_sharpstakes");
			((List<string>)val).Add("piece_dvergr_sharpstakes");
			((List<string>)val).Add("piece_stakewall_blackwood");
			RecoverAllMats = Config.Define<StringList>(true, "General", "Recover All Mats", val, "Comma separated list of pieces that will drop all materials when destroyed. (Vanilla: blank)\r\n[logout required for changes to take effect]");
			ContainerRenameForVehicle = Config.Define<bool>(true, "Containers", "Rename For Vechicles", true, "Rename open containers for vehicles in the inventory UI so that it matches the vehicle name, not \"Storage\"\r\nFor example the opened Cart storage would be \"Cart\", the Karve storage would be Karve.\r\nThis makes it easier to discern what you have opened when using automatic opening.\r\nThis does NOT change the hovertext, it still says \"Storage\" on the hovertext.\r\nOnly the inventory UI is changed to reflect the vehicle name of the accessed Storage.");
			ContainerOpenCraft = Config.Define<bool>(true, "Containers", "Craft From Open Containers", true, "Craft directly from open containers. (vanilla: false)\r\nNOTE: Materials are consumed from the player's inventory before they are consumed from the container's inventory.");
			ContainerOpenAttached = Config.Define<bool>(true, "Containers", "Open Attached", true, "When opening the inventory UI automatically open attached vehicle containers such as carts or ships when captain.");
			ContainerOpenAttachedMaxDistance = Config.Define<int>(true, "Containers", "Open Attached - Max Distance", 3, Config.AcceptRange<int>(3, 50), "Any attached containers beyond this distance will not auto-open.\r\nExamples:\r\n- Carts only, no ships: 3 (default)\r\n- Carts and Karve: 4\r\n- Carts, Karve, Longship: 12\r\n- Everything: 20\r\nYou can dial in the distance as needed for any custom requirements.");
			ContainersIgnored = Config.Define<StringList>(true, "Containers", "Ignored Containers", StringList.Empty, "Containers in this list are not auto-opened.");
			StationContainerOpen = Config.Define<bool>(true, "Crafting Stations", "Open Closest Container", true, "When using a crafting station open the closest container. ");
			StationContainerOpenPlayer = Config.Define<bool>(false, "Crafting Stations", "Open Closest To Player", true, "When \"" + ((ConfigEntryBase)StationContainerOpen).Definition.Key + "\" is true: \r\nUse the player's position to find the closest container.\r\nIf none are found, then use the station's position to look for a nearby container.\r\nIf this is false always uses the station's position, never the player's.");
			StationContainerRange = Config.Define<float>(true, "Crafting Stations", "Station Container Range", 2.5f, Config.AcceptRange<float>(1f, 10f), "Search distance when finding the closest container.");
			StationContainerHighlight = Config.Define<bool>(false, "Crafting Stations", "Station Container Highlight", true, "Highlight the container when it is opened from the crafting station.");
			StationsIgnored = Config.Define<StringList>(true, "Crafting Stations", "Stations Ignored", StringList.Empty, "List of crafting station prefab names that will not attempt to open nearby containers when used.");
			StationExtensionDistanceScale = Config.Define<float>(true, "Crafting Stations", "Station Extension Distance Scale", 1f, Config.AcceptRange<float>(1f, 3f), "Multiplier for max distance that workstation extensions can be spread out. (Vanilla: 1)\r\nLarger values allow extensions to be further away from the workstation. More elbow room.");
			EnableRotationChange = Config.Define<bool>(true, "Input", "Rotation Angle Change", true, "Enable rotation degree adjustment for smoother curves, example: 30 degrees instead of 45.\r\nEquip your hammer then press:\r\nKeyboard: Press LeftShift + RightArrow to cycle modes.\r\nGamepad: Press Alt Interact + D-Pad Right to cycle modes.");
			StringList val2 = new StringList();
			((List<string>)val2).Add("8:Default");
			((List<string>)val2).Add("10:Advanced");
			((List<string>)val2).Add("16:Expert");
			RotationSegments = Config.Define<StringList>(true, "Input", "Rotation Segments", val2, "List of rotation segments to cycle through.\r\nThese values are the number of segments in a HALF circle.\r\nCAUTION: adding to many segments will make distinguishing the angles very difficult since you are slicing\r\na circle and the more segments you have the more subtle the distinction is between each segment.\r\nThe pie slices get smaller, it gets harder to tell what angle it's going to snap at.");
			HammerKey = Config.Define<KeyCode>(false, "Input", "Hammer Hotkey", (KeyCode)98, "Put your hammer anywhere in your inventory. This frees up a slot on your hotbar.\r\nWhen pressed it searches your inventory for your highest level Hammer and equips it.\r\nPress again to unequip.  Press and hold to quick select repair. \r\nGamepad: Hold D-Pad Down to equip your hammer.  Hold again while hammer equipped to toggle repair mode.\r\n[restart required for changes to take effect]");
			StringList val3 = new StringList();
			((List<string>)val3).Add("sign");
			((List<string>)val3).Add("piece_shieldgenerator");
			((List<string>)val3).Add("piece_beehive");
			NoSupportPrefabs = Config.Define<StringList>(true, "Structure", "No Support Prefabs", val3, "List of prefabs which will have support removed, nothing can be attached to them.");
			BuildOnScenery = Config.Define<bool>(true, "Structure", "Build on Scenery", false, "When false the player is not able to attach construction pieces to the sides of scenery.\r\nIt requires a flater surface. Can no longer stick things to the sides of rocks or trees.\r\nUnless the piece is on the exception list.\r\nThis encourages the player to build using materials available from the ground up.\r\nEnemeies can destroy the foundations of their constructions.\r\n(Vanilla: true)");
			BuildOnSceneryNoTreeSupport = Config.Define<bool>(true, "Structure", "Build on Scenery - No Tree Support", false, "When enabled trees do not provide support.  Anything attached to a tree will collapse.\r\nThis encourages the player to build on the ground instead of in trees where monsters can not attack them.\r\nDANGER: Enabling this on an existing world with construction supported only by trees will cause it to collapse!\r\n(Vanilla: false)");
			StringList val4 = new StringList();
			((List<string>)val4).Add("sign");
			((List<string>)val4).Add("itemstand");
			((List<string>)val4).Add("piece_beehive");
			((List<string>)val4).Add("piece_walltorch");
			((List<string>)val4).Add("piece_dvergr_lantern");
			((List<string>)val4).Add("piece_brazierceiling01");
			((List<string>)val4).Add("piece_banner01");
			((List<string>)val4).Add("piece_banner02");
			((List<string>)val4).Add("piece_banner03");
			((List<string>)val4).Add("piece_banner04");
			((List<string>)val4).Add("piece_banner05");
			((List<string>)val4).Add("piece_banner06");
			((List<string>)val4).Add("piece_banner07");
			((List<string>)val4).Add("piece_banner08");
			((List<string>)val4).Add("piece_banner09");
			((List<string>)val4).Add("piece_banner10");
			((List<string>)val4).Add("piece_banner11");
			((List<string>)val4).Add("piece_cloth_hanging_door");
			((List<string>)val4).Add("piece_cloth_hanging_door_blue");
			((List<string>)val4).Add("piece_cloth_hanging_door_blue2");
			BuildOnSceneryPrefabs = Config.Define<StringList>(true, "Structure", "Build on Scenery - Prefabs", val4, "Exception list of prefabs that can be attached to scenery when " + ((ConfigEntryBase)BuildOnScenery).Definition.Key + " is false.\r\nNOTE: They will not be able to support other pieces attached to them.");
			StringList val5 = new StringList();
			((List<string>)val5).Add("Eikthyrnir");
			((List<string>)val5).Add("GDKing");
			((List<string>)val5).Add("Bonemass");
			((List<string>)val5).Add("Dragonqueen");
			((List<string>)val5).Add("GoblinKing");
			((List<string>)val5).Add("FaderLocation");
			StringList val6 = val5;
			NoBuildLocations = Config.Define<StringList>(true, "Structure", "No Build Locations", val6, "List of locations that prohibit building.\r\nDefaults include Bonemass to prevent palyer cheesing the boss fight by standing on top of the boss alter.\r\nAll other boss alters included by default for safety and completeness.\r\n[leave the area for changes to take effect]");
			NoBuildLocationsRadius = Config.Define<float>(true, "Structure", "No Build Locations Radius", 25f, Config.AcceptRange<float>(0.1f, 200f), "Distance around No Build Locations that building is prohibited.");
		}
	}
	internal static class Inputs
	{
		public static readonly ActionString Build = ControlInputs.Create("$hud_build $radial_hold");

		public static readonly ActionString Repair = ControlInputs.Create("$hud_repair $radial_hold");

		public static void Register()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Build.AddButton(Configs.HammerKey.Value, false, false, false, 0f, 0f);
			Build.AddButton((GamepadInput)3, false, true, false, 0f, 0f);
			Repair.AddButton(Configs.HammerKey.Value, false, false, false, 0f, 0f);
			Repair.AddButton((GamepadInput)3, false, true, false, 0f, 0f);
		}
	}
	[BepInPlugin("ZenDragon.ZenConstruction", "ZenConstruction", "1.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : ZenMod<Plugin>
	{
		public const string PluginGUID = "ZenDragon.ZenConstruction";

		public const string PluginName = "ZenConstruction";

		public const string PluginVersion = "1.1.1";

		protected override void Setup()
		{
			ZenMod.RequireGamepadRemap = true;
			base.RegisterInputs += Inputs.Register;
			base.ConfigSync += OnConfigSync;
		}

		private static void OnConfigSync()
		{
			Structure.SetupPrefabs();
			RecoverAllMats.SetupPrefabs();
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

		protected override void WorldStart()
		{
			QuickSelectBuild.CreateKeyHints();
		}

		protected override void Shutdown()
		{
		}

		private void Update()
		{
			if (ZenMod<Plugin>.Initialized && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				QuickSelectBuild.HandleInput();
				BuildRotation.HandleInput();
			}
		}
	}
}
namespace ZenConstruction.Section
{
	public static class BuildRotation
	{
		private static int _currentIndex;

		public static void HandleInput()
		{
			if (Configs.EnableRotationChange.Value && UI.IsBuildModeActive && HumanoidExt.IsUsing((Humanoid)(object)Player.m_localPlayer, "Hammer", false))
			{
				if (ZInput.GetKey((KeyCode)304, true) && ZInput.GetKeyDown((KeyCode)275, true))
				{
					SetNextBuildRotation();
				}
				if (ZInput.GetButton(ControlInputs.JoyAlt) && ZInput.GetButtonDown("JoyDPadRight"))
				{
					SetNextBuildRotation();
				}
			}
		}

		private static void SetNextBuildRotation()
		{
			Dictionary<string, string> dictionary = Configs.RotationSegments.Value.ToDictionary(':');
			List<(int, string)> list = new List<(int, string)>();
			foreach (string key in dictionary.Keys)
			{
				if (!int.TryParse(key, out var result) || result < 2)
				{
					Logging<Plugin>.Error((object)("Ignoring invalid rotation segments in configs: " + key), (ushort)0);
				}
				else
				{
					list.Add((result, dictionary[key]));
				}
			}
			list.Sort();
			if (list.Count == 0)
			{
				Logging<Plugin>.Error((object)"No rotation segments defined.", (ushort)0);
				return;
			}
			_currentIndex++;
			_currentIndex %= list.Count;
			(int, string) tuple = list[_currentIndex];
			string text = StringExt.Localize("$msg_build_rotation", new string[2]
			{
				tuple.Item2,
				(2 * tuple.Item1).ToString()
			});
			Player.m_localPlayer.m_placeRotationDegrees = 180f / (float)tuple.Item1;
			((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null);
		}
	}
	[HarmonyPatch]
	internal static class ContainerVehicle
	{
		private static Component? _attachedComponent;

		public static bool IsAttached()
		{
			return Object.op_Implicit((Object)(object)_attachedComponent);
		}

		public static bool IsAttached(out Vagon cart)
		{
			Component? attachedComponent = _attachedComponent;
			return Object.op_Implicit((Object)(object)(cart = (Vagon)(object)((attachedComponent is Vagon) ? attachedComponent : null)));
		}

		public static bool IsAttached(out Ship ship)
		{
			Component? attachedComponent = _attachedComponent;
			return Object.op_Implicit((Object)(object)(ship = (Ship)(object)((attachedComponent is Ship) ? attachedComponent : null)));
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "StartDoodadControl")]
		private static void Player_StartDoodadControl(Player __instance)
		{
			IDoodadController doodadController = __instance.GetDoodadController();
			if (doodadController != null && doodadController.IsValid())
			{
				_attachedComponent = doodadController.GetControlledComponent();
			}
			else
			{
				_attachedComponent = null;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "StopDoodadControl")]
		private static void Player_StopDoodadControl(Player __instance)
		{
			_attachedComponent = null;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Vagon), "AttachTo")]
		private static void Vagon_AttachTo(Vagon __instance)
		{
			if (PlayerExt.IsReady(Player.m_localPlayer) && __instance.IsAttached((Character)(object)Player.m_localPlayer))
			{
				_attachedComponent = (Component?)(object)__instance;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Vagon), "Detach")]
		private static void Vagon_Detach(Vagon __instance)
		{
			if (!PlayerExt.IsReady(Player.m_localPlayer) || __instance.IsAttached((Character)(object)Player.m_localPlayer))
			{
				_attachedComponent = null;
			}
		}
	}
	[HarmonyPatch]
	internal static class ContainerCraft
	{
		[HarmonyPatch]
		private static class CheckRequirements
		{
			[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
			private static class PlayerHaveRequirementItems
			{
				[UsedImplicitly]
				private static void Prefix(Recipe piece)
				{
					_isOneIngredient = piece.m_requireOnlyOneIngredient;
				}

				[UsedImplicitly]
				private static void Postfix()
				{
					_isOneIngredient = false;
				}
			}

			private static bool _isOneIngredient;

			[HarmonyTranspiler]
			[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
			{
				typeof(Piece),
				typeof(RequirementMode)
			})]
			private static IEnumerable<CodeInstruction> Player_HaveRequirements_Transpiler(IEnumerable<CodeInstruction> codes)
			{
				return Inventory_CountItems(codes);
			}

			[HarmonyTranspiler]
			[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
			private static IEnumerable<CodeInstruction> Player_HaveRequirementItems_Transpiler(IEnumerable<CodeInstruction> codes)
			{
				return Inventory_CountItems(codes);
			}

			[HarmonyTranspiler]
			[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
			private static IEnumerable<CodeInstruction> InventoryGui_SetupRequirement_Transpiler(IEnumerable<CodeInstruction> codes)
			{
				return Inventory_CountItems(codes);
			}

			private static IEnumerable<CodeInstruction> Inventory_CountItems(IEnumerable<CodeInstruction> codes)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "CountItems", (Type[])null, (Type[])null);
				Func<Inventory, string, int, bool, int> func = CountItems_Intercept;
				return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)func.Method);
			}

			private static int CountItems_Intercept(Inventory playerInv, string name, int quality, bool matchWorldLevel)
			{
				int num = playerInv.CountItems(name, quality, matchWorldLevel);
				if (!Configs.ContainerOpenCraft.Value && !Configs.CanBuildFromCart)
				{
					return num;
				}
				if (!_isOneIngredient)
				{
					Recipe recipe = ((RecipeDataPair)(ref InventoryGui.instance.m_selectedRecipe)).Recipe;
					if (recipe == null || !recipe.m_requireOnlyOneIngredient)
					{
						if (ContainerInventory == null)
						{
							return num;
						}
						int num2 = ContainerInventory.CountItems(name, quality, matchWorldLevel);
						Logging<Plugin>.Debug((object)$"Items {name} Player: {num} + Container: {num2}", 0);
						return num + num2;
					}
				}
				return num;
			}
		}

		private static Inventory? ContainerInventory
		{
			get
			{
				Container val = InventoryGui.instance.m_currentContainer;
				if (!Object.op_Implicit((Object)(object)val) && Configs.CanBuildFromCart)
				{
					val = (ContainerVehicle.IsAttached(out Vagon cart) ? cart.m_container : null);
				}
				if (!Object.op_Implicit((Object)(object)val))
				{
					return null;
				}
				return val.GetInventory();
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static IEnumerable<CodeInstruction> Player_ConsumeResources(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[4]
			{
				typeof(string),
				typeof(int),
				typeof(int),
				typeof(bool)
			}, (Type[])null);
			Action<Inventory, string, int, int, bool> action = RemoveItem_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method);
		}

		private static void RemoveItem_Intercept(Inventory playerInv, string name, int amount, int itemQuality, bool worldLevelBased)
		{
			if (!Configs.ContainerOpenCraft.Value && !Configs.CanBuildFromCart)
			{
				playerInv.RemoveItem(name, amount, itemQuality, worldLevelBased);
				return;
			}
			Logging<Plugin>.Info((object)$"Removing {name} x{amount} from player inventory", 0);
			int num = playerInv.CountItems(name, itemQuality, worldLevelBased);
			playerInv.RemoveItem(name, amount, itemQuality, worldLevelBased);
			int num2 = amount - num;
			if (num2 > 0 && ContainerInventory != null)
			{
				Logging<Plugin>.Info((object)$"Removing {name} x{num2} from container", 0);
				ContainerInventory.RemoveItem(name, num2, itemQuality, worldLevelBased);
			}
		}
	}
	[HarmonyPatch]
	internal static class ContainerRename
	{
		private static string? _containerName;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static void InventoryGui_Show(InventoryGui __instance, Container? container)
		{
			_containerName = null;
			if (Configs.ContainerRenameForVehicle.Value && Object.op_Implicit((Object)(object)container) && Object.op_Implicit((Object)(object)container.m_nview) && (Object.op_Implicit((Object)(object)((Component)container.m_nview).GetComponent<Vagon>()) || Object.op_Implicit((Object)(object)((Component)container.m_nview).GetComponent<Ship>())))
			{
				Piece component = ((Component)container.m_nview).GetComponent<Piece>();
				if (Object.op_Implicit((Object)(object)component))
				{
					_containerName = StringExt.Localize(component.m_name);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static void InventoryGui_UpdateContainer(InventoryGui __instance)
		{
			if (_containerName != null)
			{
				__instance.m_containerName.text = _containerName;
			}
		}
	}
	[HarmonyPatch]
	internal static class ContainerRules
	{
		private static readonly string[] AlwaysIgnoredContainers = new string[4] { "itemstand", "itemstandh", "ArmorStand", "piece_beehive" };

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Show")]
		[HarmonyPriority(100)]
		private static void InventoryGui_Show(InventoryGui __instance, Container? container)
		{
			if (Object.op_Implicit((Object)(object)container))
			{
				if (Configs.ContainerOpenCraft.Value)
				{
					InventoryGui.instance.m_currentContainer = container;
				}
			}
			else
			{
				Timing.EndOfFrame((MonoBehaviour)(object)__instance, (Action)TryOpenAutomaticContainers);
			}
		}

		private static void TryOpenAutomaticContainers()
		{
			if (TryGetStationContainer(out Container container) || TryGetAttachedContainer(out container))
			{
				Open(container);
			}
		}

		private static void Open(Container container)
		{
			ZNetView nview = container.m_nview;
			Logging<Plugin>.Info((object)("Open container: " + (((nview != null) ? nview.GetPrefabName() : null) ?? ((Object)container).name)), 0);
			container.Interact((Humanoid)(object)Player.m_localPlayer, false, false);
		}

		private static bool TryGetAttachedContainer(out Container container)
		{
			container = null;
			if (!Configs.ContainerOpenAttached.Value)
			{
				return false;
			}
			Container val = null;
			Ship ship;
			if (ContainerVehicle.IsAttached(out Vagon cart))
			{
				val = cart.m_container;
			}
			else if (ContainerVehicle.IsAttached(out ship))
			{
				val = ((Component)ship).GetComponentInChildren<Container>();
			}
			if (!Object.op_Implicit((Object)(object)val) || val.IsInUse())
			{
				return false;
			}
			container = val;
			return true;
		}

		private static bool TryGetStationContainer(out Container container)
		{
			container = null;
			if (!Configs.StationContainerOpen.Value)
			{
				return false;
			}
			CraftingStation currentStation = Player.m_localPlayer.m_currentStation;
			if (!Object.op_Implicit((Object)(object)currentStation))
			{
				return false;
			}
			if (Object.op_Implicit((Object)(object)((Component)currentStation).GetComponentInChildren<Container>()))
			{
				Logging<Plugin>.Info((object)(currentStation.GetHoverName() + " has Container, ignoring"), 0);
				return false;
			}
			if (!Object.op_Implicit((Object)(object)currentStation.m_nview))
			{
				return false;
			}
			if (Configs.StationsIgnored.Value.Contains(currentStation.m_nview.GetPrefabName(), true))
			{
				return false;
			}
			container = GetClosestContainer(currentStation);
			if (!Object.op_Implicit((Object)(object)container))
			{
				return false;
			}
			if (InventoryGui.instance.IsContainerOpen())
			{
				InventoryGui.instance.CloseContainer();
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Container), "RPC_OpenRespons")]
		private static void Container_RPC_OpenResponse(Container __instance, bool granted)
		{
			Logging<Plugin>.Info((object)$"Access granted? {granted}", 0);
			if (granted && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_currentStation))
			{
				if (Configs.StationContainerHighlight.Value)
				{
					Highlight(__instance);
				}
				if (ZInput.IsGamepadActive())
				{
					InventoryGui.instance.SetActiveGroup(3, false);
				}
			}
		}

		private static Container? GetClosestContainer(CraftingStation station)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Container val = (Configs.StationContainerOpenPlayer.Value ? GetNearbyContainer(((Component)Player.m_localPlayer).gameObject) : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = GetNearbyContainer(((Component)station).gameObject);
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				Logging<Plugin>.Info((object)$"Closest container: {((Object)val).name} @ {MathExt.XZY(((Component)val).transform.position)}", 0);
			}
			else
			{
				Logging<Plugin>.Info((object)"No nearby containers found", 0);
			}
			return val;
			static Container? GetNearbyContainer(GameObject g)
			{
				HashSet<string> ignored = ((IEnumerable<string>)Configs.ContainersIgnored.Value).Concat(AlwaysIgnoredContainers).ToHashSet();
				float value = Configs.StationContainerRange.Value;
				return GameObjectExt.GetClosest<Container>(g, value, (Func<Container, bool>)IsValid);
				bool IsValid(Container c)
				{
					if (!c.IsInUse() && WardAccessExt.CanAccessWard(c, false) && Object.op_Implicit((Object)(object)c.m_nview))
					{
						return !ignored.Contains(c.m_nview.GetPrefabName());
					}
					return false;
				}
			}
		}

		private static void Highlight(Container container)
		{
			//IL_0030: 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)
			Piece piece = (Object.op_Implicit((Object)(object)container.m_piece) ? container.m_piece : ((Component)container).GetComponentInParent<Piece>());
			Highlight.Select(piece, false, default(Color));
			Timing.When((MonoBehaviour)(object)container, (Func<bool>)IsClosed, (Action)Unselect);
			static bool IsClosed()
			{
				return !Object.op_Implicit((Object)(object)InventoryGui.instance.m_currentContainer);
			}
			void Unselect()
			{
				Highlight.Unselect(piece);
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static IEnumerable<CodeInstruction> InventoryGui_UpdateContainer_Transpiler(IEnumerable<CodeInstruction> codes)
		{
			FieldInfo autoCloseDistanceField = AccessTools.DeclaredField(typeof(InventoryGui), "m_autoCloseDistance");
			Func<InventoryGui, float> intercept = AutoCloseDistance;
			return Transpilers.Manipulator(codes, (Func<CodeInstruction, bool>)((CodeInstruction c) => CodeInstructionExtensions.Is(c, OpCodes.Ldfld, (MemberInfo)autoCloseDistanceField)), (Action<CodeInstruction>)delegate(CodeInstruction c)
			{
				c.opcode = OpCodes.Call;
				c.operand = intercept.Method;
			});
			static float AutoCloseDistance(InventoryGui gui)
			{
				if (!ContainerVehicle.IsAttached())
				{
					return gui.m_autoCloseDistance;
				}
				return Configs.ContainerOpenAttachedMaxDistance.Value;
			}
		}
	}
	[HarmonyPatch]
	internal static class QuickSelectBuild
	{
		private static Vector2Int? _origPieceIndex;

		private static bool IsUsingHammer
		{
			get
			{
				Player localPlayer = Player.m_localPlayer;
				object obj;
				if (localPlayer == null)
				{
					obj = null;
				}
				else
				{
					ItemData rightItem = ((Humanoid)localPlayer).RightItem;
					obj = ((rightItem != null) ? ItemDataExt.GetPrefabName(rightItem) : null);
				}
				return (string?)obj == "Hammer";
			}
		}

		public static void CreateKeyHints()
		{
			KeyHint.Create((HintType)1, Inputs.Repair, 2, false);
			KeyHint.SetEvent((HintType)1, (Action)OnUpdateHints);
		}

		private static void OnUpdateHints()
		{
			KeyHint.SetVisible(Inputs.Repair, IsUsingHammer && (!ZInput.IsGamepadActive() || !Hud.IsPieceSelectionVisible()));
			KeyHint.SetVisible("Place", !Hud.IsPieceSelectionVisible());
		}

		public static void HandleInput()
		{
			CheckRepairPressed();
			CheckBuildPressed();
		}

		private static bool IsButtonHeld(ActionString button)
		{
			if (!(ZInput.GetButtonPressedTimer(ActionString.op_Implicit(button)) >= 0.8f))
			{
				return false;
			}
			ZInput.ResetButtonStatus(ActionString.op_Implicit(button));
			return true;
		}

		private static void CheckRepairPressed()
		{
			if (IsUsingHammer && (!ZInput.IsGamepadActive() || !Hud.IsPieceSelectionVisible()) && IsButtonHeld(Inputs.Build))
			{
				ToggleRepairTool();
			}
		}

		private static void ToggleRepairTool()
		{
			//IL_0043: 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)
			if (IsUsingHammer)
			{
				Player localPlayer = Player.m_localPlayer;
				if (_origPieceIndex.HasValue)
				{
					localPlayer.SetSelectedPiece(_origPieceIndex.Value);
					localPlayer.UpdatePlacementGhost(false);
					_origPieceIndex = null;
				}
				else
				{
					_origPieceIndex = localPlayer.m_buildPieces.GetSelectedIndex();
					PlayerExt.SelectRepairTool(localPlayer);
				}
			}
		}

		private static void CheckBuildPressed()
		{
			if (!((Character)Player.m_localPlayer).TakeInput())
			{
				return;
			}
			bool flag = (UI.IsBuildModeActive ? ZInput.GetButtonUp(ActionString.op_Implicit(Inputs.Build)) : ZInput.GetButtonDown(ActionString.op_Implicit(Inputs.Build)));
			if (ZInput.IsGamepadActive())
			{
				if (Hud.IsPieceSelectionVisible() || !IsButtonHeld(Inputs.Build))
				{
					return;
				}
				flag = true;
			}
			if (flag && !(ZInput.GetButtonLastPressedTimer(ActionString.op_Implicit(Inputs.Build)) > 0.3f))
			{
				ItemData val = (from item in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()
					where ItemDataExt.GetPrefabName(item) == "Hammer"
					select item into hammer
					orderby hammer.m_quality descending
					select hammer).FirstOrDefault();
				if (val == null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_missingitem: $item_hammer", 0, (Sprite)null);
				}
				else
				{
					ToolEquip.ToggleHammer(val);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "SelectPiece")]
		private static void Hud_SelectPiece()
		{
			_origPieceIndex = null;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Awake")]
		private static void Player_Awake(Player __instance)
		{
			if (IsUsingHammer)
			{
				PlayerExt.SelectRepairTool(__instance);
				((Humanoid)__instance).HideHandItems(false, true);
			}
		}
	}
	[HarmonyPatch]
	internal static class ShowSnapIcon
	{
		[HarmonyPostfix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static void Player_AlternativePlacementActive(Player __instance, ref bool __result)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.ShowSnapIcon.Value)
			{
				if (!ZInput.IsGamepadActive())
				{
					__result = __result || ZInput.GetButton("AltPlace");
				}
				else if ((int)ZInput.InputLayout == 0)
				{
					__result = __result || ZInput.GetButton("JoyAltPlace");
				}
			}
		}
	}
	internal static class RecoverAllMats
	{
		public static void SetupPrefabs()
		{
			foreach (string item in (List<string>)(object)Configs.RecoverAllMats.Value)
			{
				Piece prefab = GlobalStatic.GetPrefab<Piece>(item, false);
				if (!Object.op_Implicit((Object)(object)prefab))
				{
					Logging<Plugin>.Error((object)("Prefab " + item + " not found"), (ushort)0);
					continue;
				}
				Requirement[] resources = prefab.m_resources;
				for (int i = 0; i < resources.Length; i++)
				{
					resources[i].m_recover = true;
				}
			}
		}
	}
	[HarmonyPatch]
	public static class Structure
	{
		internal static void SetupPrefabs()
		{
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if (Configs.NoSupportPrefabs.Value.Contains(((Object)prefab).name, true))
				{
					RemoveStructureSupports(prefab);
				}
				if (!Configs.BuildOnScenery.Value && Configs.BuildOnSceneryPrefabs.Value.Contains(((Object)prefab).name, true))
				{
					RemoveStructureSupports(prefab);
				}
			}
		}

		private static void CheckIfNoBuild(Location location)
		{
			string prefabName = Utils.GetPrefabName(((Component)location).gameObject);
			if (Configs.NoBuildLocations.Value.Contains(prefabName, true))
			{
				location.m_noBuild = true;
				location.m_noBuildRadiusOverride = Configs.NoBuildLocationsRadius.Value;
			}
		}

		private static void RemoveStructureSupports(GameObject prefab)
		{
			WearNTear val = default(WearNTear);
			if (prefab.TryGetComponent<WearNTear>(ref val))
			{
				Logging<Plugin>.Info((object)("Remove WearNTear Supports: " + ((Object)prefab).name), 0);
				val.m_supports = false;
			}
		}

		private static bool IsAllowedToBuild(GameObject gameObject)
		{
			if (Configs.BuildOnScenery.Value)
			{
				return true;
			}
			if (Configs.BuildOnSceneryPrefabs.Value.Contains(Utils.GetPrefabName(((Object)gameObject).name), true))
			{
				return true;
			}
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(WearNTear), "UpdateSupport")]
		private static IEnumerable<CodeInstruction> WearNTear_UpdateSupport_Transpiler(IEnumerable<CodeInstruction> codes)
		{
			//IL_007b: 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_009a: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Physics), "OverlapBoxNonAlloc", new Type[5]
			{
				typeof(Vector3),
				typeof(Vector3),
				typeof(Collider[]),
				typeof(Quaternion),
				typeof(int)
			}, (Type[])null);
			Func<Vector3, Vector3, Collider[], Quaternion, int, WearNTear, int> func = OverlapBoxNonAlloc_Intercept;
			return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Call, (object)methodInfo, (string)null)
			}).ThrowIfInvalid("Unable to match IL").Set(OpCodes.Call, (object)func.Method)
				.Insert((CodeInstruction[])(object)new CodeInstruction[1]
				{
					new CodeInstruction(OpCodes.Ldarg_0, (object)null)
				})
				.InstructionEnumeration();
		}

		private static int OverlapBoxNonAlloc_Intercept(Vector3 center, Vector3 halfExtents, Collider[] results, Quaternion orientation, int mask, WearNTear wnt)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapBoxNonAlloc(center, halfExtents, results, orientation, mask);
			if (Configs.BuildOnScenery.Value || IsAllowedToBuild(((Component)wnt).gameObject))
			{
				return num;
			}
			if (!Configs.BuildOnSceneryNoTreeSupport.Value)
			{
				return num;
			}
			return FilterTrees(results, num);
		}

		private static int FilterTrees(Collider[] colliders, int count)
		{
			int result = 0;
			for (int i = 0; i < count; i++)
			{
				Collider val = colliders[i];
				if (Object.op_Implicit((Object)(object)val) && val.enabled && !val.isTrigger && !IsTree(((Component)val).transform))
				{
					colliders[result++] = val;
				}
			}
			return result;
		}

		private static bool IsTree(Transform t)
		{
			if (Object.op_Implicit((Object)(object)((Component)t).GetComponentInParent<TreeBase>()))
			{
				return true;
			}
			while (true)
			{
				if (Utils.GetPrefabName(((Object)t).name).ToLower().Contains("tree"))
				{
					return true;
				}
				if (!Object.op_Implicit((Object)(object)t.parent))
				{
					break;
				}
				t = t.parent;
			}
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static IEnumerable<CodeInstruction> Player_UpdatePlacementGhost_Transpiler(IEnumerable<CodeInstruction> codes, ILGenerator gen)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[3]
			{
				new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null),
				new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null),
				new CodeMatch((OpCode?)OpCodes.Stfld, (object)AccessTools.Field(typeof(Player), "m_placementStatus"), (string)null)
			};
			Func<Vector3, Heightmap, Piece, PlacementStatus> func = PlacementStatusDefault_Intercept;
			CodeInstruction[] array2 = (CodeInstruction[])(object)new CodeInstruction[5]
			{
				new CodeInstruction(OpCodes.Pop, (object)null),
				new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)4),
				new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)6),
				new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)5),
				new CodeInstruction(OpCodes.Call, (object)func.Method)
			};
			return new CodeMatcher(codes, gen).MatchStartForward(array).Advance(2).Insert(array2)
				.ThrowIfInvalid("Unable to match IL")
				.InstructionEnumeration();
		}

		private static PlacementStatus PlacementStatusDefault_Intercept(Vector3 normal, Heightmap? heightmap, Piece? piece)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!IsAllowedToBuild(Player.m_localPlayer.m_placementGhost))
			{
				if (!(normal.y > 0.75f))
				{
					if (!Object.op_Implicit((Object)(object)heightmap) && !Object.op_Implicit((Object)(object)piece))
					{
						return (PlacementStatus)1;
					}
					return (PlacementStatus)0;
				}
				return (PlacementStatus)0;
			}
			return (PlacementStatus)0;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StationExtension), "Awake")]
		private static void StationExtension_Awake(StationExtension __instance)
		{
			float value = Configs.StationExtensionDistanceScale.Value;
			if (value > 1f)
			{
				__instance.m_maxStationDistance *= value;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Location), "Awake")]
		private static void Location_Awake(Location __instance)
		{
			CheckIfNoBuild(__instance);
		}
	}
	[HarmonyPatch]
	internal static class ToolEquip
	{
		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		[HarmonyPriority(200)]
		private static class Humanoid_EquipItem
		{
			[UsedImplicitly]
			private static void Prefix(Humanoid __instance, ItemData? item, ref (ItemData? Left, ItemData? Right) __state)
			{
				__state.Left = __instance.LeftItem;
				__state.Right = __instance.RightItem;
			}

			[UsedImplicitly]
			private static void Postfix(Humanoid __instance, ItemData? item, (ItemData? Left, ItemData? Right) __state)
			{
				Humanoid __instance2 = __instance;
				ItemData item2 = item;
				if (!Configs.AllowTorchWithHammer.Value || (Object)(object)Player.m_localPlayer != (Object)(object)__instance2 || item2 == null)
				{
					return;
				}
				ItemData right = __state.Right;
				var (left, _) = __state;
				if (ItemDataExt.GetPrefabName(item2) == "Hammer")
				{
					EquipHammer();
				}
				else if (ItemDataExt.IsItemType(item2, (ItemType)15))
				{
					ItemData obj = right;
					if (((obj != null) ? ItemDataExt.GetPrefabName(obj) : null) == "Hammer")
					{
						EquipTorchLeftHand();
					}
				}
				void EquipHammer()
				{
					if (left != null && ItemDataExt.IsItemType(left, (ItemType)15))
					{
						__instance2.m_leftItem = left;
					}
					else if (right != null && ItemDataExt.IsItemType(right, (ItemType)15))
					{
						__instance2.m_leftItem = right;
					}
					if (__instance2.m_leftItem != null)
					{
						__instance2.m_leftItem.m_equipped = true;
						__instance2.SetupEquipment();
					}
				}
				void EquipTorchLeftHand()
				{
					__instance2.m_rightItem = right;
					__instance2.m_leftItem = item2;
					__instance2.m_leftItem.m_equipped = true;
					__instance2.m_rightItem.m_equipped = true;
					__instance2.SetupEquipment();
				}
			}
		}

		private const float ToolEquipDuration = 0.3f;

		internal const string HammerTool = "Hammer";

		private static (ItemData? Left, ItemData? Right) _prevEquip;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		[HarmonyPriority(0)]
		private static void ObjectDB_CopyOtherDB(ObjectDB __instance)
		{
			foreach (GameObject item in __instance.m_items)
			{
				SetToolEquipDuration(item.GetComponent<ItemDrop>(), 0.3f);
			}
		}

		private static void SetToolEquipDuration(ItemDrop itemDrop, float duration)
		{
			ItemData itemData = itemDrop.m_itemData;
			if (ItemDataExt.IsItemType(itemData, (ItemType)19))
			{
				if (itemData.m_shared.m_equipDuration <= 0f)
				{
					itemData.m_shared.m_equipDuration = duration;
				}
				Logging<Plugin>.Info((object)(ItemDataExt.GetPrefabName(itemDrop) + " equip duration: " + itemData.m_shared.m_equipDuration), 0);
			}
		}

		internal static void ToggleHammer(ItemData hammer)
		{
			if (!(ItemDataExt.GetPrefabName(hammer) != "Hammer"))
			{
				if (hammer.m_equipped)
				{
					RestoreEquip(hammer);
					return;
				}
				CacheEquip();
				((Humanoid)Player.m_localPlayer).ToggleEquipped(hammer);
			}
		}

		private static void CacheEquip()
		{
			_prevEquip.Left = ((Humanoid)Player.m_localPlayer).LeftItem;
			_prevEquip.Right = ((Humanoid)Player.m_localPlayer).RightItem;
		}

		private static void RestoreEquip(ItemData hammer)
		{
			ItemData val = FindItem(_prevEquip.Right);
			ItemData val2 = FindItem(_prevEquip.Left);
			if (val != null && val2 != null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped(val);
				((Humanoid)Player.m_localPlayer).EquipItem(val2, true);
			}
			else if (val != null && val2 == null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped((ItemData)(ItemDataExt.IsItemType(val, (ItemType)15) ? ((object)hammer) : ((object)val)));
			}
			else if (val == null && val2 != null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped((ItemData)(ItemDataExt.IsItemType(val2, (ItemType)15) ? ((object)hammer) : ((object)val2)));
			}
			else if (val == null && val2 == null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped(hammer);
			}
			_prevEquip = default((ItemData, ItemData));
			static ItemData? FindItem(ItemData? original)
			{
				ItemData original2 = original;
				if (original2 != null)
				{
					return ((IEnumerable<ItemData>)((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => ItemDataExt.IsEqual(item, original2)));
				}
				return null;
			}
		}
	}
}
namespace ZenConstruction.Compatibility
{
	[HarmonyPatch]
	internal static class Backpacks
	{
		private const string BackpacksID = "org.bepinex.plugins.backpacks";

		private static bool IsModLoadedBackpacks => Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.backpacks");

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
		private static void InventoryGui_CloseContainer(InventoryGui __instance)
		{
			if (IsModLoadedBackpacks && InventoryGui.IsVisible())
			{
				__instance.UpdateCraftingPanel(false);
			}
		}
	}
}