Decompiled source of SmartCraftStorage v0.8.0

SmartCraftStorage.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using SmartCraftStorage.AnimalFeeder;
using SmartCraftStorage.Config;
using SmartCraftStorage.Hotkeys;
using SmartCraftStorage.Integrations;
using SmartCraftStorage.ItemMarking;
using SmartCraftStorage.PlantHarvest;
using SmartCraftStorage.QuickStack;
using SmartCraftStorage.Restock;
using SmartCraftStorage.Shared;
using SmartCraftStorage.Stations;
using SmartCraftStorage.Translations;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("SmartCraftStorage")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+156e8b08b1c8dd3b701f838ed0ffbdc94d31b0a5")]
[assembly: AssemblyProduct("SmartCraftStorage")]
[assembly: AssemblyTitle("SmartCraftStorage")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 SmartCraftStorage
{
	[BepInPlugin("com.zellds.smartcraftstorage", "SmartCraft-Storage", "0.8.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.zellds.smartcraftstorage";

		public const string PluginName = "SmartCraft-Storage";

		public const string PluginVersion = "0.8.0";

		internal static Harmony HarmonyInstance;

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			StationConfig.Bind(((BaseUnityPlugin)this).Config);
			AnimalFeederConfig.Bind(((BaseUnityPlugin)this).Config);
			HotkeyConfig.Bind(((BaseUnityPlugin)this).Config);
			PlantHarvestConfig.Bind(((BaseUnityPlugin)this).Config);
			ModTranslations.Setup();
			EpicLootProvider.Setup();
			HarmonyInstance = new Harmony("com.zellds.smartcraftstorage");
			HarmonyInstance.PatchAll();
			EpicLootSacrificeProtection.Setup(HarmonyInstance);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SmartCraft-Storage 0.8.0 loaded.");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "SmartCraftStorage";

		public const string PLUGIN_NAME = "SmartCraftStorage";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace SmartCraftStorage.Translations
{
	internal static class ModTranslations
	{
		public static void Setup()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["smartcraft_no_chest_nearby"] = "No chest nearby.",
				["smartcraft_quickstack_success"] = "Stashed $1 item(s) into nearby chests.",
				["smartcraft_quickstack_nothing"] = "Nothing to stash into nearby chests.",
				["smartcraft_restock_no_items_marked"] = "No items marked for restock.",
				["smartcraft_restock_success"] = "Restocked $1 item(s).",
				["smartcraft_restock_nothing"] = "Nothing to restock from nearby chests."
			});
			text = "Portuguese_Brazilian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["smartcraft_no_chest_nearby"] = "Nenhum baú próximo.",
				["smartcraft_quickstack_success"] = "Guardado(s) $1 item(ns) nos baús próximos.",
				["smartcraft_quickstack_nothing"] = "Nada pra guardar nos baús próximos.",
				["smartcraft_restock_no_items_marked"] = "Nenhum item marcado pra restock.",
				["smartcraft_restock_success"] = "Restock: $1 item(ns) repostos.",
				["smartcraft_restock_nothing"] = "Nada pra restockar nos baús próximos."
			});
			text = "Spanish";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["smartcraft_no_chest_nearby"] = "No hay ningún cofre cerca.",
				["smartcraft_quickstack_success"] = "Se guardaron $1 objeto(s) en cofres cercanos.",
				["smartcraft_quickstack_nothing"] = "No hay nada que guardar en cofres cercanos.",
				["smartcraft_restock_no_items_marked"] = "No hay objetos marcados para reabastecer.",
				["smartcraft_restock_success"] = "Reabastecido(s) $1 objeto(s).",
				["smartcraft_restock_nothing"] = "No hay nada que reabastecer desde cofres cercanos."
			});
		}
	}
}
namespace SmartCraftStorage.Stations
{
	internal static class BeehivePatches
	{
		[HarmonyPatch(typeof(Beehive), "UpdateBees")]
		private static class AutoCollectTriggerPatch
		{
			private static void Postfix(Beehive __instance)
			{
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (StationConfig.BeehiveAutoCollect.Value && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner())
					{
						int honeyLevel = __instance.GetHoneyLevel();
						if (honeyLevel > 0)
						{
							DebugLog.Log($"[SmartCraftStorage] Beehive: auto-trigger firing, honeyLevel={honeyLevel}, " + $"position={((Component)__instance).transform.position}");
							_autoTriggered = true;
							__instance.Extract();
							Game.instance.IncrementPlayerStat((PlayerStatType)76, (float)honeyLevel, false);
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		[HarmonyPatch(typeof(Beehive), "RPC_Extract")]
		private static class CollectRedirectPatch
		{
			private static bool Prefix(Beehive __instance, long caller)
			{
				//IL_00bb: 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_0315: Unknown result type (might be due to invalid IL or missing references)
				//IL_031a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0328: Unknown result type (might be due to invalid IL or missing references)
				//IL_032e: Unknown result type (might be due to invalid IL or missing references)
				//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0403: Unknown result type (might be due to invalid IL or missing references)
				//IL_040d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0412: Unknown result type (might be due to invalid IL or missing references)
				//IL_041a: Unknown result type (might be due to invalid IL or missing references)
				//IL_041f: Unknown result type (might be due to invalid IL or missing references)
				//IL_042f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0436: Unknown result type (might be due to invalid IL or missing references)
				//IL_043b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0440: Unknown result type (might be due to invalid IL or missing references)
				//IL_0448: Unknown result type (might be due to invalid IL or missing references)
				//IL_044a: Unknown result type (might be due to invalid IL or missing references)
				bool autoTriggered = _autoTriggered;
				_autoTriggered = false;
				try
				{
					if (!StationConfig.BeehiveAutoCollect.Value)
					{
						return true;
					}
					int honeyLevel = __instance.GetHoneyLevel();
					if (honeyLevel <= 0)
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						DebugLog.Log("[SmartCraftStorage] Beehive: RPC_Extract fired with no local " + $"player (autoTriggered={autoTriggered}), falling back to vanilla drop.");
						return true;
					}
					int num = 0;
					for (int i = 0; i < honeyLevel; i++)
					{
						num += Game.instance.ScaleDrops(__instance.m_honeyItem.m_itemData, 1);
					}
					int num2 = num;
					string name = __instance.m_honeyItem.m_itemData.m_shared.m_name;
					List<(Inventory, ItemData, int)> list = new List<(Inventory, ItemData, int)>();
					List<Container> list2 = new List<Container>(NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.BeehiveRadius.Value, localPlayer));
					DebugLog.Log($"[SmartCraftStorage] Beehive: RPC_Extract autoTriggered={autoTriggered}, " + $"honeyLevel={honeyLevel}, totalHoney={num}, foundContainers={list2.Count}, " + $"radius={StationConfig.BeehiveRadius.Value}, position={((Component)__instance).transform.position}");
					foreach (Container item in list2)
					{
						if (num2 <= 0)
						{
							break;
						}
						Inventory inventory = item.GetInventory();
						if (!NearbyContainers.HasRoomFor(inventory, name) || !NearbyContainers.TryClaimWriteAccess(item))
						{
							continue;
						}
						Dictionary<ItemData, int> dictionary = new Dictionary<ItemData, int>();
						foreach (ItemData allItem in inventory.GetAllItems())
						{
							if (allItem.m_shared.m_name == name)
							{
								dictionary[allItem] = allItem.m_stack;
							}
						}
						int num3 = inventory.CountItems(name, -1, true);
						inventory.AddItem(((Component)__instance.m_honeyItem).gameObject, num2);
						int num4 = inventory.CountItems(name, -1, true) - num3;
						if (num4 <= 0)
						{
							continue;
						}
						num2 -= num4;
						int num5 = 0;
						foreach (ItemData allItem2 in inventory.GetAllItems())
						{
							if (allItem2.m_shared.m_name != name)
							{
								continue;
							}
							dictionary.TryGetValue(allItem2, out var value);
							int num6 = allItem2.m_stack - value;
							if (num6 > 0)
							{
								int num7 = Mathf.Min(num6, num4 - num5);
								list.Add((inventory, allItem2, num7));
								num5 += num7;
								if (num5 >= num4)
								{
									break;
								}
							}
						}
					}
					DebugLog.Log($"[SmartCraftStorage] Beehive: after storage attempt, remaining={num2}, " + $"storedInto={list.Count} container(s), autoTriggered={autoTriggered}");
					if (num2 <= 0)
					{
						__instance.m_spawnEffect.Create(__instance.m_spawnPoint.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
						__instance.ResetLevel();
						DebugLog.Log("[SmartCraftStorage] Beehive: fully stored, no drop.");
						return false;
					}
					if (autoTriggered)
					{
						foreach (var (val, val2, num8) in list)
						{
							val.RemoveItem(val2, num8);
						}
						DebugLog.Log("[SmartCraftStorage] Beehive: auto-triggered, couldn't fit everything, rolled back partial storage, honey stays queued (no drop).");
						return false;
					}
					DebugLog.Log("[SmartCraftStorage] Beehive: NOT auto-triggered (manual path), " + $"dropping {num2} leftover on the ground.");
					__instance.m_spawnEffect.Create(__instance.m_spawnPoint.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
					for (int j = 0; j < num2; j++)
					{
						Vector2 val3 = Random.insideUnitCircle * 0.5f;
						Vector3 val4 = __instance.m_spawnPoint.position + new Vector3(val3.x, 0.25f * (float)j, val3.y);
						ItemDrop component = ((Component)Object.Instantiate<ItemDrop>(__instance.m_honeyItem, val4, Quaternion.identity)).GetComponent<ItemDrop>();
						component.SetStack(1);
						ItemDrop.OnCreateNew(component, false);
					}
					__instance.ResetLevel();
					return false;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					return true;
				}
			}
		}

		private static bool _autoTriggered;
	}
	internal static class CookingStationPatches
	{
		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		private static class RefuelPatch
		{
			private static void Postfix(CookingStation __instance)
			{
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					bool value = StationConfig.CookingStationAutoRefuel.Value;
					bool flag = (Object)(object)__instance.m_nview != (Object)null;
					bool flag2 = flag && __instance.m_nview.IsValid();
					bool flag3 = flag2 && __instance.m_nview.IsOwner();
					DebugLog.Log("[SmartCraftStorage] CookingStation.UpdateCooking: name=" + ((Object)__instance).name + ", " + $"position={((Component)__instance).transform.position}, configValue={value}, hasNview={flag}, " + $"nviewValid={flag2}, isOwner={flag3}");
					if (!StationConfig.CookingStationAutoRefuel.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
					{
						return;
					}
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)(object)localPlayer == (Object)null))
					{
						bool num = __instance.GetFreeSlot() != -1;
						bool flag4 = __instance.m_useFuel && (Object)(object)__instance.m_fuelItem != (Object)null && __instance.GetFuel() < (float)__instance.m_maxFuel;
						if (num || flag4)
						{
							List<Container> containers = new List<Container>(NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.CookingStationRadius.Value, localPlayer));
							RefuelFood(__instance, containers);
							RefuelFuel(__instance, containers);
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}

			private static void RefuelFood(CookingStation station, List<Container> containers)
			{
				while (station.GetFreeSlot() != -1)
				{
					bool flag = false;
					foreach (Container container in containers)
					{
						Inventory inventory = container.GetInventory();
						ItemData val = FindCookableItem(station, inventory);
						if (val != null && station.IsItemAllowed(((Object)val.m_dropPrefab).name) && NearbyContainers.TryClaimWriteAccess(container))
						{
							string name = ((Object)val.m_dropPrefab).name;
							bool cheated = val.m_cheated;
							if (UnlockedInventory.RemoveItem(inventory, val, 1) == 1)
							{
								station.m_nview.InvokeRPC("RPC_AddItem", new object[2] { name, cheated });
								flag = true;
								break;
							}
						}
					}
					if (!flag)
					{
						break;
					}
				}
			}

			private static void RefuelFuel(CookingStation station, List<Container> containers)
			{
				if (!station.m_useFuel || (Object)(object)station.m_fuelItem == (Object)null)
				{
					return;
				}
				string name = station.m_fuelItem.m_itemData.m_shared.m_name;
				while (station.GetFuel() < (float)station.m_maxFuel)
				{
					bool flag = false;
					foreach (Container container in containers)
					{
						Inventory inventory = container.GetInventory();
						ItemData val = UnlockedInventory.FindItem(inventory, name);
						if (val != null && NearbyContainers.TryClaimWriteAccess(container) && UnlockedInventory.RemoveItem(inventory, val, 1) == 1)
						{
							station.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						break;
					}
				}
			}

			private static ItemData FindCookableItem(CookingStation station, Inventory inventory)
			{
				foreach (ItemConversion item in station.m_conversion)
				{
					if (!((Object)(object)item.m_from == (Object)null))
					{
						ItemData val = UnlockedInventory.FindItem(inventory, item.m_from.m_itemData.m_shared.m_name);
						if (val != null)
						{
							return val;
						}
					}
				}
				return null;
			}
		}

		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		private static class AutoCollectTriggerPatch
		{
			private static void Postfix(CookingStation __instance)
			{
				try
				{
					if (!StationConfig.CookingStationAutoCollect.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
					{
						return;
					}
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)(object)localPlayer == (Object)null))
					{
						while (__instance.HaveDoneItem())
						{
							__instance.OnInteract((Humanoid)(object)localPlayer);
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		[HarmonyPatch(typeof(CookingStation), "SpawnItem")]
		private static class CollectRedirectPatch
		{
			private static bool Prefix(CookingStation __instance, string name, int slot, Vector3 userPoint, bool cheated)
			{
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!StationConfig.CookingStationAutoCollect.Value)
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
					if ((Object)(object)itemPrefab == (Object)null)
					{
						return true;
					}
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					if ((Object)(object)component == (Object)null)
					{
						return true;
					}
					string name2 = component.m_itemData.m_shared.m_name;
					foreach (Container item in NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.CookingStationRadius.Value, localPlayer))
					{
						Inventory inventory = item.GetInventory();
						if (NearbyContainers.HasRoomFor(inventory, name2) && NearbyContainers.TryClaimWriteAccess(item) && inventory.AddItem(itemPrefab, 1))
						{
							return false;
						}
					}
					return true;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					return true;
				}
			}
		}
	}
	internal static class FermenterPatches
	{
		[HarmonyPatch(typeof(Fermenter), "SlowUpdate")]
		private static class AutoProcessPatch
		{
			private static void Postfix(Fermenter __instance)
			{
				//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_006a: 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_006f: Invalid comparison between Unknown and I4
				try
				{
					if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
					{
						return;
					}
					float value = StationConfig.FermenterDurationOverride.Value;
					if (value > 0f)
					{
						__instance.m_fermentationDuration = value;
					}
					if (!StationConfig.FermenterAutoProcess.Value)
					{
						return;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return;
					}
					Status status = __instance.GetStatus();
					if ((int)status != 0)
					{
						if ((int)status == 3)
						{
							__instance.m_nview.InvokeRPC("RPC_Tap", Array.Empty<object>());
						}
					}
					else
					{
						TryRefuel(__instance, localPlayer);
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}

			private static void TryRefuel(Fermenter fermenter, Player player)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				if (!fermenter.m_hasRoof || fermenter.m_exposed)
				{
					return;
				}
				foreach (Container item in NearbyContainers.Find(((Component)fermenter).transform.position, StationConfig.FermenterRadius.Value, player))
				{
					Inventory inventory = item.GetInventory();
					ItemData val = FindCookableItem(fermenter, inventory);
					if (val != null && fermenter.IsItemAllowed(val) && NearbyContainers.TryClaimWriteAccess(item))
					{
						int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name);
						bool cheated = val.m_cheated;
						if (UnlockedInventory.RemoveItem(inventory, val, 1) == 1)
						{
							fermenter.m_nview.InvokeRPC("RPC_AddItem", new object[2] { stableHashCode, cheated });
							break;
						}
					}
				}
			}

			private static ItemData FindCookableItem(Fermenter fermenter, Inventory inventory)
			{
				foreach (ItemConversion item in fermenter.m_conversion)
				{
					if (!((Object)(object)item.m_from == (Object)null))
					{
						ItemData val = UnlockedInventory.FindItem(inventory, item.m_from.m_itemData.m_shared.m_name);
						if (val != null)
						{
							return val;
						}
					}
				}
				return null;
			}
		}

		[HarmonyPatch(typeof(Fermenter), "DelayedTap")]
		private static class CollectRedirectPatch
		{
			private static bool Prefix(Fermenter __instance)
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: 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_00a6: 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_017f: Unknown result type (might be due to invalid IL or missing references)
				//IL_018a: Unknown result type (might be due to invalid IL or missing references)
				//IL_018f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_019c: Unknown result type (might be due to invalid IL or missing references)
				//IL_019e: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!StationConfig.FermenterAutoProcess.Value)
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					ItemConversion itemConversion = __instance.GetItemConversion(__instance.m_delayedTapItem);
					if (itemConversion == null || (Object)(object)itemConversion.m_to == (Object)null)
					{
						return true;
					}
					__instance.m_spawnEffects.Create(((Component)__instance.m_outputPoint).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
					int num = itemConversion.m_producedItems;
					string name = itemConversion.m_to.m_itemData.m_shared.m_name;
					foreach (Container item in NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.FermenterRadius.Value, localPlayer))
					{
						if (num <= 0)
						{
							break;
						}
						if (NearbyContainers.TryClaimWriteAccess(item))
						{
							Inventory inventory = item.GetInventory();
							int num2 = inventory.CountItems(name, -1, true);
							inventory.AddItem(((Component)itemConversion.m_to).gameObject, num);
							int num3 = inventory.CountItems(name, -1, true) - num2;
							if (num3 > 0)
							{
								num -= num3;
							}
						}
					}
					if (num <= 0)
					{
						return false;
					}
					bool flag = (__instance.m_delayedTapItemCheated || __instance.m_nview.GetZDO().GetBool(ZDOVars.s_cheated, false)) && !PlayerProfile.s_bypassCheatChecks;
					float num4 = 0.3f;
					for (int i = 0; i < num; i++)
					{
						Vector3 val = __instance.m_outputPoint.position + Vector3.up * (num4 * (float)i);
						ItemDrop.OnCreateNew(Object.Instantiate<ItemDrop>(itemConversion.m_to, val, Quaternion.identity), flag);
					}
					return false;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					return true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Fireplace), "UpdateFireplace")]
	internal static class FireplacePatch
	{
		private static void Postfix(Fireplace __instance)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!StationConfig.FireplaceAutoRefuel.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner() || (Object)(object)__instance.m_fuelItem == (Object)null)
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				float num = __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
				if ((float)Mathf.CeilToInt(num) >= __instance.m_maxFuel)
				{
					return;
				}
				string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
				foreach (Container item in NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.FireplaceRadius.Value, localPlayer))
				{
					if (!((float)Mathf.CeilToInt(num) >= __instance.m_maxFuel))
					{
						Inventory inventory = item.GetInventory();
						ItemData val = UnlockedInventory.FindItem(inventory, name);
						if (val != null && NearbyContainers.TryClaimWriteAccess(item) && UnlockedInventory.RemoveItem(inventory, val, 1) == 1)
						{
							__instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
							num += 1f;
						}
						continue;
					}
					break;
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}
	}
	internal static class KilnDetection
	{
		private static readonly Dictionary<string, string> CoalItemNameByStation = new Dictionary<string, string>();

