Decompiled source of BetterTweaks v1.0.0

BetterTweaks.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterTweaks.Combat;
using BetterTweaks.Combat.Archery;
using BetterTweaks.Combat.Archery.Animation;
using BetterTweaks.Combat.Archery.Animation.Audio;
using BetterTweaks.Combat.Configuration;
using BetterTweaks.Combat.Melee;
using BetterTweaks.Combat.Patches;
using BetterTweaks.Configuration;
using BetterTweaks.Networking;
using BetterTweaks.Patching;
using BetterTweaks.Persistence;
using BetterTweaks.Services;
using HarmonyLib;
using MagicaCloth2;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("BetterTweaks.MenuSmoke")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BetterTweaks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BetterTweaks")]
[assembly: AssemblyTitle("BetterTweaks")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BetterTweaks
{
	[BepInPlugin("torubaki.bettertweaks", "BetterTweaks", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "torubaki.bettertweaks";

		public const string Version = "1.0.0";

		internal static Plugin Instance;

		internal static Settings Settings;

		internal static readonly OwnedOverrides Overrides = new OwnedOverrides();

		private Harmony harmony;

		internal static string LoadError;

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Instance = this;
			LoadError = "Initialization has not completed. Inspect the BetterTweaks log before loading a character.";
			harmony = new Harmony("torubaki.bettertweaks");
			PatchRegistry patchRegistry = new PatchRegistry(harmony, ((BaseUnityPlugin)this).Logger);
			patchRegistry.Add(typeof(Player), "Load", new Type[1] { typeof(ZPackage) }, typeof(Plugin), "BeforeLoad");
			patchRegistry.Add(typeof(Player), "Save", new Type[1] { typeof(ZPackage) }, typeof(Plugin), "BeforeSave");
			try
			{
				Settings = new Settings(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
				InventorySlots.Install(patchRegistry);
				EquipmentActions.Install(patchRegistry);
				ControlOverrides.Install(patchRegistry);
				ResourceAccess.Install(patchRegistry);
				ForgeRecipes.Install(patchRegistry);
				CraftingStations.Install(patchRegistry);
				BuildingTools.Install(patchRegistry);
				TerrainRadius.Install(patchRegistry);
				TerrainLimits.Install(patchRegistry);
				FreePlacement.Install(patchRegistry);
				CameraInput.Install(patchRegistry);
				LowerGroundFeatures.Install(patchRegistry);
				UnlockAllFeatures.Install(patchRegistry);
				WeatherProtection.Install(patchRegistry);
				BuildingExtras.Install(patchRegistry);
				BuildingEffects.Install(patchRegistry);
				ProductionFeatures.Install(patchRegistry);
				WardFeatures.Install(patchRegistry);
				TurretFeatures.Install(patchRegistry);
				CreatureLoot.Install(patchRegistry);
				WorldFeatures.Install(patchRegistry);
				MapFeatures.Install(patchRegistry);
				Recycling.Install(patchRegistry);
				PlayerFeatures.Install(patchRegistry);
				FoodFeatures.Install(patchRegistry);
				FoodAndBuffs.Install(patchRegistry);
				MagicFeatures.Install(patchRegistry);
				EquipmentRules.Install(patchRegistry);
				CombatRuntime.Install(harmony, ((BaseUnityPlugin)this).Logger);
				SessionProtocol.Install(patchRegistry);
				Settings.EditRequested += SessionProtocol.RequestEdit;
				LoadError = null;
				if (patchRegistry.Failures.Count != 0)
				{
					LoadError = "Unsupported game methods: " + string.Join(", ", patchRegistry.Failures);
				}
				Settings.Changed += Refresh;
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("BetterTweaks {0}; game assembly {1}; Unity {2}; BepInEx {3}.", "1.0.0", typeof(Player).Assembly.GetName().Version, Application.unityVersion, typeof(BaseUnityPlugin).Assembly.GetName().Version));
			}
			catch (Exception ex)
			{
				LoadError = "Initialization failed; character loading and saving are blocked. " + ex.Message;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
			if (LoadError != null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)LoadError);
			}
		}

		private void Start()
		{
			if (LoadError != null)
			{
				return;
			}
			try
			{
				ControlOverrides.Refresh();
			}
			catch (Exception ex)
			{
				LoadError = "Control initialization failed: " + ex.Message;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private static bool BeforeLoad()
		{
			if (LoadError == null)
			{
				return true;
			}
			throw new InvalidOperationException("BetterTweaks blocked character loading. " + LoadError);
		}

		private static void BeforeSave()
		{
			if (LoadError != null)
			{
				throw new InvalidOperationException("BetterTweaks blocked character saving. " + LoadError);
			}
		}

		private void Refresh()
		{
			if (LoadError == null)
			{
				Overrides.Restore();
				PlayerFeatures.Refresh();
				FoodAndBuffs.Refresh();
				SummonFeatures.Refresh();
				LanternUtility.Refresh();
				ForgeRecipes.Refresh();
				CraftingStations.Refresh();
				BuildingExtras.Refresh();
				WardFeatures.Refresh();
				BuildingTools.Refresh();
				LowerGroundFeatures.Refresh();
				TerrainRadius.Tick();
				if (!Settings.On("BuildCamera.General", "Enabled"))
				{
					CameraInput.Exit();
				}
				InventorySlots.Refresh();
				ControlOverrides.Refresh();
			}
		}

		private void Update()
		{
			if (Settings != null && LoadError == null)
			{
				SessionProtocol.Tick();
				MapFeatures.Tick();
				MapPins.Tick();
				TerrainRadius.Tick();
				CameraInput.Tick();
				FreePlacement.Tick();
				if (!((Object)(object)Player.m_localPlayer == (Object)null))
				{
					BuildingTools.Tick();
					EquipmentRules.Tick();
					ResourceAccess.Tick();
					Recycling.Tick();
				}
			}
		}

		private void OnGUI()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (LoadError != null)
			{
				GUI.Box(new Rect(20f, 20f, (float)Mathf.Min(Screen.width - 40, 900), 100f), "BetterTweaks: character loading/saving blocked\n" + LoadError);
			}
		}

		private void OnDestroy()
		{
			CombatRuntime.Close();
			if (Settings != null)
			{
				Settings.Changed -= Refresh;
			}
			if (Settings != null)
			{
				Settings.EditRequested -= SessionProtocol.RequestEdit;
			}
			BuildingExtras.Close();
			CameraInput.Exit();
			TerrainRadius.Close();
			FreePlacement.Close();
			BuildingTools.Close();
			LowerGroundFeatures.Close();
			UnlockAllFeatures.Close();
			InventorySlots.Close();
			SessionProtocol.Close();
			PlayerFeatures.Close();
			FoodFeatures.Close();
			FoodAndBuffs.Close();
			SummonFeatures.Close();
			Overrides.Restore();
			EquipmentRules.Close();
			CraftingStations.Close();
			ForgeRecipes.Close();
			ControlOverrides.Close();
			LanternUtility.Close();
			EquipmentActions.Close();
			ContainerWindow.Close();
			InventoryDiagnostics.Close();
			UtilityVisibility.Close();
			WardFeatures.Close();
			MapFeatures.Close();
			MapPins.Close();
			if (harmony != null)
			{
				PatchRegistry.Unpatch(harmony);
			}
			ConfigFileLayout.Close();
			Settings?.Dispose();
			Settings = null;
			Instance = null;
		}

		internal static void Warn(string text)
		{
			Plugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)text);
			}
		}

		internal static void Info(string text)
		{
			Plugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogInfo((object)text);
			}
		}
	}
}
namespace BetterTweaks.Services
{
	internal static class AmmoSlots
	{
		internal const int Index = 28;

		private static bool syncing;

		[ThreadStatic]
		private static Player restoring;

		internal static bool IsAmmo(ItemData item)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (item != null)
			{
				if ((int)item.m_shared.m_itemType != 9)
				{
					return (int)item.m_shared.m_itemType == 23;
				}
				return true;
			}
			return false;
		}

		internal static void Install(PatchRegistry patches)
		{
			patches.Add(typeof(Player), "OnInventoryChanged", Type.EmptyTypes, typeof(AmmoSlots), null, "Changed");
			patches.Add(typeof(Player), "EquipInventoryItems", Type.EmptyTypes, typeof(AmmoSlots), "BeginRestore", null, "EndRestore");
		}

		private static void BeginRestore(Player __instance, out Player __state)
		{
			__state = restoring;
			restoring = __instance;
		}

		private static Exception EndRestore(Player __state, Exception __exception)
		{
			restoring = __state;
			return __exception;
		}

		private static void Changed(Player __instance)
		{
			if (syncing || (Object)(object)restoring == (Object)(object)__instance || !InventorySlots.AmmoFor(__instance) || EquipmentSlots.Changing(__instance) || Fields.Get<bool>(__instance, "m_isLoading"))
			{
				return;
			}
			ItemData val = InventorySlots.At(__instance, 28);
			if (!IsAmmo(val) || ((Humanoid)__instance).GetAmmoItem() == val)
			{
				return;
			}
			syncing = true;
			try
			{
				((Humanoid)__instance).EquipItem(val, false);
			}
			finally
			{
				syncing = false;
			}
		}

		internal static ItemData Current(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			ItemData ammoItem = ((Humanoid)player).GetAmmoItem();
			if (!IsAmmo(ammoItem) || !ammoItem.m_equipped || ammoItem.m_stack <= 0 || !inventory.ContainsItem(ammoItem))
			{
				return null;
			}
			return ammoItem;
		}

