Decompiled source of ZenConstruction v0.6.9

plugins/ZenConstruction.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
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("0.6.9")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.6.9.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<bool> ShowPieceHealthColorGradient;

		public static readonly ConfigEntry<bool> StationContainerOpen;

		public static readonly ConfigEntry<bool> StationContainerCraft;

		public static readonly ConfigEntry<StringList> StationsIgnored;

		public static readonly ConfigEntry<StringList> StationContainers;

		public static readonly ConfigEntry<float> StationContainersRange;

		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> EnableSmelterSupports;

		public static readonly ConfigEntry<bool> EnableTreeSupports;

		public static readonly ConfigEntry<StringList> BuildOnTreesException;

		public static readonly ConfigEntry<StringList> NoSupportPrefabs;

		public static readonly ConfigEntry<StringList> NoBuildLocations;

		public static readonly ConfigEntry<float> NoBuildLocationsRadius;

		public static readonly ConfigEntry<float> StationExtensionDistanceScale;

		static Configs()
		{
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_0164: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01d0: Expected O, but got Unknown
			//IL_01fb: 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_020b: Expected O, but got Unknown
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Expected O, but got Unknown
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Expected O, but got Unknown
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Expected O, but got Unknown
			//IL_0241: Expected O, but got Unknown
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Expected O, but got Unknown
			//IL_026b: 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)");
			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)");
			ShowPieceHealthColorGradient = Config.Define<bool>(false, "General", "Show Piece Health Color Gradient", true, "Show the piece health bar as a color gradient: Red > Yellow > Green\r\n[logout required to disable]\r\n(Vanilla: false)");
			StationContainerOpen = Config.Define<bool>(true, "Crafting Stations", "Open Closest Container", true, "When using a crafting station open the closest container. ");
			StationContainerCraft = Config.Define<bool>(true, "Crafting Stations", "Craft From Container", true, "Craft directly from open containers.\r\nNOTE: Materials are consumed from the open container before they are consumed from the player inventory.");
			StationContainersRange = Config.Define<float>(true, "Crafting Stations", "Station Containers Range", 2f, Config.AcceptRange<float>(1f, 10f), "Search distance when finding the closest container in the allowed list.");
			StationContainers = Config.Define<StringList>(true, "Crafting Stations", "Station Containers Allowed", Config.ContainersCommon, "Interacting with crafting stations open the closest container in this list that is not in use.");
			StationContainerHighlight = Config.Define<bool>(false, "Crafting Stations", "Station Container Highlight", true, "Highlight the container while 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.");
			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 val = new StringList();
			((List<string>)val).Add("8:Default");
			((List<string>)val).Add("10:Advanced");
			((List<string>)val).Add("16:Expert");
			RotationSegments = Config.Define<StringList>(true, "Input", "Rotation Segments", val, "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]");
			EnableSmelterSupports = Config.Define<bool>(true, "Structure", "Enable Smelter Supports", true, "Enable structure support on Smelters, Blast Furnaces, Kilns, etc.\r\nCan the player attach construction to those pieces? (Vanilla: True)");
			StringList val2 = new StringList();
			((List<string>)val2).Add("sign");
			((List<string>)val2).Add("piece_shieldgenerator");
			NoSupportPrefabs = Config.Define<StringList>(true, "Structure", "No Support Prefabs", val2, "List of prefabs which will always have support removed");
			EnableTreeSupports = Config.Define<bool>(true, "Structure", "Tree Supports", false, "Do trees support construction? (Vanilla: True)");
			StringList val3 = new StringList();
			((List<string>)val3).Add("sign");
			((List<string>)val3).Add("piece_walltorch");
			((List<string>)val3).Add("piece_dvergr_lantern");
			((List<string>)val3).Add("itemstand");
			((List<string>)val3).Add("piece_beehive");
			BuildOnTreesException = Config.Define<StringList>(true, "Structure", "Allow Build On Trees Prefabs", val3, "These items can always be built on trees.  \r\nNOTE: These items will lose any support capability they may have had.");
			StringList val4 = new StringList();
			((List<string>)val4).Add("Bonemass");
			NoBuildLocations = Config.Define<StringList>(true, "Structure", "No Build Locations", val4, "List of locations that prohibit building.\r\nDefaults to Bonemass because otherwise the palyer can cheese the boss fight by standing on top of the boss alter.\r\nExample, All Boss Locations:\r\nEikthyrnir, GDKing, Bonemass, Dragonqueen, GoblinKing, FaderLocation ");
			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.");
			StationExtensionDistanceScale = Config.Define<float>(true, "Structure", "Station Extension Distance Multiplier", 1.17f, 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.");
		}
	}
	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", "0.6.9")]
	[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 = "0.6.9";

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

		private static void OnConfigSync()
		{
			Structure.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 PieceHealthColor
	{
		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
		private static IEnumerable<CodeInstruction> Hud_UpdateCrosshair(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(GuiBar), "SetValue", (Type[])null, (Type[])null);
			Action<GuiBar, float> action = SetValue_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method);
		}

		private static void SetValue_Intercept(GuiBar guiBar, float value)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			guiBar.SetValue(value);
			if (Configs.ShowPieceHealthColorGradient.Value)
			{
				guiBar.SetColor(AdjustColor(value));
			}
		}

		private static Color AdjustColor(float value, float maxValue = 1f, float saturation = 1f, float brightness = 1f)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (maxValue <= 0f)
			{
				return Color.red;
			}
			return Color.HSVToRGB(Mathf.Clamp01(value / maxValue) * (1f / 3f), Mathf.Clamp01(saturation), Mathf.Clamp01(brightness));
		}
	}
	[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");
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class StationContainer
	{
		[HarmonyPatch(typeof(CraftingStation), "Interact")]
		private static class CraftingStationInteract
		{
			[UsedImplicitly]
			private static void Postfix(CraftingStation __instance, Humanoid user)
			{
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				if (!Configs.StationContainerOpen.Value || (Object)(object)_connectedStation == (Object)null)
				{
					return;
				}
				if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInChildren<Container>()))
				{
					Logging<Plugin>.Info((object)(__instance.GetHoverName() + " has Container, ignoring"), 0);
				}
				else if (Object.op_Implicit((Object)(object)__instance.m_nview) && !Configs.StationsIgnored.Value.Contains(__instance.m_nview.GetPrefabName(), true))
				{
					Container closestContainer = GetClosestContainer(_connectedStation);
					if ((Object)(object)closestContainer == (Object)null)
					{
						Logging<Plugin>.Info((object)"No nearby containers found", 0);
						return;
					}
					Logging<Plugin>.Info((object)$"Closest container: {((Object)closestContainer).name} @ {MathExt.XZY(((Component)closestContainer).transform.position)}", 0);
					_connectedContainer = closestContainer;
					closestContainer.Interact(user, false, false);
				}
			}

			[UsedImplicitly]
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(CraftingStation), "CheckUsable", (Type[])null, (Type[])null);
				Func<CraftingStation, Player, bool, bool> func = CheckUsable_Intercept;
				return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)func.Method);
			}

			private static bool CheckUsable_Intercept(CraftingStation station, Player player, bool showMessage)
			{
				if (!station.CheckUsable(player, showMessage))
				{
					return false;
				}
				_connectedStation = station;
				return true;
			}
		}

		[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), "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.StationContainerCraft.Value)
				{
					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 CraftingStation? _connectedStation;

		private static Container? _connectedContainer;

		private static Inventory? ContainerInventory
		{
			get
			{
				Container currentContainer = InventoryGui.instance.m_currentContainer;
				if (currentContainer == null)
				{
					return null;
				}
				return currentContainer.GetInventory();
			}
		}

		private static void ResetState()
		{
			_connectedStation = null;
			_connectedContainer = null;
		}

		private static Container? GetClosestContainer(CraftingStation station)
		{
			StringList allow = Configs.StationContainers.Value;
			float value = Configs.StationContainersRange.Value;
			return GameObjectExt.GetClosest<Container>(((Component)station).gameObject, value, (Func<Container, bool>)((Container c) => !c.IsInUse() && allow.Contains(c.m_nview.GetPrefabName(), true)), "piece");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static void Player_OnSpawned()
		{
			ResetState();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static void InventoryGui_Hide()
		{
			ResetState();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Container), "Interact")]
		private static IEnumerable<CodeInstruction> Container_Interact_Transpiler(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(PrivateArea), "CheckAccess", (Type[])null, (Type[])null);
			Func<Vector3, float, bool, bool, bool> func = CheckAccess_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)func.Method);
		}

		private static bool CheckAccess_Intercept(Vector3 point, float radius, bool flash, bool wardCheck)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return PrivateArea.CheckAccess(point, radius, flash && !Object.op_Implicit((Object)(object)_connectedStation), wardCheck);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "RPC_OpenRespons")]
		private static void Container_RPC_OpenResponse(Container __instance, bool granted)
		{
			if (!Configs.StationContainerOpen.Value && !Configs.StationContainerCraft.Value)
			{
				return;
			}
			if (InventoryGui.instance.IsContainerOpen())
			{
				InventoryGui.instance.CloseContainer();
			}
			InventoryGui.instance.m_currentContainer = __instance;
			if ((Object)(object)_connectedContainer != (Object)(object)__instance || !granted)
			{
				return;
			}
			if (ZInput.IsGamepadActive())
			{
				Timing.EndOfFrame((MonoBehaviour)(object)InventoryGui.instance, (Action)delegate
				{
					InventoryGui.instance.SetActiveGroup(3, false);
				});
			}
			if (Configs.StationContainerHighlight.Value)
			{
				Highlight(__instance);
			}
		}

		private static void Highlight(Container container)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			Container container2 = container;
			WearNTear wnt = ((Component)container2).GetComponentInParent<WearNTear>();
			if (Object.op_Implicit((Object)(object)wnt))
			{
				Color val = default(Color);
				((Color)(ref val))..ctor(0.6f, 0.8f, 1f);
				MaterialMan.instance.SetValue<Color>(((Component)wnt).gameObject, ShaderProps._EmissionColor, val * 0.4f);
				MaterialMan.instance.SetValue<Color>(((Component)wnt).gameObject, ShaderProps._Color, val);
				Timing.When((MonoBehaviour)(object)container2, (Func<bool>)IsClosed, (Action)Unselect);
			}
			bool IsClosed()
			{
				return (Object)(object)_connectedContainer != (Object)(object)container2;
			}
			void Unselect()
			{
				wnt.ResetHighlight();
			}
		}

		[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.StationContainerCraft.Value)
			{
				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]
	public static class Structure
	{
		private static readonly RaycastHit[] RaycastHitInfoBuffer = (RaycastHit[])(object)new RaycastHit[8];

		internal static void SetupPrefabs()
		{
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if (!Configs.EnableSmelterSupports.Value)
				{
					RemoveSmelterStructureSupports(prefab);
				}
				if (Configs.NoSupportPrefabs.Value.Contains(((Object)prefab).name, true))
				{
					RemoveStructureSupports(prefab);
				}
				if (!Configs.EnableTreeSupports.Value && Configs.BuildOnTreesException.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 RemoveSmelterStructureSupports(GameObject prefab)
		{
			Smelter[] componentsInChildren = prefab.GetComponentsInChildren<Smelter>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				RemoveStructureSupports(((Component)componentsInChildren[i]).gameObject);
			}
		}

		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 IsPlacementTree()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Transform transform = ((Component)GameCamera.instance).transform;
			Vector3 position = transform.position;
			Vector3 forward = transform.forward;
			int placeRayMask = localPlayer.m_placeRayMask;
			int num = Physics.RaycastNonAlloc(position, forward, RaycastHitInfoBuffer, 50f, placeRayMask);
			for (int i = 0; i < num; i++)
			{
				RaycastHit val = RaycastHitInfoBuffer[i];
				Transform transform2 = ((RaycastHit)(ref val)).transform;
				if (((Object)transform2).name.Contains("Tree") || (Object.op_Implicit((Object)(object)transform2.parent) && ((Object)transform2.parent).name.Contains("Tree")))
				{
					return false;
				}
				if (Object.op_Implicit((Object)(object)((Component)transform2).GetComponentInParent<TreeBase>()))
				{
					return false;
				}
			}
			return true;
		}

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

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "SetPlacementGhostValid")]
		private static void Player_SetPlacementGhostValid(Player __instance, ref bool valid)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (valid && !Configs.BuildOnTreesException.Value.Contains(Utils.GetPrefabName(((Object)__instance.m_placementGhost).name), true))
			{
				if (!Configs.EnableTreeSupports.Value)
				{
					valid = IsPlacementTree();
				}
				if (!valid)
				{
					__instance.m_placementStatus = (PlacementStatus)1;
				}
			}
		}

		[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);
			}
		}
	}
}