		public static bool IsKiln(Smelter smelter)
		{
			return GetCoalItemName(smelter) != null;
		}

		public static string GetCoalItemName(Smelter smelter)
		{
			string name = smelter.m_name;
			if (string.IsNullOrEmpty(name))
			{
				return FindCoalItemName(smelter);
			}
			if (CoalItemNameByStation.TryGetValue(name, out var value))
			{
				return value;
			}
			string text = FindCoalItemName(smelter);
			CoalItemNameByStation[name] = text;
			return text;
		}

		private static string FindCoalItemName(Smelter smelter)
		{
			foreach (ItemConversion item in smelter.m_conversion)
			{
				if ((Object)(object)item.m_to != (Object)null && ((Object)((Component)item.m_to).gameObject).name == "Coal")
				{
					return item.m_to.m_itemData.m_shared.m_name;
				}
			}
			return null;
		}

		public static ItemDrop GetRegularWoodItem(Smelter smelter)
		{
			foreach (ItemConversion item in smelter.m_conversion)
			{
				if ((Object)(object)item.m_from != (Object)null && ((Object)((Component)item.m_from).gameObject).name == "Wood")
				{
					return item.m_from;
				}
			}
			return null;
		}
	}
	internal static class SmelterPatches
	{
		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		private static class RefuelPatch
		{
			private static void Postfix(Smelter __instance)
			{
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					bool flag = KilnDetection.IsKiln(__instance);
					if (!(flag ? StationConfig.KilnAutoRefuel.Value : StationConfig.SmelterAutoRefuel.Value) || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
					{
						return;
					}
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)(object)localPlayer == (Object)null))
					{
						bool num = __instance.GetQueueSize() < (flag ? StationConfig.KilnWoodBuffer.Value : __instance.m_maxOre);
						bool flag2 = __instance.m_maxFuel > 0 && (Object)(object)__instance.m_fuelItem != (Object)null && __instance.GetFuel() < (float)__instance.m_maxFuel;
						if (num || flag2)
						{
							List<Container> containers = new List<Container>(NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.SmelterKilnRadius.Value, localPlayer));
							RefuelOre(__instance, flag, containers);
							RefuelFuel(__instance, containers);
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}