		internal static int Count(Player player, ItemData ammo)
		{
			if (ammo != null)
			{
				return (from i in ((Humanoid)player).GetInventory().GetAllItems()
					where i.m_shared.m_name == ammo.m_shared.m_name
					select i).Sum((ItemData i) => i.m_stack);
			}
			return 0;
		}
	}
	internal static class BuildingEffects
	{
		[ThreadStatic]
		private static string category;

		private static Settings S => Plugin.Settings;

		public static void Install(PatchRegistry p)
		{
			p.Add(typeof(EffectList), "Create", new Type[6]
			{
				typeof(Vector3),
				typeof(Quaternion),
				typeof(Transform),
				typeof(float),
				typeof(int),
				typeof(ZDOID)
			}, typeof(BuildingEffects), "Filter", "Particles", "RestoreEffects");
			p.Add(typeof(Player), "PlacePiece", new Type[5]
			{
				typeof(Piece),
				typeof(Vector3),
				typeof(Quaternion),
				typeof(bool),
				typeof(bool)
			}, typeof(BuildingEffects), "Place", null, "End");
			Context(p, typeof(TerrainModifier), "OnPlaced");
			Context(p, typeof(TerrainOp), "OnPlaced");
			Context(p, typeof(Attack), "DoAreaAttack");
			Context(p, typeof(Attack), "DoNonAttack");
			Context(p, typeof(Attack), "DoMeleeAttack");
			Context(p, typeof(Attack), "FireProjectileBurst");
			Context(p, typeof(Character), "OnDeath");
			Context(p, typeof(Ragdoll), "DestroyNow");
			Context(p, typeof(Projectile), "OnHit", typeof(Collider), typeof(Vector3), typeof(bool), typeof(Vector3));
			p.Add(typeof(FootStep), "DoEffect", new Type[2]
			{
				typeof(StepEffect),
				typeof(Vector3)
			}, typeof(BuildingEffects), "Step", null, "RestoreStep");
			p.Add(typeof(FootStep), "SetEffectCreator", new Type[1] { typeof(GameObject) }, typeof(BuildingEffects), null, "StepParticles");
			Context(p, typeof(WearNTear), "Destroy", typeof(HitData), typeof(bool));
		}

		private static void Context(PatchRegistry p, Type type, string method, params Type[] args)
		{
			p.Add(type, method, args, typeof(BuildingEffects), "Begin", null, "End");
		}

		private static void Begin(object __instance, MethodBase __originalMethod, out string __state)
		{
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Invalid comparison between Unknown and I4
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Invalid comparison between Unknown and I4
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Invalid comparison between Unknown and I4
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Invalid comparison between Unknown and I4
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Invalid comparison between Unknown and I4
			__state = category;
			Type declaringType = __originalMethod.DeclaringType;
			if (declaringType == typeof(Attack))
			{
				ItemData val = Fields.Get<ItemData>(__instance, "m_weapon");
				string text = BuildingTools.ToolName(val);
				Character val2 = Fields.Get<Character>(__instance, "m_character");
				bool flag = (val != null && (int)val.m_shared.m_skillType == 8) || (val != null && (int)val.m_shared.m_skillType == 14);
				category = ((text == "Hoe") ? "Hoe Dust" : ((text == "Cultivator") ? "Cultivator Dust" : (((Object)(object)val2 != (Object)null && !(val2 is Player)) ? "Creature Dust" : (flag ? "Archery Dust" : (((val != null && (int)val.m_shared.m_itemType == 14) || (val != null && (int)val.m_shared.m_itemType == 3) || (val != null && (int)val.m_shared.m_itemType == 22) || (val != null && (int)val.m_shared.m_skillType == 11)) ? "Melee Dust" : null)))));
			}
			else if (declaringType == typeof(Projectile))
			{
				Projectile val3 = (Projectile)__instance;
				Character val4 = Fields.Get<Character>(val3, "m_owner");
				category = (((Object)(object)val4 != (Object)null && !(val4 is Player)) ? "Creature Dust" : (((int)val3.m_skill == 8 || (int)val3.m_skill == 14) ? "Archery Dust" : null));
			}
			else if (declaringType == typeof(Character) || declaringType == typeof(Ragdoll))
			{
				category = ((__instance is Player) ? null : "Creature Dust");
			}
			else if (declaringType == typeof(WearNTear))
			{
				category = "Build Dust";
			}
			else if (category != "Cultivator Dust")
			{
				category = "Hoe Dust";
			}
		}

		private static void Place(Player __instance, Piece __0, out string __state)
		{
			__state = category;
			string text = BuildingTools.ToolName(Fields.Get<ItemData>(__instance, "m_rightItem"));
			string text2 = ((Object)__0).name.ToLowerInvariant();
			category = ((text == "Cultivator" || text2.Contains("replant") || text2.Contains("cultivate")) ? "Cultivator Dust" : ((text == "Hoe" || text2.Contains("road") || text2.Contains("raise") || text2.Contains("path_") || text2.Contains("paved")) ? "Hoe Dust" : "Build Dust"));
		}

		private static Exception End(string __state, Exception __exception)
		{
			category = __state;
			return __exception;
		}

		private static bool Enabled(string kind)
		{
			return kind switch
			{
				"Creature Dust" => S.On("Enemies", "Hide Creature Dust"), 
				"Melee Dust" => S.On("Melee", "Hide Melee Dust"), 
				"Archery Dust" => S.On("Archery", "Hide Archery Dust"), 
				_ => S.On("Effects.Dust Toggles", kind), 
			};
		}

		private static void Particles(GameObject[] __result)
		{
			if (category == null || (!(category == "Archery Dust") && !(category == "Melee Dust") && !(category == "Creature Dust")) || !Enabled(category))
			{
				return;
			}
			foreach (GameObject val in __result)
			{
				if ((Object)(object)val != (Object)null)
				{
					HideDustParticles(val);
				}
			}
		}

		private static void HideDustParticles(GameObject effect)
		{
			ParticleSystem[] componentsInChildren = effect.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val in componentsInChildren)
			{
				bool flag = false;
				Transform val2 = ((Component)val).transform;
				while ((Object)(object)val2 != (Object)null)
				{
					if (IsDust(((Component)val2).gameObject))
					{
						flag = true;
						break;
					}
					val2 = (((Object)(object)val2 == (Object)(object)effect.transform) ? null : val2.parent);
				}
				if (flag)
				{
					val.Stop(false, (ParticleSystemStopBehavior)0);
				}
			}
		}

		private static bool IsDust(GameObject prefab)
		{
			return ((Object)prefab).name.IndexOf("dust", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static void StepParticles(FootStep __instance, GameObject __0)
		{
			Character val = Fields.Get<Character>(__instance, "m_character");
			if ((Object)(object)val != (Object)null && !(val is Player) && Enabled("Creature Dust"))
			{
				HideDustParticles(__0);
			}
		}

		private static void Step(FootStep __instance, StepEffect effect, out GameObject[] __state)
		{
			__state = null;
			Character val = Fields.Get<Character>(__instance, "m_character");
			if (!((Object)(object)val == (Object)null) && !(val is Player) && Enabled("Creature Dust") && effect.m_effectPrefabs.Any((GameObject p) => (Object)(object)p != (Object)null && IsDust(p)))
			{
				__state = effect.m_effectPrefabs;
				effect.m_effectPrefabs = __state.Where((GameObject p) => (Object)(object)p == (Object)null || !IsDust(p)).ToArray();
			}
		}

		private static Exception RestoreStep(StepEffect effect, GameObject[] __state, Exception __exception)
		{
			if (__state != null)
			{
				effect.m_effectPrefabs = __state;
			}
			return __exception;
		}

		private static bool IsVfx(EffectData e)
		{
			if ((Object)(object)e?.m_prefab == (Object)null)
			{
				return false;
			}
			string text = ((Object)e.m_prefab).name.ToLowerInvariant();
			if (!text.Contains("vfx") && !text.StartsWith("fx_"))
			{
				return text.Contains("dust");
			}
			return true;
		}

		private static void Filter(EffectList __instance, out EffectData[] __state)
		{
			__state = null;
			if (category == null || !Enabled(category))
			{
				return;
			}
			Func<EffectData, bool> remove = ((category == "Archery Dust" || category == "Melee Dust" || category == "Creature Dust") ? ((Func<EffectData, bool>)((EffectData e) => (Object)(object)e?.m_prefab != (Object)null && IsDust(e.m_prefab))) : new Func<EffectData, bool>(IsVfx));
			if (__instance.m_effectPrefabs.Any(remove))
			{
				__state = __instance.m_effectPrefabs;
				__instance.m_effectPrefabs = __state.Where((EffectData e) => !remove(e)).ToArray();
			}
		}

		private static Exception RestoreEffects(EffectList __instance, EffectData[] __state, Exception __exception)
		{
			if (__state != null)
			{
				__instance.m_effectPrefabs = __state;
			}
			return __exception;
		}
	}
	internal static class BuildingExtras
	{
		private static readonly HashSet<Fireplace> fires = new HashSet<Fireplace>();

		private static readonly OwnedOverrides overrides = new OwnedOverrides();

		private static readonly HashSet<string> torches = new HashSet<string> { "piece_groundtorch_wood", "piece_groundtorch", "piece_groundtorch_green", "piece_groundtorch_blue", "piece_walltorch", "piece_brazierceiling01", "piece_brazierfloor01", "piece_brazierfloor02", "piece_jackoturnip" };

		internal static void Install(PatchRegistry patches)
		{
			patches.Add(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, typeof(BuildingExtras), null, "Crops");
			patches.Add(typeof(Fireplace), "Awake", Type.EmptyTypes, typeof(BuildingExtras), null, "FireAwake");
		}

		private static void Crops(Player __instance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Settings.On("Player", "cropNotifier") || (int)__instance.GetPlacementStatus() != 0)
			{
				return;
			}
			GameObject val = Fields.Get<GameObject>(__instance, "m_placementGhost");
			Plant val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Plant>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			int mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			Collider[] array = Physics.OverlapSphere(val.transform.position, val2.m_growRadius, mask);
			foreach (Collider val3 in array)
			{
				if (!((Component)val3).transform.IsChildOf(val.transform) && !((Object)(object)((Component)val3).GetComponentInParent<Plant>() == (Object)null))
				{
					Fields.Set(__instance, "m_placementStatus", (object)(PlacementStatus)5);
					Piece component = val.GetComponent<Piece>();
					if (component != null)
					{
						component.SetInvalidPlacementHeightlight(true);
					}
					break;
				}
			}
		}

		private static void FireAwake(Fireplace __instance)
		{
			fires.Add(__instance);
			Configure(__instance);
		}

		private static void Configure(Fireplace fire)
		{
			bool flag = torches.Contains(Utils.GetPrefabName(((Component)fire).gameObject));
			if (Plugin.Settings.On("FireSource", flag ? "torches" : "fires"))
			{
				overrides.Set(fire, "infiniteFuel", () => fire.m_infiniteFuel, delegate(bool value)
				{
					fire.m_infiniteFuel = value;
				}, value: true);
			}
		}

		internal static void Refresh()
		{
			overrides.Restore();
			fires.RemoveWhere((Fireplace fire) => (Object)(object)fire == (Object)null);
			foreach (Fireplace fire in fires)
			{
				Configure(fire);
			}
		}

		internal static void Close()
		{
			overrides.Restore();
			fires.Clear();
		}
	}
	internal static class BuildingTools
	{
		private sealed class PlacementState
		{
			internal Player Previous;

			internal Attack Attack;

			internal float Stamina;
		}

		private static float nextScan;

		private static Player freeBuilder;

		private static readonly HashSet<SharedData> logged = new HashSet<SharedData>();

		internal static string ToolName(ItemData item)
		{
			if (item == null)
			{
				return null;
			}
			string a = (((Object)(object)item.m_dropPrefab == (Object)null) ? "" : ((Object)item.m_dropPrefab).name.Replace("(Clone)", ""));
			string[] array = new string[3] { "Hammer", "Hoe", "Cultivator" };
			foreach (string text in array)
			{
				if (string.Equals(a, text, StringComparison.OrdinalIgnoreCase) || string.Equals(item.m_shared.m_name, "$item_" + text.ToLowerInvariant(), StringComparison.OrdinalIgnoreCase))
				{
					return text;
				}
			}
			return null;
		}

		internal static bool FreeDurability(ItemData item)
		{
			string text = ToolName(item);
			if (text != null)
			{
				return Plugin.Settings.On("BuildingTools", text + " No Durability Drain");
			}
			return false;
		}

		internal static bool FreeStamina(ItemData item)
		{
			string text = ToolName(item);
			if (text != null)
			{
				return Plugin.Settings.On("BuildingTools", text + " No Stamina Drain");
			}
			return false;
		}

		internal static bool FreeStation(ItemData item)
		{
			string text = ToolName(item);
			if (text != null)
			{
				return Plugin.Settings.On("BuildingTools", text + " No Workbench Requirement");
			}
			return false;
		}

		public static void Install(PatchRegistry p)
		{
			p.Add(typeof(Player), "GetBuildStamina", Type.EmptyTypes, typeof(BuildingTools), "BuildStamina");
			p.Add(typeof(Attack), "GetAttackStamina", Type.EmptyTypes, typeof(BuildingTools), "AttackStamina");
			p.Add(typeof(Player), "UpdatePlacement", new Type[2]
			{
				typeof(bool),
				typeof(float)
			}, typeof(BuildingTools), "BeginPlacement", null, "EndPlacement");
			p.Add(typeof(Player), "HaveStamina", new Type[1] { typeof(float) }, typeof(BuildingTools), "HaveStamina");
			p.Add(typeof(Humanoid), "StartAttack", new Type[2]
			{
				typeof(Character),
				typeof(bool)
			}, typeof(BuildingTools), "BeginAttack", null, "EndAttack");
			p.Add(typeof(Player), "HaveRequirements", new Type[2]
			{
				typeof(Piece),
				typeof(RequirementMode)
			}, typeof(BuildingTools), "WithoutStation", null, "RestoreStation");
			p.Add(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, typeof(BuildingTools), "WithoutStation", null, "RestoreStation");
		}

		private static bool BuildStamina(Player __instance, ref float __result)
		{
			if (!FreeStamina(Fields.Get<ItemData>(__instance, "m_rightItem")))
			{
				return true;
			}
			__result = 0f;
			return false;
		}

		private static bool AttackStamina(Attack __instance, ref float __result)
		{
			if (!FreeStamina(Fields.Get<ItemData>(__instance, "m_weapon")))
			{
				return true;
			}
			__result = 0f;
			return false;
		}

		private static void BeginPlacement(Player __instance, out PlacementState __state)
		{
			__state = BeginScope(__instance, Fields.Get<ItemData>(__instance, "m_rightItem"));
		}

		private static PlacementState BeginScope(Player player, ItemData item)
		{
			PlacementState placementState = new PlacementState
			{
				Previous = freeBuilder
			};
			freeBuilder = null;
			if ((Object)(object)player == (Object)null || !FreeStamina(item))
			{
				return placementState;
			}
			freeBuilder = player;
			placementState.Attack = item.m_shared.m_attack;
			if (placementState.Attack != null)
			{
				placementState.Stamina = placementState.Attack.m_attackStamina;
				placementState.Attack.m_attackStamina = 0f;
			}
			return placementState;
		}

		private static Exception EndPlacement(PlacementState __state, Exception __exception)
		{
			if (__state != null)
			{
				freeBuilder = __state.Previous;
				if (__state.Attack != null && __state.Attack.m_attackStamina == 0f)
				{
					__state.Attack.m_attackStamina = __state.Stamina;
				}
			}
			return __exception;
		}

		private static bool HaveStamina(Player __instance, ref bool __result)
		{
			if ((Object)(object)__instance != (Object)(object)freeBuilder || (Object)(object)freeBuilder == (Object)null)
			{
				return true;
			}
			__result = true;
			return false;
		}

		private static void BeginAttack(Humanoid __instance, out PlacementState __state)
		{
			__state = BeginScope((Player)(object)((__instance is Player) ? __instance : null), __instance.GetCurrentWeapon());
		}

		private static Exception EndAttack(PlacementState __state, Exception __exception)
		{
			return EndPlacement(__state, __exception);
		}

		private static void WithoutStation(Player __instance, Piece piece, out CraftingStation __state)
		{
			__state = null;
			if (!((Object)(object)piece == (Object)null) && FreeStation(Fields.Get<ItemData>(__instance, "m_rightItem")))
			{
				__state = piece.m_craftingStation;
				piece.m_craftingStation = null;
			}
		}

		private static Exception RestoreStation(Piece piece, CraftingStation __state, Exception __exception)
		{
			if ((Object)(object)piece != (Object)null && (Object)(object)__state != (Object)null && (Object)(object)piece.m_craftingStation == (Object)null)
			{
				piece.m_craftingStation = __state;
			}
			return __exception;
		}

		public static void Refresh()
		{
			nextScan = 0f;
			logged.Clear();
			Tick();
		}

		public static void Tick()
		{
			if (Time.unscaledTime < nextScan)
			{
				return;
			}
			nextScan = Time.unscaledTime + Mathf.Max(0.25f, Plugin.Settings.Get<float>("BuildingTools", "Scan Interval Seconds"));
			IEnumerable<ItemData> first = (((Object)(object)ObjectDB.instance == (Object)null) ? Enumerable.Empty<ItemData>() : (from g in ObjectDB.instance.m_items
				select g.GetComponent<ItemDrop>() into i
				where (Object)(object)i != (Object)null
				select i.m_itemData));
			IEnumerable<ItemData> enumerable;
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				IEnumerable<ItemData> allItems = ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems();
				enumerable = allItems;
			}
			else
			{
				enumerable = Enumerable.Empty<ItemData>();
			}
			IEnumerable<ItemData> second = enumerable;
			foreach (ItemData item in first.Concat(second).Where(FreeDurability))
			{
				SharedData s = item.m_shared;
				if (s.m_useDurability && logged.Add(s) && Plugin.Settings.On("BuildingTools", "Log Changes"))
				{
					Plugin.Info("Building tool durability disabled: " + s.m_name);
				}
				Plugin.Overrides.Set(s, "m_useDurability", () => s.m_useDurability, delegate(bool v)
				{
					s.m_useDurability = v;
				}, value: false);
			}
		}

		internal static void Close()
		{
			freeBuilder = null;
			logged.Clear();
			nextScan = 0f;
		}
	}
	internal static class CameraInput
	{
		private static bool active;

		private static Player owner;

		private static Vector3 position;

		private static float yaw;

		private static float pitch;

		private static float health;

		private static float sailOffset;

		private static Vector3? stationPoint;

		private static Camera drivenCamera;

		private static float nearClip;

		private static bool Enabled => Plugin.Settings.On("BuildCamera.General", "Enabled");

		internal static bool Active => active;

		private static bool Applies(Player player)
		{
			if (active && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)owner)
			{
				return (Object)(object)player == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

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

		internal static bool HasBuildToggle()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled && InventorySlots.InputAllowed && ((Character)Player.m_localPlayer).InPlaceMode())
			{
				KeyboardShortcut val = Plugin.Settings.Get<KeyboardShortcut>("BuildCamera.1 - Keys", "Toggle");
				return ((KeyboardShortcut)(ref val)).IsDown();
			}
			return false;
		}

		internal static void Install(PatchRegistry p)
		{
			p.Add(typeof(GameCamera), "GetCameraPosition", new Type[3]
			{
				typeof(float),
				typeof(Vector3).MakeByRefType(),
				typeof(Quaternion).MakeByRefType()
			}, typeof(CameraInput), null, "Sailing");
			p.Add(typeof(GameCamera), "UpdateCamera", new Type[1] { typeof(float) }, typeof(CameraInput), "Camera");
			p.Add(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, typeof(CameraInput), "Placement", null, "RestorePlacement");
			p.Add(typeof(Player), "PieceRayTest", new Type[6]
			{
				typeof(Vector3).MakeByRefType(),
				typeof(Vector3).MakeByRefType(),
				typeof(Piece).MakeByRefType(),
				typeof(Heightmap).MakeByRefType(),
				typeof(Collider).MakeByRefType(),
				typeof(bool)
			}, typeof(CameraInput), "Placement", "Reach", "RestorePlacement");
			p.Add(typeof(PlayerController), "FixedUpdate", Type.EmptyTypes, typeof(CameraInput), "Controls");
			p.Add(typeof(PlayerController), "LateUpdate", Type.EmptyTypes, typeof(CameraInput), "Look");
			p.Add(typeof(GameCamera), "UpdateListner", Type.EmptyTypes, typeof(CameraInput), "Listener");
			p.Add(typeof(Player), "UpdateWearNTearHover", Type.EmptyTypes, typeof(CameraInput), "Hover", null, "RestorePlacement");
			string[] array = new string[2] { "RemovePiece", "CopyPiece" };
			foreach (string name in array)
			{
				p.Add(typeof(Player), name, Type.EmptyTypes, typeof(CameraInput), "Removal", null, "RestorePlacement");
			}
			p.Add(typeof(Player), "HaveRequirements", new Type[2]
			{
				typeof(Piece),
				typeof(RequirementMode)
			}, typeof(CameraInput), "BuildStation", null, "RestoreStation");
			p.Add(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, typeof(CameraInput), "RemoveStation", null, "RestoreStation");
			p.Add(typeof(CraftingStation), "HaveBuildStationInRange", new Type[2]
			{
				typeof(string),
				typeof(Vector3)
			}, typeof(CameraInput), "Station");
			p.Add(typeof(Player), "OnDamaged", new Type[1] { typeof(HitData) }, typeof(CameraInput), "Damaged");
		}

		internal static void Tick()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (active && !CanStay(localPlayer))
			{
				Exit();
			}
			if (HasBuildToggle())
			{
				if (active)
				{
					Exit();
				}
				else if ((Object)(object)GameCamera.instance != (Object)null)
				{
					owner = localPlayer;
					if (!CanStay(localPlayer))
					{
						owner = null;
						return;
					}
					active = true;
					position = ((Component)GameCamera.instance).transform.position;
					Vector3 eulerAngles = ((Component)GameCamera.instance).transform.eulerAngles;
					yaw = eulerAngles.y;
					pitch = ((eulerAngles.x > 180f) ? (eulerAngles.x - 360f) : eulerAngles.x);
					health = ((Character)localPlayer).GetHealth();
				}
			}
			if (!active)
			{
				return;
			}
			if (Plugin.Settings.On("BuildCamera.3 - Limits", "ExitWhenHit") && ((Character)localPlayer).GetHealth() < health)
			{
				Exit();
				return;
			}
			health = ((Character)localPlayer).GetHealth();
			ClampPosition(localPlayer);
			if (InventorySlots.InputAllowed && (!((Object)(object)Hud.instance != (Object)null) || !((Object)(object)Hud.instance.m_buildUi != (Object)null) || !Hud.instance.m_buildUi.SearchFieldFocused))
			{
				Vector2 val = ZInput.GetMouseDelta() * PlayerController.m_mouseSens * Plugin.Settings.Percent("BuildCamera.2 - Movement", "MouseSensitivity");
				if (PlayerController.m_invertMouse)
				{
					val.y = 0f - val.y;
				}
				if (ZInput.IsGamepadActive() && !ZInput.GetButton("JoyRotate"))
				{
					val.x += ZInput.GetJoyRightStickX() * 110f * Time.unscaledDeltaTime * PlayerController.m_gamepadSens * (float)((!PlayerController.m_invertCameraX) ? 1 : (-1));
					val.y -= ZInput.GetJoyRightStickY() * 110f * Time.unscaledDeltaTime * PlayerController.m_gamepadSens * (float)((!PlayerController.m_invertCameraY) ? 1 : (-1));
				}
				yaw = Mathf.Repeat(yaw + val.x, 360f);
				pitch = Mathf.Clamp(pitch - val.y, -89f, 89f);
				Quaternion val2 = Quaternion.Euler(pitch, yaw, 0f);
				Vector3 val3 = val2 * Vector3.forward;
				if (Plugin.Settings.On("BuildCamera.2 - Movement", "HorizontalMovement"))
				{
					val3 = Quaternion.Euler(0f, yaw, 0f) * Vector3.forward;
				}
				Vector3 val4 = val3 * (float)((ZInput.GetButton("Forward") ? 1 : 0) - (ZInput.GetButton("Backward") ? 1 : 0));
				val4 += val2 * Vector3.right * (float)((ZInput.GetButton("Right") ? 1 : 0) - (ZInput.GetButton("Left") ? 1 : 0));
				val4 += Vector3.up * (float)((ZInput.GetButton("Jump") ? 1 : 0) - (ZInput.GetButton("Crouch") ? 1 : 0));
				if (ZInput.IsGamepadActive())
				{
					Vector2 joyLeftStick = ZInput.GetJoyLeftStick();
					val4 += val3 * joyLeftStick.y + val2 * Vector3.right * joyLeftStick.x;
				}
				float num = Plugin.Settings.Get<float>("BuildCamera.2 - Movement", "Speed") * (ZInput.GetButton("Run") ? Plugin.Settings.Percent("BuildCamera.2 - Movement", "RunMultiplier") : 1f);
				position += Vector3.ClampMagnitude(val4, 1f) * num * Time.unscaledDeltaTime;
				ClampPosition(localPlayer);
			}
		}

		private static void ClampPosition(Player p)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)((Character)p).m_eye != (Object)null) ? ((Character)p).m_eye.position : ((Component)p).transform.position);
			position = val + Vector3.ClampMagnitude(position - val, Plugin.Settings.Get<float>("BuildCamera.3 - Limits", "MaxDistance"));
			RaycastHit val2 = default(RaycastHit);
			if (Plugin.Settings.On("BuildCamera.3 - Limits", "StayAboveGround") && Physics.Raycast(position + Vector3.up * 100f, Vector3.down, ref val2, 200f, LayerMask.GetMask(new string[1] { "terrain" })))
			{
				position.y = Mathf.Max(position.y, ((RaycastHit)(ref val2)).point.y + 0.2f);
			}
		}

		private static bool Camera(GameCamera __instance)
		{
			//IL_0022: 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)
			if (!active)
			{
				return true;
			}
			if (!CanStay(Player.m_localPlayer))
			{
				Exit();
				return true;
			}
			((Component)__instance).transform.SetPositionAndRotation(position, Quaternion.Euler(pitch, yaw, 0f));
			Camera component = ((Component)__instance).GetComponent<Camera>();
			if ((Object)(object)component != (Object)null)
			{
				if ((Object)(object)drivenCamera != (Object)(object)component)
				{
					RestoreClip();
					drivenCamera = component;
					nearClip = component.nearClipPlane;
				}
				component.nearClipPlane = __instance.m_nearClipPlaneMin;
			}
			return false;
		}

		private static bool Controls(PlayerController __instance)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			Player component = ((Component)__instance).GetComponent<Player>();
			if (!Applies(component))
			{
				return true;
			}
			float num = (float)AccessTools.Field(typeof(PlayerController), "takeInputDelay").GetValue(null);
			AccessTools.Field(typeof(PlayerController), "takeInputDelay").SetValue(null, Mathf.Max(0f, num - Time.deltaTime));
			Fields.Set(component, "m_autoRun", false);
			component.SetControls(Vector3.zero, false, false, false, false, false, false, false, false, false, false, false);
			return false;
		}

		private static bool Look(PlayerController __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Player component = ((Component)__instance).GetComponent<Player>();
			if (!Applies(component))
			{
				return true;
			}
			component.SetMouseLook(Vector2.zero);
			return false;
		}

		private static bool Listener(GameCamera __instance)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!active)
			{
				return true;
			}
			AudioListener val = Fields.Get<AudioListener>(__instance, "m_listner");
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).transform.localPosition = Vector3.zero;
			}
			return false;
		}

		private static void Sailing(float dt, ref Vector3 pos)
		{
			if (active || !Plugin.Settings.On("Interface", "Raise Sailing Camera"))
			{
				sailOffset = 0f;
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			Ship val = ((localPlayer != null) ? localPlayer.GetControlledShip() : null);
			float num = 0f;
			if ((Object)(object)val != (Object)null)
			{
				num = ((Object)((Component)val).gameObject).name.Replace("(Clone)", "") switch
				{
					"VikingShip_Ashlands" => 5, 
					"VikingShip" => 4, 
					"Karve" => 3, 
					"Raft" => 2, 
					_ => 0, 
				};
			}
			sailOffset = Mathf.Lerp(sailOffset, num, Mathf.Clamp01(dt * 2f));
			pos.y += sailOffset;
		}

		private static void Placement(Player __instance, out float __state)
		{
			__state = __instance.m_maxPlaceDistance;
			if (Applies(__instance))
			{
				__instance.m_maxPlaceDistance = 1000f;
			}
		}

		private static Exception RestorePlacement(Player __instance, float __state, Exception __exception)
		{
			if (__instance.m_maxPlaceDistance == 1000f)
			{
				__instance.m_maxPlaceDistance = __state;
			}
			return __exception;
		}

		private static void Reach(Player __instance, ref bool __result, Vector3 point)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (Applies(__instance) && __result)
			{
				GameObject val = Fields.Get<GameObject>(__instance, "m_placementGhost");
				float num = ((!((Object)(object)val == (Object)null)) ? (val.GetComponent<Piece>()?.m_extraPlacementDistance ?? 0) : 0);
				if (Vector3.Distance(position, point) > Plugin.Settings.Get<float>("BuildCamera.3 - Limits", "PlacementReach") + num)
				{
					__result = false;
				}
			}
		}

		private static bool RemovalReach(Player player)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if ((Object)(object)GameCamera.instance != (Object)null && Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, Plugin.Settings.Get<float>("BuildCamera.3 - Limits", "PlacementReach"), Fields.Get<int>(player, "m_removeRayMask")))
			{
				return ((RaycastHit)(ref val)).distance <= Plugin.Settings.Get<float>("BuildCamera.3 - Limits", "PlacementReach");
			}
			return false;
		}

		private static bool Hover(Player __instance, out float __state)
		{
			__state = __instance.m_maxPlaceDistance;
			if (!Applies(__instance))
			{
				return true;
			}
			if (!RemovalReach(__instance))
			{
				Fields.Set(__instance, "m_hoveringPiece", null);
				return false;
			}
			__instance.m_maxPlaceDistance = 1000f;
			return true;
		}

		private static bool Removal(Player __instance, ref bool __result, out float __state)
		{
			__state = __instance.m_maxPlaceDistance;
			if (!Applies(__instance))
			{
				return true;
			}
			if (!RemovalReach(__instance))
			{
				__result = false;
				return false;
			}
			__instance.m_maxPlaceDistance = 1000f;
			return true;
		}

		private static void BuildStation(Player __instance, RequirementMode mode, out Vector3? __state)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			__state = stationPoint;
			stationPoint = null;
			if (Applies(__instance) && (int)mode == 0 && Plugin.Settings.On("BuildCamera.3 - Limits", "WorkbenchNearPiece"))
			{
				GameObject val = Fields.Get<GameObject>(__instance, "m_placementGhost");
				if ((Object)(object)val != (Object)null)
				{
					stationPoint = val.transform.position;
				}
			}
		}

		private static void RemoveStation(Player __instance, Piece piece, out Vector3? __state)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			__state = stationPoint;
			stationPoint = null;
			if (Applies(__instance) && (Object)(object)piece != (Object)null && Plugin.Settings.On("BuildCamera.3 - Limits", "WorkbenchNearPiece"))
			{
				stationPoint = ((Component)piece).transform.position;
			}
		}

		private static void Station(ref Vector3 point)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (stationPoint.HasValue)
			{
				point = stationPoint.Value;
			}
		}

		private static Exception RestoreStation(Vector3? __state, Exception __exception)
		{
			stationPoint = __state;
			return __exception;
		}

		private static void RestoreClip()
		{
			if ((Object)(object)drivenCamera != (Object)null)
			{
				drivenCamera.nearClipPlane = nearClip;
			}
			drivenCamera = null;
		}

		private static void Damaged(Player __instance)
		{
			if (Applies(__instance) && Plugin.Settings.On("BuildCamera.3 - Limits", "ExitWhenHit"))
			{
				Exit();
			}
		}

		internal static void Exit()
		{
			RestoreClip();
			active = false;
			owner = null;
			stationPoint = null;
		}
	}
	internal static class CarryWeight
	{
		private struct BaseScope
		{
			internal bool Changed;

			internal float Original;

			internal float Written;
		}

		internal static void Install(PatchRegistry patches)
		{
			patches.Add(typeof(Player), "GetMaxCarryWeight", Type.EmptyTypes, typeof(CarryWeight), "Begin", null, "End");
			patches.Add(typeof(SE_Stats), "ModifyMaxCarryWeight", new Type[2]
			{
				typeof(float),
				typeof(float).MakeByRefType()
			}, typeof(CarryWeight), "Bonus");
		}

		private static void Begin(Player __instance, out BaseScope __state)
		{
			__state = default(BaseScope);
			Settings settings = Plugin.Settings;
			__state = new BaseScope
			{
				Changed = true,
				Original = __instance.m_maxCarryWeight,
				Written = settings.Get<float>("Player", "baseMaximumWeight")
			};
			__instance.m_maxCarryWeight = __state.Written;
		}

		private static Exception End(Player __instance, BaseScope __state, Exception __exception)
		{
			if (__state.Changed && __instance.m_maxCarryWeight == __state.Written)
			{
				__instance.m_maxCarryWeight = __state.Original;
			}
			return __exception;
		}

		private static bool Bonus(SE_Stats __instance, ref float limit)
		{
			if (__instance.m_addMaxCarryWeight <= 0f)
			{
				return true;
			}
			float num = Plugin.Settings.Get<float>("Player", "baseMegingjordBuff") - 150f;
			limit = Mathf.Max(0f, limit + __instance.m_addMaxCarryWeight + num);
			return false;
		}
	}
	internal static class ContainerWindow
	{
		private static InventoryGui owner;

		private static ContainerWindowDrag handle;

		private static Vector2 initial;

		internal static RectTransform Root => owner?.m_container;

		internal static void Install(PatchRegistry p)
		{
			p.Add(typeof(InventoryGui), "UpdateContainer", new Type[1] { typeof(Player) }, typeof(ContainerWindow), null, "Update");
			p.Add(typeof(InventoryGui), "OnDestroy", Type.EmptyTypes, typeof(ContainerWindow), "Destroyed");
		}

		private static void Update(InventoryGui __instance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			if (!((Component)__instance.m_container).gameObject.activeInHierarchy || Plugin.Settings == null)
			{
				return;
			}
			if ((Object)(object)owner != (Object)(object)__instance)
			{
				Close();
				owner = __instance;
				initial = owner.m_container.anchoredPosition;
				handle = ((Component)owner.m_container).gameObject.AddComponent<ContainerWindowDrag>();
			}
			if (!handle.Dragging)
			{
				if (!InventorySlots.Active)
				{
					owner.m_container.anchoredPosition = initial;
					return;
				}
				Vector2 val = Plugin.Settings.Get<Vector2>("Equipment.Container Window", "Container Position");
				Matrix4x4 val2 = SlotPanel.LayoutMatrix(((Transform)owner.m_container).parent, owner);
				Matrix4x4 val3 = ((Matrix4x4)(ref val2)).inverse * SlotPanel.LayoutMatrix((Transform)(object)owner.m_player, owner);
				Matrix4x4 val4 = ((Matrix4x4)(ref val2)).inverse * SlotPanel.LayoutMatrix((Transform)(object)owner.m_container, owner);
				Rect rect = owner.m_player.rect;
				float y = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(Vector2.op_Implicit(((Rect)(ref rect)).min)).y;
				rect = owner.m_container.rect;
				float xMin = ((Rect)(ref rect)).xMin;
				rect = owner.m_container.rect;
				float y2 = ((Matrix4x4)(ref val4)).MultiplyPoint3x4(Vector2.op_Implicit(new Vector2(xMin, ((Rect)(ref rect)).yMax))).y;
				Vector2 val5 = owner.m_container.anchoredPosition + Vector2.up * (y - 12f - y2);
				SetPosition((val == Vector2.zero) ? val5 : val);
			}
		}

		internal static void SetPosition(Vector2 position)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			RectTransform root = Root;
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			root.anchoredPosition = position;
			Transform parent = ((Transform)owner.m_player).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Matrix4x4 val2 = SlotPanel.LayoutMatrix((Transform)(object)root, owner);
			Rect rect = root.rect;
			Vector2 val3 = Vector2.op_Implicit(((Matrix4x4)(ref val2)).MultiplyPoint3x4(Vector2.op_Implicit(((Rect)(ref rect)).min)));
			rect = root.rect;
			Vector2 val4 = Vector2.op_Implicit(((Matrix4x4)(ref val2)).MultiplyPoint3x4(Vector2.op_Implicit(((Rect)(ref rect)).max)));
			float x = val3.x;
			rect = val.rect;
			float num;
			if (!(x < ((Rect)(ref rect)).xMin))
			{
				float x2 = val4.x;
				rect = val.rect;
				if (!(x2 > ((Rect)(ref rect)).xMax))
				{
					num = 0f;
				}
				else
				{
					rect = val.rect;
					num = ((Rect)(ref rect)).xMax - val4.x;
				}
			}
			else
			{
				rect = val.rect;
				num = ((Rect)(ref rect)).xMin - val3.x;
			}
			float y = val3.y;
			rect = val.rect;
			float num2;
			if (!(y < ((Rect)(ref rect)).yMin))
			{
				float y2 = val4.y;
				rect = val.rect;
				if (!(y2 > ((Rect)(ref rect)).yMax))
				{
					num2 = 0f;
				}
				else
				{
					rect = val.rect;
					num2 = ((Rect)(ref rect)).yMax - val4.y;
				}
			}
			else
			{
				rect = val.rect;
				num2 = ((Rect)(ref rect)).yMin - val3.y;
			}
			Vector2 val5 = default(Vector2);
			((Vector2)(ref val5))..ctor(num, num2);
			Vector2 anchoredPosition = root.anchoredPosition;
			Matrix4x4 val6 = SlotPanel.LayoutMatrix(((Transform)root).parent, owner);
			val6 = ((Matrix4x4)(ref val6)).inverse;
			root.anchoredPosition = anchoredPosition + Vector2.op_Implicit(((Matrix4x4)(ref val6)).MultiplyVector(Vector2.op_Implicit(val5)));
		}

		private static void Destroyed(InventoryGui __instance)
		{
			if ((Object)(object)owner == (Object)(object)__instance)
			{
				Close();
			}
		}

		internal static void Close()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)owner != (Object)null)
			{
				owner.m_container.anchoredPosition = initial;
			}
			if ((Object)(object)handle != (Object)null)
			{
				Object.Destroy((Object)(object)handle);
			}
			owner = null;
			handle = null;
		}
	}
	internal sealed class ContainerWindowDrag : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
	{
		internal bool Dragging;

		private Vector2 start;

		private Vector2 origin;

		private static bool Modifier()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut val = Plugin.Settings.Get<KeyboardShortcut>("Equipment.Container Window", "Container Drag Key");
			if ((int)((KeyboardShortcut)(ref val)).MainKey != 0)
			{
				return ((KeyboardShortcut)(ref val)).IsPressed();
			}
			return true;
		}

		private static bool Background(PointerEventData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			RaycastResult pointerPressRaycast = data.pointerPressRaycast;
			if (!((Object)(object)((RaycastResult)(ref pointerPressRaycast)).gameObject == (Object)null))
			{
				pointerPressRaycast = data.pointerPressRaycast;
				if ((Object)(object)((RaycastResult)(ref pointerPressRaycast)).gameObject.GetComponentInParent<InventoryGrid>() == (Object)null)
				{
					pointerPressRaycast = data.pointerPressRaycast;
					return (Object)(object)((RaycastResult)(ref pointerPressRaycast)).gameObject.GetComponentInParent<Selectable>() == (Object)null;
				}
				return false;
			}
			return true;
		}

		private static bool Point(PointerEventData data, out Vector2 point)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			return RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)((Transform)ContainerWindow.Root).parent, data.position, data.pressEventCamera, ref point);
		}

		public void OnBeginDrag(PointerEventData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if ((int)data.button == 0 && Background(data) && Modifier() && Plugin.Settings.On("Equipment.Container Window", "Container Draggable") && Point(data, out start))
			{
				origin = ContainerWindow.Root.anchoredPosition;
				Dragging = true;
			}
		}

		public void OnDrag(PointerEventData data)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (Dragging && Point(data, out var point))
			{
				ContainerWindow.SetPosition(origin + point - start);
			}
		}

		public void OnEndDrag(PointerEventData data)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (Dragging)
			{
				Dragging = false;
				Plugin.Settings.SetLocal<Vector2>("Equipment.Container Window", "Container Position", ContainerWindow.Root.anchoredPosition);
			}
		}

		public void OnPointerClick(PointerEventData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((int)data.button == 1 && Background(data) && Modifier())
			{
				Plugin.Settings.SetLocal<Vector2>("Equipment.Container Window", "Container Position", Vector2.zero);
			}
		}

		private void OnDisable()
		{
			Dragging = false;
		}
	}
	internal static class ControlOverrides
	{
		private static string lastControls;

		private static ZInput lastInput;

		internal static void Install(PatchRegistry patches)
		{
			patches.Add(typeof(ZInput), "Load", Type.EmptyTypes, typeof(ControlOverrides), null, "Loaded");
		}

		private static void Loaded()
		{
			lastInput = null;
			Refresh();
		}

		internal static void Refresh()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			Settings settings = Plugin.Settings;
			if (settings == null || ZInput.instance == null)
			{
				return;
			}
			bool flag = settings.On("Controls", "Override Controls");
			HashSet<KeyCode> hashSet = new HashSet<KeyCode>();
			KeyboardShortcut val;
			if (InventorySlots.Active && settings.On("Equipment.Toggles", "Enable Quick Slots"))
			{
				for (int i = 1; i <= settings.Get<int>("Equipment.Quick Slots", "Quick Slot Count"); i++)
				{
					val = settings.Get<KeyboardShortcut>("Equipment.Hotkeys", "Quick slot hotkey " + i);
					hashSet.Add(((KeyboardShortcut)(ref val)).MainKey);
				}
			}
			if (InventorySlots.Active && settings.On("Equipment.Equipment Panel", "Equipment Panel Draggable"))
			{
				val = settings.Get<KeyboardShortcut>("Equipment.Equipment Panel", "Equipment Panel Drag Key");
				hashSet.Add(((KeyboardShortcut)(ref val)).MainKey);
			}
			if (settings.On("Interface", "Drag Ammo Slot Panel"))
			{
				val = settings.Get<KeyboardShortcut>("Interface", "Ammo Slot Panel Drag Key");
				hashSet.Add(((KeyboardShortcut)(ref val)).MainKey);
			}
			if (settings.On("Equipment.Container Window", "Container Draggable"))
			{
				val = settings.Get<KeyboardShortcut>("Equipment.Container Window", "Container Drag Key");
				hashSet.Add(((KeyboardShortcut)(ref val)).MainKey);
			}
			if (settings.On("Recycling", "Enabled"))
			{
				hashSet.Add(settings.Get<KeyCode>("Recycling", "DiscardHotkey"));
			}
			hashSet.Remove((KeyCode)0);
			string text = flag + ":" + string.Join(",", hashSet.OrderBy((KeyCode k) => k));
			if (lastInput == ZInput.instance && lastControls == text)
			{
				return;
			}
			lastInput = ZInput.instance;
			lastControls = text;
			if (flag)
			{
				MethodInfo pathMethod = typeof(ZInput).GetMethod("KeyCodeToPath", BindingFlags.Static | BindingFlags.NonPublic);
				HashSet<string> paths = new HashSet<string>(hashSet.Select((KeyCode k) => (string)pathMethod.Invoke(null, new object[2] { k, false })), StringComparer.OrdinalIgnoreCase);
				ButtonDef[] array = Fields.Get<Dictionary<string, ButtonDef>>(ZInput.instance, "m_buttons").Values.Where((ButtonDef b) => b.Rebindable && paths.Contains(b.GetActionPath(true))).ToArray();
				foreach (ButtonDef val2 in array)
				{
					val2.Rebind(string.Empty);
					PlatformPrefs.SetString("kbmBinding_" + val2.Name, string.Empty);
				}
			}
		}

		internal static void Close()
		{
			lastControls = null;
			lastInput = null;
		}
	}
	internal static class CosmeticArmor
	{
		private const string HiddenHelmetKey = "torubaki.bettertweaks.hideHelmet";

		private const string HiddenCapeKey = "torubaki.bettertweaks.hideCape";

		private static readonly ItemType[] Types;

		internal static bool CapeButtonEnabled => Plugin.Settings.On("Interface", "Hide Cape Button");

		internal static bool ButtonEnabled => Plugin.Settings.On("Interface", "Hide Helmet Button");

		internal static bool HelmetHidden(Player player)
		{
			if ((Object)(object)player != (Object)null && ButtonEnabled && InventorySlots.EquipmentFor(player) && player.m_customData.TryGetValue("torubaki.bettertweaks.hideHelmet", out var value))
			{
				return value == "true";
			}
			return false;
		}

		internal static bool CapeHidden(Player player)
		{
			if ((Object)(object)player != (Object)null && CapeButtonEnabled && InventorySlots.EquipmentFor(player) && player.m_customData.TryGetValue("torubaki.bettertweaks.hideCape", out var value))
			{
				return value == "true";
			}
			return false;
		}

		internal static void ToggleCape(Player player)
		{
			if (!((Object)(object)player == (Object)null) && CapeButtonEnabled && InventorySlots.EquipmentFor(player))
			{
				if (CapeHidden(player))
				{
					player.m_customData.Remove("torubaki.bettertweaks.hideCape");
				}
				else
				{
					player.m_customData["torubaki.bettertweaks.hideCape"] = "true";
				}
				Changed(player);
			}
		}

		internal static void Loaded(Player player)
		{
			if (!ButtonEnabled)
			{
				player.m_customData.Remove("torubaki.bettertweaks.hideHelmet");
			}
			if (!CapeButtonEnabled)
			{
				player.m_customData.Remove("torubaki.bettertweaks.hideCape");
			}
		}

		internal static void ToggleHelmet(Player player)
		{
			if (!((Object)(object)player == (Object)null) && ButtonEnabled && InventorySlots.EquipmentFor(player))
			{
				if (HelmetHidden(player))
				{
					player.m_customData.Remove("torubaki.bettertweaks.hideHelmet");
				}
				else
				{
					player.m_customData["torubaki.bettertweaks.hideHelmet"] = "true";
				}
				Changed(player);
			}
		}

		internal static bool IsSlot(int slot)
		{
			if (slot >= 24)
			{
				return slot < 28;
			}
			return false;
		}

		internal static bool Matches(ItemData item, int slot)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			if (item != null && IsSlot(slot))
			{
				return (int)item.m_shared.m_itemType == (int)Types[slot - 24];
			}
			return false;
		}

		internal static bool Allows(Player player, ItemData item, Vector2i position)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			if (InventorySlots.CosmeticsFor(player) && position.x >= 0 && position.x < 8)
			{
				return Matches(item, (position.y - InventorySlots.PositionFor(player, 0).y) * 8 + position.x);
			}
			return false;
		}

		internal static void Install(PatchRegistry patches)
		{
			patches.Add(typeof(Humanoid), "SetupVisEquipment", new Type[2]
			{
				typeof(VisEquipment),
				typeof(bool)
			}, typeof(CosmeticArmor), null, "Visuals");
			patches.Add(typeof(Player), "OnInventoryChanged", Type.EmptyTypes, typeof(CosmeticArmor), null, "Changed");
			patches.Add(typeof(Inventory), "UpdateTotalWeight", Type.EmptyTypes, typeof(CosmeticArmor), null, "Weight");
		}

		private static ItemData Display(Player player, int slot, string regular)
		{
			ItemData val = (InventorySlots.CosmeticsFor(player) ? InventorySlots.At(player, slot) : null);
			if (!Matches(val, slot))
			{
				return Fields.Get<ItemData>(player, regular);
			}
			return val;
		}

		private static int Hash(ItemData item)
		{
			if (!((Object)(object)item?.m_dropPrefab == (Object)null))
			{
				return StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name);
			}
			return 0;
		}

		private static void Visuals(Humanoid __instance, VisEquipment visEq)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && !((Object)(object)visEq == (Object)null) && !((Object)(object)InventorySlots.Owner(((Humanoid)val).GetInventory()) == (Object)null))
			{
				ItemData item = Display(val, 24, "m_helmetItem");
				ItemData item2 = Display(val, 25, "m_chestItem");
				ItemData item3 = Display(val, 26, "m_legItem");
				ItemData val2 = Display(val, 27, "m_shoulderItem");
				visEq.SetHelmetItem((!HelmetHidden(val)) ? Hash(item) : 0);
				visEq.SetChestItem(Hash(item2));
				visEq.SetLegItem(Hash(item3));
				visEq.SetShoulderItem((!CapeHidden(val)) ? Hash(val2) : 0, val2?.m_variant ?? 0, val2?.m_quality ?? 0);
			}
		}

		private static void Changed(Player __instance)
		{
			if (!((Object)(object)InventorySlots.Owner(((Humanoid)__instance).GetInventory()) == (Object)null))
			{
				ZNetView val = Fields.Get<ZNetView>(__instance, "m_nview");
				if (!((Object)(object)val == (Object)null) && (val.GetZDO() == null || val.IsOwner()))
				{
					Visuals((Humanoid)(object)__instance, Fields.Get<VisEquipment>(__instance, "m_visEquipment"));
				}
			}
		}

		private static void Weight(Inventory __instance)
		{
			Player player = InventorySlots.Owner(__instance);
			if (!((Object)(object)player == (Object)null) && InventorySlots.CosmeticsFor(player))
			{
				Fields.Set(__instance, "m_totalWeight", Fields.Get<float>(__instance, "m_totalWeight") - (from i in __instance.GetAllItems()
					where Matches(i, InventorySlots.SlotFor(player, i))
					select i).Sum((ItemData i) => i.GetWeight(-1)));
			}
		}

		static CosmeticArmor()
		{
			ItemType[] array = new ItemType[4];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Types = (ItemType[])(object)array;
		}
	}
	internal static class CraftingStations
	{
		private static readonly HashSet<CraftingStation> stations = new HashSet<CraftingStation>();

		private static readonly HashSet<StationExtension> extensions = new HashSet<StationExtension>();

		private static bool restoring;

		private static readonly OwnedOverrides overrides = new OwnedOverrides();

		internal static void Install(PatchRegistry patches)
		{
			patches.Add(typeof(CraftingStation), "Start", Type.EmptyTypes, typeof(CraftingStations), null, "Ready");
			patches.Add(typeof(StationExtension), "Awake", Type.EmptyTypes, typeof(CraftingStations), null, "Extension");
			patches.Add(typeof(CraftingStation), "GetExtensions", Type.EmptyTypes, typeof(CraftingStations), null, "SpawnRadius");
			patches.Add(typeof(ZNetScene), "Awake", Type.EmptyTypes, typeof(CraftingStations), null, "CompactSpacing");
		}

		private static void Ready(CraftingStation __instance)
		{
			stations.Add(__instance);
			Configure(__instance);
		}

		private static void Configure(CraftingStation station)
		{
			overrides.Set(station, "m_rangeBuild", () => station.m_rangeBuild, delegate(float value)
			{
				station.m_rangeBuild = value;
			}, Plugin.Settings.Get<float>("Workbench", "workbenchRange"));
			if (Plugin.Settings.On("Workbench", "disableRoofCheck"))
			{
				overrides.Set(station, "m_craftRequireRoof", () => station.m_craftRequireRoof, delegate(bool value)
				{
					station.m_craftRequireRoof = value;
				}, value: false);
			}
		}

		private static void Extension(StationExtension __instance)
		{
			extensions.Add(__instance);
			overrides.Set(__instance, "m_maxStationDistance", () => __instance.m_maxStationDistance, delegate(float value)
			{
				__instance.m_maxStationDistance = value;
			}, Plugin.Settings.Get<float>("Workbench", "workbenchAttachmentRange"));
		}

		private static void SpawnRadius(CraftingStation __instance)
		{
			if (restoring)
			{
				return;
			}
			float num = Plugin.Settings.Get<float>("Workbench", "workbenchEnemySpawnRange");
			if (num <= 0f)
			{
				return;
			}
			Collider effectAreaCollider = __instance.m_effectAreaCollider;
			SphereCollider val = (SphereCollider)(object)((effectAreaCollider is SphereCollider) ? effectAreaCollider : null);
			if (val != null)
			{
				val.radius = num;
				return;
			}
			Collider effectAreaCollider2 = __instance.m_effectAreaCollider;
			CapsuleCollider val2 = (CapsuleCollider)(object)((effectAreaCollider2 is CapsuleCollider) ? effectAreaCollider2 : null);
			if (val2 != null)
			{
				val2.radius = num;
			}
		}

		private static void CompactSpacing()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null || !Plugin.Settings.Tweak("Station Extensions Changes"))
			{
				return;
			}
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				Piece piece = prefab.GetComponent<Piece>();
				if ((Object)(object)piece != (Object)null && piece.m_spaceRequirement >= 2f)
				{
					overrides.Set(piece, "m_spaceRequirement", () => piece.m_spaceRequirement, delegate(float value)
					{
						piece.m_spaceRequirement = value;
					}, 1f);
				}
			}
		}

		private static void RefreshStations(bool restore)
		{
			stations.RemoveWhere((CraftingStation station) => (Object)(object)station == (Object)null);
			extensions.RemoveWhere((StationExtension extension) => (Object)(object)extension == (Object)null);
			restoring = restore;
			try
			{
				if (!restore)
				{
					StationExtension[] array = extensions.ToArray();
					for (int num = 0; num < array.Length; num++)
					{
						Extension(array[num]);
					}
				}
				CraftingStation[] array2 = stations.ToArray();
				foreach (CraftingStation val in array2)
				{
					if (!restore)
					{
						Configure(val);
					}
					Fields.Set(val, "m_updateExtensionTimer", 2f);
					Fields.Call(val, "GetExtensions", Type.EmptyTypes);
				}
			}
			finally
			{
				restoring = false;
			}
		}

		internal static void Refresh()
		{
			overrides.Restore();
			CompactSpacing();
			RefreshStations(restore: false);
		}

		internal static void Close()
		{
			overrides.Restore();
			RefreshStations(restore: true);
			stations.Clear();
			extensions.Clear();
		}
	}
	internal static class CreatureLoot
	{
		private static readonly HashSet<ZDO> spawningLoot = new HashSet<ZDO>();

		internal static void Install(PatchRegistry p)
		{
			p.Add(typeof(Ragdoll), "Start", Type.EmptyTypes, typeof(CreatureLoot), null, "EarlyLoot");
			p.Add(typeof(Ragdoll), "FixedUpdate", Type.EmptyTypes, typeof(CreatureLoot), null, "EarlyLoot");
			p.Add(typeof(Ragdoll), "SpawnLoot", new Type[1] { typeof(Vector3) }, typeof(CreatureLoot), "BeginLoot", null, "EndLoot");
		}

		private static void EarlyLoot(Ragdoll __instance)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Settings.On("Enemies", "Instant Loot Drops"))
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && component.GetZDO().GetInt(ZDOVars.s_drops, 0) > 0)
				{
					Fields.Call(__instance, "SpawnLoot", new Type[1] { typeof(Vector3) }, ((Component)__instance).transform.position);
				}
			}
		}

		private static bool BeginLoot(Ragdoll __instance, out ZDO __state)
		{
			__state = null;
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return false;
			}
			ZDO zDO = component.GetZDO();
			if (zDO.GetBool("torubaki.bettertweaks.loot.spawned.v1", false) || zDO.GetInt(ZDOVars.s_drops, 0) <= 0)
			{
				return false;
			}
			if (!spawningLoot.Add(zDO))
			{
				return false;
			}
			__state = zDO;
			return true;
		}

		private static Exception EndLoot(ZDO __state, bool __runOriginal, Exception __exception)
		{
			if (__state != null)
			{
				spawningLoot.Remove(__state);
			}
			if (__state != null && __runOriginal && __exception == null)
			{
				__state.Set("torubaki.bettertweaks.loot.spawned.v1", true);
				__state.Set(ZDOVars.s_drops, 0, false);
			}
			return __exception;
		}
	}
	internal static class EquipmentActions
	{
		internal const string LoadedKey = "torubaki.bettertweaks.crossbowLoaded";

		private static readonly Dictionary<Player, int> running = new Dictionary<Player, int>();

		private static readonly Dictionary<Player, int> unequipping = new Dictionary<Player, int>();

		private static bool Keep => Plugin.Settings.Tweak("Keep Crossbows Loaded");

		internal static void Install(PatchRegistry patches)
		{
			Type typeFromHandle = typeof(EquipmentActions);
			patches.Add(typeof(Player), "CheckRun", new Type[2]
			{
				typeof(Vector3),
				typeof(float)
			}, typeFromHandle, "BeginRun", null, "EndRun");
			patches.Add(typeof(Player), "ClearActionQueue", Type.EmptyTypes, typeFromHandle, "ClearQueue");
			patches.Add(typeof(Player), "InMinorActionSlowdown", Type.EmptyTypes, typeFromHandle, "Slowdown", "ReloadSlowdown");
			patches.Add(typeof(Player), "SetWeaponLoaded", new Type[1] { typeof(ItemData) }, typeFromHandle, null, "Loaded");
			patches.Add(typeof(Player), "ResetLoadedWeapon", Type.EmptyTypes, typeFromHandle, "BeforeReset", "AfterReset");
			patches.Add(typeof(Humanoid), "UnequipItem", new Type[2]
			{
				typeof(ItemData),
				typeof(bool)
			}, typeFromHandle, "BeginUnequip", null, "EndUnequip");
			patches.Add(typeof(Humanoid), "EquipItem", new Type[2]
			{
				typeof(ItemData),
				typeof(bool)
			}, typeFromHandle, null, "Equipped");
		}

		private static bool Crossbow(ItemData item)
		{
			if (item != null && item.m_shared.m_attack != null && item.m_shared.m_attack.m_requiresReload)
			{
				if (!(((object)Unsafe.As<AnimationState, AnimationState>(ref item.m_shared.m_animationState)/*cast due to .constrained prefix*/).ToString() == "Crossbow"))
				{
					return item.m_shared.m_name == "$item_graplinghook";
				}
				return true;
			}
			return false;
		}

		private static int Depth(Dictionary<Player, int> scope, Player player)
		{
			if (!scope.TryGetValue(player, out var value))
			{
				return 0;
			}
			return value;
		}

		private static void BeginRun(Player __instance)
		{
			running[__instance] = Depth(running, __instance) + 1;
		}

		private static void EndRun(Player __instance)
		{
			if (Depth(running, __instance) <= 1)
			{
				running.Remove(__instance);
			}
			else
			{
				running[__instance]--;
			}
		}

		private static bool ClearQueue(Player __instance)
		{
			if (Depth(running, __instance) == 0)
			{
				return true;
			}
			bool flag = Plugin.Settings.On("MovingEquipment", "Enabled");
			bool flag2 = Plugin.Settings.Tweak("Crossbow Reload While Moving") && Crossbow(((Humanoid)__instance).GetCurrentWeapon());
			if (!flag && !flag2)
			{
				return true;
			}
			IList list = Fields.Get<IList>(__instance, "m_actionQueue");
			for (int num = list.Count - 1; num >= 0; num--)
			{
				string text = Fields.Get<object>(list[num], "m_type").ToString();
				if ((!flag || (!(text == "Equip") && !(text == "Unequip"))) && (!flag2 || !(text == "Reload")))
				{
					list.RemoveAt(num);
				}
			}
			return false;
		}

		private static bool Slowdown(Player __instance, ref bool __result)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Settings.On("MovingEquipment", "Enabled") && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				if (!((Character)__instance).IsRunning())
				{
					Vector3 val = Fields.Get<Vector3>(__instance, "m_moveDir");
					if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
					{
						goto IL_0045;
					}
				}
				IList list = Fields.Get<IList>(__instance, "m_actionQueue");
				if (list.Count != 0)
				{
					string text = Fields.Get<object>(list[0], "m_type").ToString();
					if (text != "Equip" && text != "Unequip")
					{
						return true;
					}
				}
				__result = false;
				return false;
			}
			goto IL_0045;
			IL_0045:
			return true;
		}

		private static void ReloadSlowdown(Player __instance, ref bool __result)
		{
			if (__result && ((Character)__instance).IsRunning())
			{
				IList list = Fields.Get<IList>(__instance, "m_actionQueue");
				if (list.Count != 0 && Fields.Get<object>(list[0], "m_type").ToString() == "Reload" && Plugin.Settings.Tweak("Crossbow Reload While Moving") && Crossbow(Fields.Get<ItemData>(list[0], "m_item")))
				{
					__result = false;
				}
			}
		}

		private static void Loaded(Player __instance, ItemData __0)
		{
			if (Keep && Crossbow(__0))
			{
				__0.m_customData["torubaki.bettertweaks.crossbowLoaded"] = "1";
			}
		}

		private static void BeforeReset(Player __instance, out ItemData __state)
		{
			__state = Fields.Get<ItemData>(__instance, "m_weaponLoaded");
		}

		private static void AfterReset(Player __instance, ItemData __state)
		{
			if (__state != null && Depth(unequipping, __instance) == 0)
			{
				__state.m_customData.Remove("torubaki.bettertweaks.crossbowLoaded");
			}
		}

		private static void BeginUnequip(Humanoid __instance, ItemData __0, out Player __state)
		{
			__state = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)__state == (Object)null || !Keep || !Crossbow(__0))
			{
				__state = null;
				return;
			}
			if (Fields.Get<ItemData>(__state, "m_weaponLoaded") == __0)
			{
				__0.m_customData["torubaki.bettertweaks.crossbowLoaded"] = "1";
			}
			unequipping[__state] = Depth(unequipping, __state) + 1;
		}

		private static void EndUnequip(Player __state)
		{
			if (!((Object)(object)__state == (Object)null))
			{
				if (Depth(unequipping, __state) <= 1)
				{
					unequipping.Remove(__state);
				}
				else
				{
					unequipping[__state]--;
				}
			}
		}

		private static void Equipped(Humanoid __instance, ItemData __0, bool __result)
		{
			if (__result && Keep)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && Crossbow(__0) && __0.m_customData.TryGetValue("torubaki.bettertweaks.crossbowLoaded", out var value) && value == "1")
				{
					Fields.Call(val, "SetWeaponLoaded", new Type[1] { typeof(ItemData) }, __0);
				}
			}
		}

		internal static void Close()
		{
			running.Clear();
			unequipping.Clear();
		}
	}
	internal static class EquipmentRules
	{
		private sealed class Pending
		{
			internal ItemData Item;

			internal bool Equip;
		}

		private sealed class Hands
		{
			internal ItemData Left;

			internal ItemData Right;
		}

		private static readonly Dictionary<Player, List<Pending>> queued = new Dictionary<Player, List<Pending>>();

		private static readonly Dictionary<Player, Hands> swimming = new Dictionary<Player, Hands>();

		[ThreadStatic]
		private static Humanoid updating;

		[ThreadStatic]
		private static int automating;

		[ThreadStatic]
		private static int hiding;

		private static bool Enabled(string key)
		{
			return Plugin.Settings.Get<bool>("Player", key);
		}

		internal static void Install(PatchRegistry p)
		{
			p.Add(typeof(Player), "ToggleEquipped", new Type[1] { typeof(ItemData) }, typeof(EquipmentRules), "Queue");
			p.Add(typeof(Humanoid), "EquipItem", new Type[2]
			{
				typeof(ItemData),
				typeof(bool)
			}, typeof(EquipmentRules), null, "Equipped");
			p.Add(typeof(Humanoid), "UnequipItem", new Type[2]
			{
				typeof(ItemData),
				typeof(bool)
			}, typeof(EquipmentRules), null, "Unequipped");
			p.Add(typeof(Humanoid), "UpdateEquipment", new Type[1] { typeof(float) }, typeof(EquipmentRules), "UpdateEquipment", null, "EndUpdate");
			p.Add(typeof(Humanoid), "HideHandItems", new Type[2]
			{
				typeof(bool),
				typeof(bool)
			}, typeof(EquipmentRules), "Hide", "Hidden", "EndHide");
			p.Add(typeof(Humanoid), "ShowHandItems", new Type[2]
			{
				typeof(bool),
				typeof(bool)
			}, typeof(EquipmentRules), "Show");
		}

		private static bool Queue(Player __instance, ItemData __0, ref bool __result)
		{
			if (!Enabled("queueWeaponChanges") || !((Character)__instance).InAttack() || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || __0 == null || !__0.IsEquipable() || !((Humanoid)__instance).GetInventory().ContainsItem(__0))
			{
				return true;
			}
			if (!queued.TryGetValue(__instance, out var value))
			{
				queued.Add(__instance, value = new List<Pending>());
			}
			Pending pending = value.FirstOrDefault((Pending p) => p.Item == __0);
			bool flag = !(pending?.Equip ?? ((Humanoid)__instance).IsItemEquiped(__0));
			if (pending != null)
			{
				value.Remove(pending);
			}
			if (flag != ((Humanoid)__instance).IsItemEquiped(__0) && value.Count < 32)
			{
				value.Add(new Pending
				{
					Item = __0,
					Equip = flag
				});
			}
			__result = true;
			return false;
		}

		private static void Equipped(Humanoid __instance, ItemData __0, bool __result)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Invalid comparison between Unknown and I4
			if (!__result)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer || automating > 0 || hiding > 0 || __0 == null)
			{
				return;
			}
			if ((Object)(object)updating != (Object)(object)val)
			{
				swimming.Remove(val);
			}
			if (!Enabled("autoEquipShield") || (int)__0.m_shared.m_itemType != 3)
			{
				return;
			}
			ItemData obj = Fields.Get<ItemData>(val, "m_leftItem");
			if (obj != null && (int)obj.m_shared.m_itemType == 5)
			{
				return;
			}
			ItemData val2 = (from i in ((Humanoid)val).GetInventory().GetAllItems()
				where (int)i.m_shared.m_itemType == 5 && (!i.m_shared.m_useDurability || i.m_durability > 0f)
				orderby i.GetBaseBlockPower() descending
				select i).FirstOrDefault();
			if (val2 == null)
			{
				return;
			}
			automating++;
			try
			{
				((Humanoid)val).EquipItem(val2, false);
			}
			finally
			{
				automating--;
			}
		}

		private static void Unequipped(Humanoid __instance, ItemData __0)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Invalid comparison between Unknown and I4
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer || automating > 0 || hiding > 0 || !Enabled("autoUnequipShield") || __0 == null || (int)__0.m_shared.m_itemType != 3 || ((Humanoid)val).IsItemEquiped(__0))
			{
				return;
			}
			ItemData val2 = Fields.Get<ItemData>(val, "m_leftItem");
			if (val2 == null || (int)val2.m_shared.m_itemType != 5)
			{
				return;
			}
			automating++;
			try
			{
				((Humanoid)val).UnequipItem(val2, false);
			}
			finally
			{
				automating--;
			}
		}

		private static void UpdateEquipment(Humanoid __instance, out Humanoid __state)
		{
			__state = updating;
			updating = __instance;
		}

		private static Exception EndUpdate(Humanoid __state, Exception __exception)
		{
			updating = __state;
			return __exception;
		}

		private static bool Hide(Humanoid __instance, ref bool __result, out int __state)
		{
			__state = hiding;
			hiding++;
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if ((Object)(object)updating != (Object)(object)val)
			{
				swimming.Remove(val);
				return true;
			}
			if (!((Character)val).IsSwimming() || ((Character)val).IsOnGround())
			{
				return true;
			}
			if (Enabled("dontUnequipItemsWhenSwimming"))
			{
				__result = false;
				return false;
			}
			return true;
		}

		private static void Hidden(Humanoid __instance, bool __result)
		{
			if (__result)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Object)(object)updating != (Object)(object)val) && Enabled("reequipItemsAfterSwimming") && ((Character)val).IsSwimming())
				{
					swimming[val] = new Hands
					{
						Left = Fields.Get<ItemData>(val, "m_hiddenLeftItem"),
						Right = Fields.Get<ItemData>(val, "m_hiddenRightItem")
					};
				}
			}
		}

		private static Exception EndHide(int __state, Exception __exception)
		{
			hiding = __state;
			return __exception;
		}

		private static void Show(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && automating == 0)
			{
				swimming.Remove(val);
			}
		}

		internal static void Tick()
		{
			Player player = Player.m_localPlayer;
			Player[] array = queued.Keys.Where((Player p) => (Object)(object)p == (Object)null || (Object)(object)p != (Object)(object)player || ((Character)p).IsDead()).ToArray();
			foreach (Player key in array)
			{
				queued.Remove(key);
			}
			array = swimming.Keys.Where((Player p) => (Object)(object)p == (Object)null || (Object)(object)p != (Object)(object)player || ((Character)p).IsDead()).ToArray();
			foreach (Player key2 in array)
			{
				swimming.Remove(key2);
			}
			if ((Object)(object)player == (Object)null || ((Character)player).IsDead())
			{
				return;
			}
			if (!Enabled("queueWeaponChanges"))
			{
				queued.Clear();
			}
			if (!Enabled("reequipItemsAfterSwimming"))
			{
				swimming.Clear();
			}
			if (((Character)player).InAttack() || ((Character)player).InDodge() || ((Character)player).IsStaggering() || ((Character)player).IsKnockedBack() || ((Character)player).InMinorAction() || ((Character)player).IsTeleporting())
			{
				return;
			}
			if (queued.TryGetValue(player, out var value) && value.Count > 0)
			{
				Pending pending = value[0];
				value.RemoveAt(0);
				if (((Humanoid)player).GetInventory().ContainsItem(pending.Item) && ((Humanoid)player).IsItemEquiped(pending.Item) != pending.Equip)
				{
					Fields.Call(player, "ToggleEquipped", new Type[1] { typeof(ItemData) }, pending.Item);
				}
			}
			if (((Character)player).IsSwimming() || !((Character)player).IsOnGround() || !swimming.TryGetValue(player, out var value2))
			{
				return;
			}
			swimming.Remove(player);
			automating++;
			try
			{
				Restore(player, value2.Right, "m_hiddenRightItem");
				Restore(player, value2.Left, "m_hiddenLeftItem");
			}
			finally
			{
				automating--;
			}
		}

		private static void Restore(Player player, ItemData item, string field)
		{
			if (item != null && Fields.Get<ItemData>(player, field) == item && ((Humanoid)player).GetInventory().ContainsItem(item) && ((Humanoid)player).EquipItem(item, true))
			{
				Fields.Set(player, field, null);
			}
		}

		internal static void Close()
		{
			queued.Clear();
			swimming.Clear();
			updating = null;
			automating = (hiding = 0);
		}
	}
	internal static class EquipmentSlots
	{
		private sealed class Scope
		{
			internal Player Player;

			internal ItemData Item;

			internal ItemData Primary;

			internal ItemData Displaced;

			internal Vector2i Destination;

			internal Vector2i Return;

			internal bool Substituted;

			internal bool Restored;

			internal bool ReturnToInventory;
		}

		private static readonly FieldInfo Utility = typeof(Humanoid).GetField("m_utilityItem", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo[] Gear = new string[8] { "m_leftItem", "m_rightItem", "m_chestItem", "m_legItem", "m_helmetItem", "m_shoulderItem", "m_utilityItem", "m_trinketItem" }.Select((string n) => typeof(Humanoid).GetField(n, BindingFlags.Instance | BindingFlags.NonPublic)).ToArray();

		private static readonly Dictionary<Player, HashSet<ItemData>> active = new Dictionary<Player, HashSet<ItemData>>();

		private static readonly List<Scope> scopes = new List<Scope>();

		private static readonly Dictionary<ItemData, (Player Player, Vector2i Position)> unequipTargets = new Dictionary<ItemData, (Player, Vector2i)>();

		internal static void Install(PatchRegistry p)
		{
			if (Utility == null || Gear.Any((FieldInfo f) => f == null))
			{
				throw new MissingFieldException("Required Humanoid equipment fields are unavailable.");
			}
			LanternUtility.Install(p);
			UtilityVisuals.Install(p);
			Type typeFromHandle = typeof(EquipmentSlots);
			p.Add(typeof(Player), "RemoveEquipAction", new Type[1] { typeof(ItemData) }, typeFromHandle, null, "ClearUnequipTargets");
			p.Add(typeof(Player), "ClearActionQueue", Type.EmptyTypes, typeFromHandle, null, "Cle