			private static void RefuelOre(Smelter smelter, bool isKiln, List<Container> containers)
			{
				int num = (isKiln ? StationConfig.KilnWoodBuffer.Value : smelter.m_maxOre);
				string coalName = (isKiln ? KilnDetection.GetCoalItemName(smelter) : null);
				while (smelter.GetQueueSize() < num && (!isKiln || !KilnCoalCapReached(coalName, containers)) && TryPullOneOre(smelter, isKiln, containers))
				{
				}
			}

			private static bool TryPullOneOre(Smelter smelter, bool isKiln, List<Container> containers)
			{
				ItemDrop val = null;
				if (isKiln && StationConfig.KilnRegularWoodOnly.Value)
				{
					val = KilnDetection.GetRegularWoodItem(smelter);
				}
				foreach (Container container in containers)
				{
					Inventory inventory = container.GetInventory();
					if ((Object)(object)val != (Object)null)
					{
						string name = val.m_itemData.m_shared.m_name;
						ItemData val2 = UnlockedInventory.FindItem(inventory, name);
						if (val2 != null && NearbyContainers.TryClaimWriteAccess(container) && UnlockedInventory.RemoveItem(inventory, val2, 1) == 1)
						{
							smelter.m_nview.InvokeRPC("RPC_AddOre", new object[2]
							{
								((Object)((Component)val).gameObject).name,
								false
							});
							return true;
						}
						continue;
					}
					ItemData val3 = FindCookableItem(smelter, inventory);
					if (val3 != null && smelter.IsItemAllowed(((Object)val3.m_dropPrefab).name) && NearbyContainers.TryClaimWriteAccess(container))
					{
						string name2 = ((Object)val3.m_dropPrefab).name;
						bool cheated = val3.m_cheated;
						if (UnlockedInventory.RemoveItem(inventory, val3, 1) == 1)
						{
							smelter.m_nview.InvokeRPC("RPC_AddOre", new object[2] { name2, cheated });
							return true;
						}
					}
				}
				return false;
			}

			private static void RefuelFuel(Smelter smelter, List<Container> containers)
			{
				if (smelter.m_maxFuel <= 0 || (Object)(object)smelter.m_fuelItem == (Object)null)
				{
					return;
				}
				string name = smelter.m_fuelItem.m_itemData.m_shared.m_name;
				while (smelter.GetFuel() < (float)smelter.m_maxFuel)
				{
					bool flag = false;
					foreach (Container container in containers)
					{
						Inventory inventory = container.GetInventory();
						ItemData val = UnlockedInventory.FindItem(inventory, name);
						if (val != null && NearbyContainers.TryClaimWriteAccess(container) && UnlockedInventory.RemoveItem(inventory, val, 1) == 1)
						{
							smelter.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						break;
					}
				}
			}

			private static ItemData FindCookableItem(Smelter smelter, Inventory inventory)
			{
				foreach (ItemConversion item in smelter.m_conversion)
				{
					if (!((Object)(object)item.m_from == (Object)null))
					{
						ItemData val = UnlockedInventory.FindItem(inventory, item.m_from.m_itemData.m_shared.m_name);
						if (val != null)
						{
							return val;
						}
					}
				}
				return null;
			}

			private static bool KilnCoalCapReached(string coalName, List<Container> containers)
			{
				if (coalName == null)
				{
					return false;
				}
				int num = 0;
				foreach (Container container in containers)
				{
					num += container.GetInventory().CountItems(coalName, -1, true);
					if (num >= StationConfig.KilnMaxCoalInChest.Value)
					{
						return true;
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Smelter), "Spawn")]
		private static class CollectPatch
		{
			private static bool Prefix(Smelter __instance, string ore, ref int stack)
			{
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					bool flag = KilnDetection.IsKiln(__instance);
					if (!(flag ? StationConfig.KilnAutoCollect.Value : StationConfig.SmelterAutoCollect.Value))
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					ItemConversion itemConversion = __instance.GetItemConversion(ore);
					if (itemConversion == null || (Object)(object)itemConversion.m_to == (Object)null)
					{
						return true;
					}
					int num = stack;
					if (flag)
					{
						num = FeedNearbySmelters(__instance, num);
					}
					if (num <= 0)
					{
						stack = 0;
						return false;
					}
					string name = itemConversion.m_to.m_itemData.m_shared.m_name;
					foreach (Container item in NearbyContainers.Find(((Component)__instance).transform.position, StationConfig.SmelterKilnRadius.Value, localPlayer))
					{
						if (num <= 0)
						{
							break;
						}
						Inventory inventory = item.GetInventory();
						if (NearbyContainers.HasRoomFor(inventory, name) && NearbyContainers.TryClaimWriteAccess(item))
						{
							int num2 = inventory.CountItems(name, -1, true);
							inventory.AddItem(((Component)itemConversion.m_to).gameObject, num);
							int num3 = inventory.CountItems(name, -1, true) - num2;
							if (num3 > 0)
							{
								num -= num3;
							}
						}
					}
					stack = num;
					return num > 0;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					return true;
				}
			}

			private static int FeedNearbySmelters(Smelter kiln, int amount)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				string coalItemName = KilnDetection.GetCoalItemName(kiln);
				List<Smelter> list = new List<Smelter>();
				HashSet<Smelter> hashSet = new HashSet<Smelter>();
				Vector3 kilnPosition = ((Component)kiln).transform.position;
				int num = NearbyContainers.OverlapNearby(kilnPosition, StationConfig.SmelterKilnRadius.Value);
				for (int i = 0; i < num; i++)
				{
					Smelter componentInParent = ((Component)NearbyContainers.Hits[i]).GetComponentInParent<Smelter>();
					if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)componentInParent == (Object)(object)kiln) && hashSet.Add(componentInParent) && !KilnDetection.IsKiln(componentInParent) && !((Object)(object)componentInParent.m_fuelItem == (Object)null) && !(componentInParent.GetFuel() >= (float)componentInParent.m_maxFuel) && !(componentInParent.m_fuelItem.m_itemData.m_shared.m_name != coalItemName) && PrivateArea.CheckAccess(((Component)componentInParent).transform.position, 0f, false, false))
					{
						list.Add(componentInParent);
					}
				}
				if (list.Count == 0)
				{
					return amount;
				}
				if (StationConfig.KilnFeedStrategyConfig.Value == KilnFeedStrategy.LeastFuelFirst)
				{
					list.Sort((Smelter a, Smelter b) => a.GetFuel().CompareTo(b.GetFuel()));
				}
				else
				{
					list.Sort(delegate(Smelter a, Smelter b)
					{
						//IL_0006: Unknown result type (might be due to invalid IL or missing references)
						//IL_000c: Unknown result type (might be due to invalid IL or missing references)
						//IL_0011: Unknown result type (might be due to invalid IL or missing references)
						//IL_0016: Unknown result type (might be due to invalid IL or missing references)
						//IL_0027: 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_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)
						Vector3 val = ((Component)a).transform.position - kilnPosition;
						float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
						val = ((Component)b).transform.position - kilnPosition;
						return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude);
					});
				}
				foreach (Smelter item in list)
				{
					while (amount > 0 && item.GetFuel() < (float)item.m_maxFuel && NearbyContainers.TryClaimWriteAccess(item.m_nview))
					{
						item.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
						amount--;
					}
					if (amount <= 0)
					{
						break;
					}
				}
				return amount;
			}
		}
	}
	internal enum KilnFeedStrategy
	{
		LeastFuelFirst,
		Nearest
	}
	internal static class StationConfig
	{
		public static ConfigEntry<float> FireplaceRadius;

		public static ConfigEntry<float> SmelterKilnRadius;

		public static ConfigEntry<float> CookingStationRadius;

		public static ConfigEntry<float> BeehiveRadius;

		public static ConfigEntry<float> FermenterRadius;

		public static ConfigEntry<bool> FireplaceAutoRefuel;

		public static ConfigEntry<bool> SmelterAutoRefuel;

		public static ConfigEntry<bool> SmelterAutoCollect;

		public static ConfigEntry<bool> KilnAutoRefuel;

		public static ConfigEntry<bool> KilnAutoCollect;

		public static ConfigEntry<bool> CookingStationAutoRefuel;

		public static ConfigEntry<bool> CookingStationAutoCollect;

		public static ConfigEntry<bool> BeehiveAutoCollect;

		public static ConfigEntry<bool> FermenterAutoProcess;

		public static ConfigEntry<int> KilnWoodBuffer;

		public static ConfigEntry<int> KilnMaxCoalInChest;

		public static ConfigEntry<KilnFeedStrategy> KilnFeedStrategyConfig;

		public static ConfigEntry<bool> KilnRegularWoodOnly;

		public static ConfigEntry<float> FermenterDurationOverride;

		public static void Bind(ConfigFile config)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//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_0081: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Expected O, but got Unknown
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Expected O, but got Unknown
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Expected O, but got Unknown
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Expected O, but got Unknown
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Expected O, but got Unknown
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Expected O, but got Unknown
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Expected O, but got Unknown
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Expected O, but got Unknown
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Expected O, but got Unknown
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Expected O, but got Unknown
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Expected O, but got Unknown
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Expected O, but got Unknown
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Expected O, but got Unknown
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Expected O, but got Unknown
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Expected O, but got Unknown
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Expected O, but got Unknown
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Expected O, but got Unknown
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Expected O, but got Unknown
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Expected O, but got Unknown
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Expected O, but got Unknown
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Expected O, but got Unknown
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Expected O, but got Unknown
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Expected O, but got Unknown
			FireplaceRadius = config.Bind<float>("Stations", "FireplaceRadius", 10f, new ConfigDescription("Radius (in meters) in which fireplaces/torches/hearths search nearby chests for fuel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			SmelterKilnRadius = config.Bind<float>("Stations", "SmelterKilnRadius", 10f, new ConfigDescription("Radius (in meters) shared between smelters and charcoal kilns to search nearby chests.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			CookingStationRadius = config.Bind<float>("Stations", "CookingStationRadius", 10f, new ConfigDescription("Radius (in meters) in which cooking stations search nearby chests for raw food.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			BeehiveRadius = config.Bind<float>("Stations", "BeehiveRadius", 10f, new ConfigDescription("Radius (in meters) in which beehives search nearby chests to store harvested honey.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			FermenterRadius = config.Bind<float>("Stations", "FermenterRadius", 10f, new ConfigDescription("Radius (in meters) in which fermenters search nearby chests for mead/potion bases and to store the finished product.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			FireplaceAutoRefuel = config.Bind<bool>("Stations", "FireplaceAutoRefuel", true, new ConfigDescription("Fireplaces/torches automatically pull fuel from nearby chests.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			SmelterAutoRefuel = config.Bind<bool>("Stations", "SmelterAutoRefuel", true, new ConfigDescription("Smelters automatically pull ore/fuel from nearby chests.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			SmelterAutoCollect = config.Bind<bool>("Stations", "SmelterAutoCollect", true, new ConfigDescription("Smelters store the produced bar in the nearest chest instead of dropping it on the ground.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			KilnAutoRefuel = config.Bind<bool>("Stations", "KilnAutoRefuel", true, new ConfigDescription("Charcoal kilns automatically pull wood from nearby chests.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			KilnAutoCollect = config.Bind<bool>("Stations", "KilnAutoCollect", true, new ConfigDescription("Charcoal kilns store the coal they produce (or feed nearby smelters first) instead of dropping it on the ground.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			CookingStationAutoRefuel = config.Bind<bool>("Stations", "CookingStationAutoRefuel", true, new ConfigDescription("Cooking stations automatically pull raw food (and their own fuel, if applicable) from nearby chests.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			CookingStationAutoCollect = config.Bind<bool>("Stations", "CookingStationAutoCollect", true, new ConfigDescription("Cooking stations collect finished food on their own and store it in the nearest chest, without needing to interact.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			BeehiveAutoCollect = config.Bind<bool>("Stations", "BeehiveAutoCollect", false, new ConfigDescription("Beehives harvest honey on their own as soon as it's ready and store it in the nearest chest, without needing to interact.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			FermenterAutoProcess = config.Bind<bool>("Stations", "FermenterAutoProcess", true, new ConfigDescription("Fermenters automatically pull any mead/potion base from nearby chests (mead, resistances, etc.) and store the finished product in the nearest chest once ready.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			KilnWoodBuffer = config.Bind<int>("Charcoal Kiln", "KilnWoodBuffer", 3, new ConfigDescription("Wood level the kiln tries to keep in its internal queue (not its max capacity).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			KilnMaxCoalInChest = config.Bind<int>("Charcoal Kiln", "KilnMaxCoalInChest", 50, new ConfigDescription("The kiln stops pulling new wood once nearby chest(s) already hold this much coal combined.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 9999), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			KilnFeedStrategyConfig = config.Bind<KilnFeedStrategy>("Charcoal Kiln", "KilnFeedStrategy", KilnFeedStrategy.LeastFuelFirst, new ConfigDescription("How the kiln picks which nearby smelter to feed first with the coal it produces.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			KilnRegularWoodOnly = config.Bind<bool>("Charcoal Kiln", "KilnRegularWoodOnly", true, new ConfigDescription("The kiln only pulls regular Wood from nearby chests, skipping Fine Wood and Core Wood (all three convert to coal at the same rate in vanilla, so burning the better ones is pure waste). Disable to let it pull any wood type it accepts.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			FermenterDurationOverride = config.Bind<float>("Fermenter", "FermenterDurationOverride", 0f, new ConfigDescription("Overrides how long (in seconds) a fermenter takes to finish, for every base it processes. 0 means don't override: the fermenter keeps its own vanilla duration.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 86400f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}
	}
}
namespace SmartCraftStorage.Shared
{
	internal static class ChestCountCache
	{
		private readonly struct Query : IEquatable<Query>
		{
			private readonly string _name;

			private readonly int _quality;

			private readonly bool _matchWorldLevel;

			public Query(string name, int quality, bool matchWorldLevel)
			{
				_name = name;
				_quality = quality;
				_matchWorldLevel = matchWorldLevel;
			}

			public bool Equals(Query other)
			{
				if (_quality == other._quality && _matchWorldLevel == other._matchWorldLevel)
				{
					return string.Equals(_name, other._name, StringComparison.Ordinal);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is Query other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((_name != null) ? _name.GetHashCode() : 0) * 397) ^ _quality) * 397) ^ (_matchWorldLevel ? 1 : 0);
			}
		}

		private sealed class QueryComparer : IEqualityComparer<Query>
		{
			public static readonly QueryComparer Instance = new QueryComparer();

			public bool Equals(Query a, Query b)
			{
				return a.Equals(b);
			}

			public int GetHashCode(Query query)
			{
				return query.GetHashCode();
			}
		}

		private static readonly Dictionary<Query, int> Totals = new Dictionary<Query, int>(QueryComparer.Instance);

		private static int _frame = -1;

		public static bool TryGet(string name, int quality, bool matchWorldLevel, out int chestTotal)
		{
			ExpireIfFrameChanged();
			return Totals.TryGetValue(new Query(name, quality, matchWorldLevel), out chestTotal);
		}

		public static void Store(string name, int quality, bool matchWorldLevel, int chestTotal)
		{
			ExpireIfFrameChanged();
			Totals[new Query(name, quality, matchWorldLevel)] = chestTotal;
		}

		public static void Invalidate()
		{
			if (Totals.Count > 0)
			{
				Totals.Clear();
			}
		}

		private static void ExpireIfFrameChanged()
		{
			int frameCount = Time.frameCount;
			if (frameCount != _frame)
			{
				_frame = frameCount;
				Invalidate();
			}
		}
	}
	internal static class DebugLog
	{
		public static void Log(string message)
		{
			if (ModConfig.DebugLogging.Value)
			{
				Debug.Log((object)message);
			}
		}
	}
	internal static class NearbyContainers
	{
		private sealed class CacheEntry
		{
			public Vector3 Origin;

			public float Radius = -1f;

			public float Time = float.NegativeInfinity;

			public readonly List<Container> Containers = new List<Container>();
		}

		private sealed class DistanceComparer : IComparer<Container>
		{
			public Vector3 Origin;

			public int Compare(Container a, Container b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: 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_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)
				Vector3 val = ((Component)a).transform.position - Origin;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				val = ((Component)b).transform.position - Origin;
				return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude);
			}
		}

		private const float CacheSeconds = 0.25f;

		private const float CacheMoveToleranceSqr = 0.25f;

		private const int CacheSlots = 8;

		private static int _queryMask;

		private static bool _queryMaskResolved;

		private static int _vehicleLayer = -1;

		private static Collider[] _hits = (Collider[])(object)new Collider[512];

		private const int MaxHits = 8192;

		private static readonly CacheEntry[] Cache = CreateCache();

		private static readonly HashSet<Container> Seen = new HashSet<Container>();

		private static readonly DistanceComparer Comparer = new DistanceComparer();

		private static int QueryMask
		{
			get
			{
				if (_queryMaskResolved)
				{
					return _queryMask;
				}
				_queryMask = LayerMask.GetMask(new string[6] { "piece", "piece_nonsolid", "vehicle", "Default", "static_solid", "Default_small" });
				_vehicleLayer = LayerMask.NameToLayer("vehicle");
				_queryMaskResolved = true;
				if (_queryMask == 0)
				{
					Debug.LogWarning((object)"[SmartCraft-Storage] None of the expected collision layers exist; falling back to querying all layers. Nearby-chest lookups will be slower than usual.");
					_queryMask = -1;
				}
				return _queryMask;
			}
		}

		public static Collider[] Hits => _hits;

		public static List<Container> Find(Vector3 origin, float radius, Player player)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			CacheEntry cached = GetCached(origin, radius);
			if (cached != null)
			{
				PruneDestroyed(cached.Containers);
				return cached.Containers;
			}
			ChestCountCache.Invalidate();
			cached = TakeOldestSlot();
			cached.Origin = origin;
			cached.Radius = radius;
			cached.Time = Time.time;
			List<Container> containers = cached.Containers;
			containers.Clear();
			Seen.Clear();
			long playerID = player.GetPlayerID();
			int num = OverlapNearby(origin, radius);
			for (int i = 0; i < num; i++)
			{
				Collider val = _hits[i];
				Container val2 = ((Component)val).GetComponentInParent<Container>();
				if ((Object)(object)val2 == (Object)null && ((Component)val).gameObject.layer == _vehicleLayer)
				{
					Vagon componentInParent = ((Component)val).GetComponentInParent<Vagon>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						val2 = componentInParent.m_container;
					}
				}
				if (!((Object)(object)val2 == (Object)null) && Seen.Add(val2) && IsUsableBy(val2, playerID))
				{
					containers.Add(val2);
				}
			}
			Comparer.Origin = origin;
			containers.Sort(Comparer);
			return containers;
		}

		public static int OverlapNearby(Vector3 origin, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num;
			while (true)
			{
				num = Physics.OverlapSphereNonAlloc(origin, radius, _hits, QueryMask);
				if (num < _hits.Length || _hits.Length >= 8192)
				{
					break;
				}
				_hits = (Collider[])(object)new Collider[Mathf.Min(_hits.Length * 2, 8192)];
			}
			return num;
		}

		public static bool HasRoomFor(Inventory inventory, string itemName)
		{
			if (inventory == null)
			{
				return false;
			}
			if (!inventory.HaveEmptySlot())
			{
				return inventory.FindFreeStackSpace(itemName, (float)Game.m_worldLevel) > 0;
			}
			return true;
		}

		public static bool TryClaimWriteAccess(ZNetView nview)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return false;
			}
			if (nview.IsOwner())
			{
				return true;
			}
			nview.ClaimOwnership();
			return nview.IsOwner();
		}

		public static bool TryClaimWriteAccess(Container container)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)container == (Object)null || (Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			if (!IsUsableBy(container, localPlayer.GetPlayerID()))
			{
				return false;
			}
			if (!TryClaimWriteAccess(container.m_nview))
			{
				return false;
			}
			ChestCountCache.Invalidate();
			return true;
		}

		private static bool IsUsableBy(Container container, long playerId)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container == (Object)null || container.GetInventory() == null)
			{
				return false;
			}
			if ((Object)(object)((Component)container).GetComponent<TombStone>() != (Object)null)
			{
				return false;
			}
			if (IsInUseByAnyone(container))
			{
				return false;
			}
			if (!container.CheckAccess(playerId))
			{
				return false;
			}
			return PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false);
		}

		private static bool IsInUseByAnyone(Container container)
		{
			if (container.IsInUse())
			{
				return true;
			}
			if ((Object)(object)container.m_nview != (Object)null && container.m_nview.IsValid())
			{
				return container.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1;
			}
			return false;
		}

		private static CacheEntry GetCached(Vector3 origin, float radius)
		{
			//IL_002d: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			CacheEntry[] cache = Cache;
			foreach (CacheEntry cacheEntry in cache)
			{
				if (cacheEntry.Radius == radius && time - cacheEntry.Time <= 0.25f)
				{
					Vector3 val = cacheEntry.Origin - origin;
					if (((Vector3)(ref val)).sqrMagnitude <= 0.25f)
					{
						return cacheEntry;
					}
				}
			}
			return null;
		}

		private static CacheEntry TakeOldestSlot()
		{
			CacheEntry cacheEntry = Cache[0];
			CacheEntry[] cache = Cache;
			foreach (CacheEntry cacheEntry2 in cache)
			{
				if (cacheEntry2.Time < cacheEntry.Time)
				{
					cacheEntry = cacheEntry2;
				}
			}
			return cacheEntry;
		}

		private static void PruneDestroyed(List<Container> containers)
		{
			for (int num = containers.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)containers[num] == (Object)null)
				{
					containers.RemoveAt(num);
				}
			}
		}

		private static CacheEntry[] CreateCache()
		{
			CacheEntry[] array = new CacheEntry[8];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new CacheEntry();
			}
			return array;
		}
	}
	internal static class UnlockedInventory
	{
		public static int CountItems(Inventory inventory, string name, int quality = -1, bool matchWorldLevel = true)
		{
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!ItemFlags.IsLocked(allItem) && MatchesCount(allItem, name, quality, matchWorldLevel))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		public static bool HaveItem(Inventory inventory, string name, bool matchWorldLevel = true)
		{
			return FindItem(inventory, name, matchWorldLevel) != null;
		}

		public static ItemData FindItem(Inventory inventory, string name, bool matchWorldLevel = true)
		{
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!ItemFlags.IsLocked(allItem) && MatchesNamed(allItem, name, -1, matchWorldLevel))
				{
					return allItem;
				}
			}
			return null;
		}

		public static int RemoveItems(Inventory inventory, string name, int amount, int quality = -1, bool matchWorldLevel = true)
		{
			int num = 0;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (num >= amount)
				{
					break;
				}
				if (!ItemFlags.IsLocked(item) && MatchesNamed(item, name, quality, matchWorldLevel))
				{
					num += RemoveItem(inventory, item, amount - num);
				}
			}
			return num;
		}

		public static int RemoveItem(Inventory inventory, ItemData item, int amount)
		{
			if (item == null || amount <= 0 || ItemFlags.IsLocked(item) || !inventory.ContainsItem(item))
			{
				return 0;
			}
			int stack = item.m_stack;
			int num = Math.Min(amount, stack);
			if (!inventory.RemoveItem(item, num))
			{
				return 0;
			}
			int num2 = (inventory.ContainsItem(item) ? item.m_stack : 0);
			return Math.Min(num, Math.Max(0, stack - num2));
		}

		private static bool MatchesCount(ItemData item, string name, int quality, bool matchWorldLevel)
		{
			if ((name == null || item.m_shared.m_name == name) && (quality < 0 || item.m_quality == quality))
			{
				if (matchWorldLevel)
				{
					return item.m_worldLevel >= Game.m_worldLevel;
				}
				return true;
			}
			return false;
		}

		private static bool MatchesNamed(ItemData item, string name, int quality, bool matchWorldLevel)
		{
			if (item.m_shared.m_name == name && (quality < 0 || item.m_quality == quality))
			{
				if (matchWorldLevel)
				{
					return item.m_worldLevel >= Game.m_worldLevel;
				}
				return true;
			}
			return false;
		}
	}
}
namespace SmartCraftStorage.Restock
{
	internal static class RestockService
	{
		public static void Execute(Player player)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<string> all = RestockList.GetAll(player);
			if (all.Count == 0)
			{
				((Character)player).Message((MessageType)2, Localization.instance.Localize("$smartcraft_restock_no_items_marked"), 0, (Sprite)null, false);
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<Container> containers = new List<Container>(NearbyContainers.Find(((Component)player).transform.position, ModConfig.QuickStackRadius.Value, player));
			int num = 0;
			foreach (string item in all)
			{
				num += RestockOne(inventory, item, containers);
			}
			((Character)player).Message((MessageType)2, (num > 0) ? Localization.instance.Localize("$smartcraft_restock_success", new string[1] { num.ToString() }) : Localization.instance.Localize("$smartcraft_restock_nothing"), 0, (Sprite)null, false);
		}

		private static int RestockOne(Inventory playerInventory, string itemName, List<Container> containers)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			int num = FindMaxStackSize(itemName, containers);
			if (num <= 0)
			{
				return 0;
			}
			int num2 = num - CountPlayerOwned(playerInventory, itemName);
			if (num2 <= 0)
			{
				return 0;
			}
			int num3 = 0;
			foreach (Container container in containers)
			{
				if (num2 <= 0)
				{
					break;
				}
				Inventory inventory = container.GetInventory();
				List<ItemData> list = inventory.GetAllItems().FindAll((ItemData i) => i.m_shared.m_name == itemName);
				if (list.Count == 0 || !NearbyContainers.TryClaimWriteAccess(container))
				{
					continue;
				}
				foreach (ItemData item in list)
				{
					if (num2 <= 0)
					{
						break;
					}
					int num4 = Math.Min(num2, item.m_stack);
					Vector2i val = playerInventory.GetItem(itemName, -1, false)?.m_gridPos ?? playerInventory.FindEmptySlot(false);
					if (val.x < 0)
					{
						return num3;
					}
					if (playerInventory.MoveItemToThis(inventory, item, num4, val.x, val.y))
					{
						num2 -= num4;
						num3 += num4;
					}
				}
			}
			return num3;
		}

		private static int CountPlayerOwned(Inventory playerInventory, string itemName)
		{
			int num = 0;
			foreach (ItemData allItem in playerInventory.GetAllItems())
			{
				if (allItem.m_shared.m_name == itemName)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		private static int FindMaxStackSize(string itemName, List<Container> containers)
		{
			foreach (Container container in containers)
			{
				ItemData val = container.GetInventory().GetAllItems().Find((ItemData i) => i.m_shared.m_name == itemName);
				if (val != null)
				{
					return val.m_shared.m_maxStackSize;
				}
			}
			return 0;
		}
	}
}
namespace SmartCraftStorage.Repair
{
	[HarmonyPatch(typeof(InventoryGui), "RepairOneItem")]
	internal static class RepairAllPatch
	{
		private static bool Prefix(InventoryGui __instance)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return true;
				}
				CraftingStation currentCraftingStation = Player.m_localPlayer.GetCurrentCraftingStation();
				if (((Object)(object)currentCraftingStation == (Object)null && !Player.m_localPlayer.NoCostCheat()) || ((Object)(object)currentCraftingStation != (Object)null && !currentCraftingStation.CheckUsable(Player.m_localPlayer, false)))
				{
					return true;
				}
				List<ItemData> list = new List<ItemData>();
				((Humanoid)Player.m_localPlayer).GetInventory().GetWornItems(list);
				foreach (ItemData item in list)
				{
					if (__instance.CanRepair(item))
					{
						((Character)Player.m_localPlayer).RaiseSkill((SkillType)107, 1f - item.m_durability / item.GetMaxDurability());
						item.m_durability = item.GetMaxDurability();
						if ((Object)(object)currentCraftingStation != (Object)null)
						{
							currentCraftingStation.m_repairItemDoneEffects.Create(((Component)currentCraftingStation).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
						}
					}
				}
				return false;
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				return true;
			}
		}
	}
}
namespace SmartCraftStorage.QuickStack
{
	internal static class QuickStackService
	{
		public static void Execute(Player player)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<Container> list = new List<Container>(NearbyContainers.Find(((Component)player).transform.position, ModConfig.QuickStackRadius.Value, player));
			if (list.Count == 0)
			{
				((Character)player).Message((MessageType)2, Localization.instance.Localize("$smartcraft_no_chest_nearby"), 0, (Sprite)null, false);
				return;
			}
			int num = 0;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (!item.m_equipped && !ItemFlags.IsLocked(item))
				{
					num += MoveItemIntoMatchingStacks(inventory, item, list);
				}
			}
			((Character)player).Message((MessageType)2, (num > 0) ? Localization.instance.Localize("$smartcraft_quickstack_success", new string[1] { num.ToString() }) : Localization.instance.Localize("$smartcraft_quickstack_nothing"), 0, (Sprite)null, false);
		}

		private static int MoveItemIntoMatchingStacks(Inventory playerInventory, ItemData item, List<Container> containers)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_016e: Unknown result type (might be due to invalid IL or missing references)
			int stack = item.m_stack;
			foreach (Container container in containers)
			{
				if (item.m_stack <= 0)
				{
					break;
				}
				Inventory inventory = container.GetInventory();
				List<ItemData> list = inventory.GetAllItems().FindAll((ItemData i) => i.m_shared.m_name == item.m_shared.m_name && i.m_quality == item.m_quality);
				if (list.Count == 0 || !NearbyContainers.TryClaimWriteAccess(container))
				{
					continue;
				}
				foreach (ItemData item2 in list)
				{
					if (item.m_stack <= 0)
					{
						break;
					}
					int num = item2.m_shared.m_maxStackSize - item2.m_stack;
					if (num > 0)
					{
						int num2 = Mathf.Min(num, item.m_stack);
						inventory.MoveItemToThis(playerInventory, item, num2, item2.m_gridPos.x, item2.m_gridPos.y);
					}
				}
				while (item.m_stack > 0)
				{
					Vector2i val = inventory.FindEmptySlot(false);
					if (val.x < 0)
					{
						break;
					}
					int num3 = Mathf.Min(item.m_shared.m_maxStackSize, item.m_stack);
					inventory.MoveItemToThis(playerInventory, item, num3, val.x, val.y);
				}
			}
			return stack - item.m_stack;
		}
	}
}
namespace SmartCraftStorage.PlantHarvest
{
	internal static class PlantHarvestConfig
	{
		public static ConfigEntry<float> PlantHarvestRadius;

		public static ConfigEntry<bool> PlantAutoHarvest;

		public static void Bind(ConfigFile config)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			PlantHarvestRadius = config.Bind<float>("Plant Harvest (In Test)", "PlantHarvestRadius", 10f, new ConfigDescription("Radius (in meters), around the player, in which ripe crops are harvested automatically and stored in the nearest chest.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			PlantAutoHarvest = config.Bind<bool>("Plant Harvest (In Test)", "PlantAutoHarvest", false, new ConfigDescription("Experimental: automatically harvests ripe cultivated crops near the player and stores them in the nearest chest. Off by default, test it before relying on it.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}
	}
	internal static class PlantHarvestPatch
	{
		[HarmonyPatch(typeof(Player), "Update")]
		private static class AutoHarvestTriggerPatch
		{
			private const float ScanInterval = 3f;

			private static float _nextScanTime;

			private static void Postfix(Player __instance)
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!PlantHarvestConfig.PlantAutoHarvest.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || Time.time < _nextScanTime)
					{
						return;
					}
					_nextScanTime = Time.time + 3f;
					Collider[] array = Physics.OverlapSphere(((Component)__instance).transform.position, PlantHarvestConfig.PlantHarvestRadius.Value);
					HashSet<Pickable> hashSet = new HashSet<Pickable>();
					Collider[] array2 = array;
					for (int i = 0; i < array2.Length; i++)
					{
						Pickable componentInParent = ((Component)array2[i]).GetComponentInParent<Pickable>();
						if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && componentInParent.m_harvestable && componentInParent.CanBePicked())
						{
							componentInParent.Interact((Humanoid)(object)__instance, false, false);
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "Drop")]
		private static class CollectRedirectPatch
		{
			private static bool Prefix(Pickable __instance, GameObject prefab, ref int stack)
			{
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!PlantHarvestConfig.PlantAutoHarvest.Value)
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					ItemDrop component = prefab.GetComponent<ItemDrop>();
					if ((Object)(object)component == (Object)null)
					{
						return true;
					}
					int num = stack;
					string name = component.m_itemData.m_shared.m_name;
					foreach (Container item in NearbyContainers.Find(((Component)__instance).transform.position, PlantHarvestConfig.PlantHarvestRadius.Value, localPlayer))
					{
						if (num <= 0)
						{
							break;
						}
						if (NearbyContainers.TryClaimWriteAccess(item))
						{
							Inventory inventory = item.GetInventory();
							int num2 = inventory.CountItems(name, -1, true);
							inventory.AddItem(prefab, num);
							int num3 = inventory.CountItems(name, -1, true) - num2;
							if (num3 > 0)
							{
								num -= num3;
							}
						}
					}
					stack = num;
					return num > 0;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					return true;
				}
			}
		}
	}
}
namespace SmartCraftStorage.ItemMarking
{
	[HarmonyPatch(typeof(InventoryGrid), "OnLeftDown")]
	internal static class AltClickPatch
	{
		private static bool Prefix(InventoryGrid __instance, UIInputHandler clickHandler)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				bool flag = AreAllKeysHeld(HotkeyConfig.RestockMarkClickShortcut.Value);
				bool flag2 = AreAllKeysHeld(HotkeyConfig.LockClickShortcut.Value);
				if (!flag && !flag2)
				{
					return true;
				}
				Vector2i buttonPos = __instance.GetButtonPos(((Component)clickHandler).gameObject);
				ItemData itemAt = __instance.m_inventory.GetItemAt(buttonPos.x, buttonPos.y);
				if (itemAt == null)
				{
					return true;
				}
				if (flag)
				{
					if ((Object)(object)Player.m_localPlayer != (Object)null)
					{
						RestockList.Toggle(Player.m_localPlayer, itemAt.m_shared.m_name);
					}
				}
				else
				{
					ItemFlags.ToggleLocked(itemAt);
					__instance.m_inventory.Changed(false, false);
					ChestCountCache.Invalidate();
				}
				return false;
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				return true;
			}
		}

		private static bool AreAllKeysHeld(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey, true))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, true))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class ItemFlags
	{
		private const string LockedKey = "SmartCraft_Locked";

		public static bool IsLocked(ItemData item)
		{
			if (item.m_customData.TryGetValue("SmartCraft_Locked", out var value))
			{
				return value == "1";
			}
			return false;
		}

		public static void SetLocked(ItemData item, bool locked)
		{
			if (locked)
			{
				item.m_customData["SmartCraft_Locked"] = "1";
			}
			else
			{
				item.m_customData.Remove("SmartCraft_Locked");
			}
		}

		public static void ToggleLocked(ItemData item)
		{
			SetLocked(item, !IsLocked(item));
		}
	}
	internal static class RestockList
	{
		private const string CustomDataKey = "SmartCraft_RestockList";

		private const char Separator = '|';

		private static string _cachedRaw;

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

		public static bool Contains(Player player, string itemName)
		{
			return GetAll(player).Contains(itemName);
		}

		public static void Toggle(Player player, string itemName)
		{
			List<string> list = new List<string>(GetAll(player));
			if (list.Contains(itemName))
			{
				list.Remove(itemName);
			}
			else
			{
				list.Add(itemName);
			}
			Save(player, list);
		}

		public static IReadOnlyList<string> GetAll(Player player)
		{
			if ((Object)(object)player == (Object)null || !player.m_customData.TryGetValue("SmartCraft_RestockList", out var value) || string.IsNullOrEmpty(value))
			{
				return Array.Empty<string>();
			}
			return value.Split(new char[1] { '|' });
		}

		public static HashSet<string> GetSet(Player player)
		{
			string value = null;
			if ((Object)(object)player != (Object)null)
			{
				player.m_customData.TryGetValue("SmartCraft_RestockList", out value);
			}
			if (value == _cachedRaw)
			{
				return CachedSet;
			}
			_cachedRaw = value;
			CachedSet.Clear();
			if (!string.IsNullOrEmpty(value))
			{
				string[] array = value.Split(new char[1] { '|' });
				foreach (string item in array)
				{
					CachedSet.Add(item);
				}
			}
			return CachedSet;
		}

		private static void Save(Player player, List<string> items)
		{
			if (!((Object)(object)player == (Object)null))
			{
				player.m_customData["SmartCraft_RestockList"] = string.Join('|'.ToString(), items);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class SlotOverlayPatch
	{
		private static readonly Dictionary<InventoryElement, Image> LockedOverlays = new Dictionary<InventoryElement, Image>();

		private static readonly Dictionary<InventoryElement, Image> RestockOverlays = new Dictionary<InventoryElement, Image>();

		private static Sprite _lockedSprite;

		private static Sprite _restockSprite;

		private static Sprite LockedSprite
		{
			get
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_lockedSprite != (Object)null))
				{
					return _lockedSprite = CreateBorderSprite(new Color(1f, 0.35f, 0.1f, 0.9f));
				}
				return _lockedSprite;
			}
		}

		private static Sprite RestockSprite
		{
			get
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_restockSprite != (Object)null))
				{
					return _restockSprite = CreateCornerDotSprite(new Color(0.2f, 0.6f, 1f, 0.95f));
				}
				return _restockSprite;
			}
		}

		private static void Postfix(InventoryGrid __instance)
		{
			try
			{
				if (__instance.m_inventory == null)
				{
					return;
				}
				int width = __instance.m_inventory.GetWidth();
				Player localPlayer = Player.m_localPlayer;
				HashSet<string> hashSet = (((Object)(object)localPlayer != (Object)null) ? RestockList.GetSet(localPlayer) : null);
				foreach (InventoryElement element2 in __instance.m_elements)
				{
					if (LockedOverlays.TryGetValue(element2, out var value) && (Object)(object)value != (Object)null)
					{
						((Behaviour)value).enabled = false;
					}
					if (RestockOverlays.TryGetValue(element2, out var value2) && (Object)(object)value2 != (Object)null)
					{
						((Behaviour)value2).enabled = false;
					}
				}
				foreach (ItemData allItem in __instance.m_inventory.GetAllItems())
				{
					InventoryElement element = __instance.GetElement(allItem.m_gridPos.x, allItem.m_gridPos.y, width);
					if (!((Object)(object)element == (Object)null))
					{
						((Behaviour)GetOrCreateOverlay(element, LockedOverlays, LockedSprite, "SmartCraft_LockedOverlay")).enabled = ItemFlags.IsLocked(allItem);
						bool enabled = hashSet?.Contains(allItem.m_shared.m_name) ?? false;
						((Behaviour)GetOrCreateOverlay(element, RestockOverlays, RestockSprite, "SmartCraft_RestockOverlay")).enabled = enabled;
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}

		internal static Image GetOrCreateOverlay(InventoryElement element, Dictionary<InventoryElement, Image> cache, Sprite sprite, string overlayName)
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (cache.TryGetValue(element, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			GameObject val = new GameObject(overlayName);
			val.transform.SetParent(((Component)element).transform, false);
			val.transform.SetSiblingIndex(((Component)element.m_icon).transform.GetSiblingIndex() + 1);
			RectTransform obj = val.AddComponent<RectTransform>();
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.offsetMin = Vector2.zero;
			obj.offsetMax = Vector2.zero;
			Image val2 = val.AddComponent<Image>();
			val2.sprite = sprite;
			((Graphic)val2).raycastTarget = false;
			val2.type = (Type)1;
			cache[element] = val2;
			return val2;
		}

		internal static Sprite CreateBorderSprite(Color color, int size = 64, int thickness = 5)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[size * size];
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					bool flag = j < thickness || j >= size - thickness || i < thickness || i >= size - thickness;
					array[i * size + j] = (flag ? color : Color.clear);
				}
			}
			val.SetPixels(array);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)thickness, (float)thickness, (float)thickness, (float)thickness));
		}

		internal static Sprite CreateCornerDotSprite(Color color, int size = 64, int dotRadius = 10)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0088: 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_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)
			//IL_0053: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[size * size];
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor((float)(size - dotRadius - 4), (float)(dotRadius + 4));
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					float num = Vector2.Distance(new Vector2((float)j, (float)i), val2);
					array[i * size + j] = ((num <= (float)dotRadius) ? color : Color.clear);
				}
			}
			val.SetPixels(array);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f));
		}
	}
}
namespace SmartCraftStorage.Integrations
{
	internal static class EpicLootProvider
	{
		private const string EpicLootGuid = "randyknapp.mods.epicloot";

		public static void Setup()
		{
			try
			{
				if (Chainloader.PluginInfos.ContainsKey("randyknapp.mods.epicloot"))
				{
					MethodInfo methodInfo = Type.GetType("EpicLoot.API, EpicLoot")?.GetMethod("RegisterInventoryProvider", BindingFlags.Static | BindingFlags.Public);
					if (methodInfo == null)
					{
						Debug.LogWarning((object)"[SmartCraftStorage] Epic Loot is installed but its inventory provider API wasn't found; skipping the integration for this version.");
						return;
					}
					Func<List<ItemData>> func = GetItems;
					Func<string, int> func2 = CountItem;
					Func<string, int, int> func3 = RemoveItem;
					Func<ItemData, int, int> func4 = RemoveExactItem;
					methodInfo.Invoke(null, new object[5] { "com.zellds.smartcraftstorage", func, func2, func3, func4 });
					Debug.Log((object)"[SmartCraftStorage] Registered with Epic Loot: the enchanting table can now see nearby chests.");
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}

		private static List<ItemData> GetItems()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			List<ItemData> list = new List<ItemData>();
			foreach (Container item in NearbyContainers.Find(((Component)localPlayer).transform.position, ModConfig.CraftingChestRadius.Value, localPlayer))
			{
				foreach (ItemData allItem in item.GetInventory().GetAllItems())
				{
					if (!ItemFlags.IsLocked(allItem))
					{
						list.Add(allItem);
					}
				}
			}
			return list;
		}

		private static int CountItem(string itemName)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return 0;
			}
			int num = 0;
			foreach (Container item in NearbyContainers.Find(((Component)localPlayer).transform.position, ModConfig.CraftingChestRadius.Value, localPlayer))
			{
				num += UnlockedInventory.CountItems(item.GetInventory(), itemName);
			}
			return num;
		}

		private static int RemoveItem(string itemName, int amount)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return 0;
			}
			int num = amount;
			foreach (Container item in NearbyContainers.Find(((Component)localPlayer).transform.position, ModConfig.CraftingChestRadius.Value, localPlayer))
			{
				if (num <= 0)
				{
					break;
				}
				if (NearbyContainers.TryClaimWriteAccess(item))
				{
					int num2 = UnlockedInventory.RemoveItems(item.GetInventory(), itemName, num);
					num -= num2;
				}
			}
			return amount - num;
		}

		private static int RemoveExactItem(ItemData item, int amount)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || item == null || ItemFlags.IsLocked(item))
			{
				return 0;
			}
			foreach (Container item2 in NearbyContainers.Find(((Component)localPlayer).transform.position, ModConfig.CraftingChestRadius.Value, localPlayer))
			{
				Inventory inventory = item2.GetInventory();
				if (inventory.ContainsItem(item) && NearbyContainers.TryClaimWriteAccess(item2))
				{
					return UnlockedInventory.RemoveItem(inventory, item, amount);
				}
			}
			return 0;
		}
	}
	internal static class EpicLootSacrificeProtection
	{
		private static FieldInfo _availableItems;

		private static MethodInfo _getSelectedItems;

		private static PropertyInfo _selectedElement;

		private static MethodInfo _getItem;

		private static MethodInfo _cancel;

		private static MethodInfo _refresh;

		public static void Setup(Harmony harmony)
		{
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.ContainsKey("randyknapp.mods.epicloot"))
			{
				return;
			}
			try
			{
				Type type = Type.GetType("EpicLoot.API, EpicLoot");
				MethodInfo methodInfo = type?.GetMethod("RegisterSacrificeFilter", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(string),
					typeof(Func<ItemData, bool>)
				}, null);
				MethodInfo methodInfo2 = type?.GetMethod("UnregisterSacrificeFilter", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
				Type? type2 = Type.GetType("EpicLoot_UnityLib.SacrificeUI, EpicLoot");
				Type type3 = Type.GetType("EpicLoot_UnityLib.IListElement, EpicLoot");
				MethodInfo methodInfo3 = type2?.GetMethod("SacrificeItems", BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				FieldInfo fieldInfo = type2?.GetField("AvailableItems", BindingFlags.Instance | BindingFlags.Public);
				MethodInfo methodInfo4 = fieldInfo?.FieldType.GetMethod("GetSelectedItems", BindingFlags.Instance | BindingFlags.Public);
				MethodInfo methodInfo5 = type3?.GetMethod("GetItem", Type.EmptyTypes);
				MethodInfo methodInfo6 = type2?.GetMethod("Cancel", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
				MethodInfo methodInfo7 = type2?.GetMethod("RefreshAvailableItems", BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (methodInfo?.ReturnType != typeof(bool) || methodInfo2?.ReturnType != typeof(bool) || methodInfo3?.ReturnType != typeof(void) || methodInfo5?.ReturnType != typeof(ItemData) || methodInfo6?.ReturnType != typeof(void) || methodInfo7?.ReturnType != typeof(void) || methodInfo4 == null || !methodInfo4.IsGenericMethodDefinition || methodInfo4.GetGenericArguments().Length != 1 || methodInfo4.GetParameters().Length != 0)
				{
					Debug.LogWarning((object)"[SmartCraftStorage] Epic Loot sacrifice protection is unavailable: unsupported filter or UI API.");
					return;
				}
				Type type4 = typeof(Tuple<, >).MakeGenericType(type3, typeof(int));
				methodInfo4 = methodInfo4.MakeGenericMethod(type3);
				if (methodInfo4.ReturnType != typeof(List<>).MakeGenericType(type4))
				{
					Debug.LogWarning((object)"[SmartCraftStorage] Epic Loot sacrifice protection is unavailable: unsupported selection type.");
					return;
				}
				_availableItems = fieldInfo;
				_getSelectedItems = methodInfo4;
				_selectedElement = type4.GetProperty("Item1");
				_getItem = methodInfo5;
				_cancel = methodInfo6;
				_refresh = methodInfo7;
				Func<ItemData, bool> func = (ItemData item) => item == null || !ItemFlags.IsLocked(item);
				if (!(bool)methodInfo.Invoke(null, new object[2] { "com.zellds.smartcraftstorage", func }))
				{
					Debug.LogWarning((object)"[SmartCraftStorage] Epic Loot rejected the sacrifice filter registration.");
					return;
				}
				try
				{
					harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(EpicLootSacrificeProtection), "BeforeSacrifice", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				catch
				{
					methodInfo2.Invoke(null, new object[1] { "com.zellds.smartcraftstorage" });
					throw;
				}
				Debug.Log((object)"[SmartCraftStorage] Registered Epic Loot sacrifice protection for ALT-locked items.");
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)"[SmartCraftStorage] Could not initialize Epic Loot sacrifice protection.");
				Debug.LogException(ex);
			}
		}

		private static bool BeforeSacrifice(object __instance)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			try
			{
				IEnumerable obj = (IEnumerable)_getSelectedItems.Invoke(_availableItems.GetValue(__instance), null);
				bool flag = false;
				foreach (object item in obj)
				{
					ItemData val = (ItemData)_getItem.Invoke(_selectedElement.GetValue(item, null), null);
					if (val != null && ItemFlags.IsLocked(val))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					return true;
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)"[SmartCraftStorage] Canceled Epic Loot sacrifice because the selection could not be checked.");
				Debug.LogException(ex);
			}
			try
			{
				_cancel.Invoke(__instance, null);
				_refresh.Invoke(__instance, null);
			}
			catch (Exception ex2)
			{
				Debug.LogException(ex2);
			}
			return false;
		}
	}
}
namespace SmartCraftStorage.Hotkeys
{
	internal static class HotkeyConfig
	{
		public static ConfigEntry<KeyboardShortcut> QuickStackShortcut;

		public static ConfigEntry<KeyboardShortcut> RestockShortcut;

		public static ConfigEntry<KeyboardShortcut> LockClickShortcut;

		public static ConfigEntry<KeyboardShortcut> RestockMarkClickShortcut;

		public static void Bind(ConfigFile config)
		{
			//IL_001b: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			QuickStackShortcut = config.Bind<KeyboardShortcut>("Hotkeys", "QuickStackShortcut", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Shortcut to stash inventory items into nearby chests (quick-stack). Click the value in Configuration Manager and press the key combo you want.");
			RestockShortcut = config.Bind<KeyboardShortcut>("Hotkeys", "RestockShortcut", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Shortcut to refill items marked for restock from nearby chests. Click the value in Configuration Manager and press the key combo you want.");
			LockClickShortcut = config.Bind<KeyboardShortcut>("Hotkeys", "LockClickShortcut", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Key(s) held while left-clicking an inventory item to toggle its lock. Independent of RestockMarkClickShortcut.");
			RestockMarkClickShortcut = config.Bind<KeyboardShortcut>("Hotkeys", "RestockMarkClickShortcut", new KeyboardShortcut((KeyCode)308, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Key(s) held while left-clicking an item to mark it for restock instead of toggling lock. Independent of LockClickShortcut — does not require it to also be held.");
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class HotkeyPatch
	{
		private static void Postfix(Player __instance)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ((Character)__instance).TakeInput())
				{
					if (IsShortcutDown(HotkeyConfig.QuickStackShortcut.Value))
					{
						QuickStackService.Execute(__instance);
					}
					else if (IsShortcutDown(HotkeyConfig.RestockShortcut.Value))
					{
						RestockService.Execute(__instance);
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}

		private static bool IsShortcutDown(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, true))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, true))
				{
					return false;
				}
			}
			return true;
		}
	}
}
namespace SmartCraftStorage.CraftingChestAccess
{
	internal static class InventoryChestPatches
	{
		[HarmonyPatch(typeof(Inventory), "CountItems", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(bool)
		})]
		private static class CountItemsPatch
		{
			private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!IsCraftingOrBuildingContext(__instance, out var player))
					{
						return;
					}
					if (ChestCountCache.TryGet(name, quality, matchWorldLevel, out var chestTotal))
					{
						__result += chestTotal;
						return;
					}
					int num = 0;
					foreach (Container item in NearbyContainers.Find(((Component)player).transform.position, ModConfig.CraftingChestRadius.Value, player))
					{
						num += UnlockedInventory.CountItems(item.GetInventory(), name, quality, matchWorldLevel);
					}
					ChestCountCache.Store(name, quality, matchWorldLevel, num);
					__result += num;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static class HaveItemPatch
		{
			private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (__result || !IsCraftingOrBuildingContext(__instance, out var player))
					{
						return;
					}
					foreach (Container item in NearbyContainers.Find(((Component)player).transform.pos