Decompiled source of ChestReach v0.1.0

ChestReach.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ChestReach;

[BepInPlugin("j1ga.chestreach", "ChestReach", "0.1.0")]
public class ChestReachPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	private static class Player_HaveRequirements_Piece_Patch
	{
		private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return;
			}
			try
			{
				instance.AfterHavePieceRequirements(__instance, piece, mode, ref __result);
			}
			catch (Exception e)
			{
				instance.Fail("Player.HaveRequirements(Piece)", e);
			}
		}
	}

	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	private static class Player_TryPlacePiece_Patch
	{
		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return true;
			}
			try
			{
				if (instance.BeforeTryPlacePiece(__instance, piece))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("Player.TryPlacePiece", e);
				instance._consume = null;
				__result = false;
				return false;
			}
		}

		private static void Postfix(bool __result)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null && !__result)
			{
				instance._consume = null;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	private static class Player_UpdatePlacement_Patch
	{
		private static void Prefix()
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance._consume = null;
			}
		}

		private static Exception Finalizer(Exception __exception)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance._consume = null;
			}
			return __exception;
		}
	}

	private sealed class ConsumeContext
	{
		public List<Box> Boxes;
	}

	[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
	private static class Player_HaveRequirementItems_Patch
	{
		private static void Postfix(Player __instance, Recipe piece, bool discover, int qualityLevel, int amount, ref bool __result)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return;
			}
			try
			{
				instance.AfterHaveRequirementItems(__instance, piece, discover, qualityLevel, amount, ref __result);
			}
			catch (Exception e)
			{
				instance.Fail("Player.HaveRequirementItems", e);
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")]
	private static class InventoryGui_OnCraftPressed_Patch
	{
		private static void Postfix(InventoryGui __instance)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return;
			}
			try
			{
				instance.AfterCraftPressed(__instance);
			}
			catch (Exception e)
			{
				instance.Fail("InventoryGui.OnCraftPressed", e);
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	private static class InventoryGui_DoCrafting_Patch
	{
		private static bool Prefix(InventoryGui __instance, Player player)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return true;
			}
			try
			{
				return instance.BeforeDoCrafting(__instance, player);
			}
			catch (Exception e)
			{
				instance.Fail("InventoryGui.DoCrafting", e);
				instance._consume = null;
				instance._craftHold = false;
				return false;
			}
		}

		private static Exception Finalizer(Exception __exception)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance._consume = null;
			}
			return __exception;
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
	private static class InventoryGui_UpdateRecipe_Patch
	{
		private static void Postfix(InventoryGui __instance)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance._craftHold)
			{
				return;
			}
			try
			{
				_craftTimer.SetValue(__instance, 1000f);
			}
			catch (Exception e)
			{
				instance.Fail("InventoryGui.UpdateRecipe", e);
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	private static class InventoryGui_Hide_Patch
	{
		private static void Postfix()
		{
			ChestReachPlugin instance = Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance._craftHold = false;
				instance._craftHoldStart = -1f;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	private static class Player_ConsumeResources_Patch
	{
		private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._consume == null)
			{
				return;
			}
			try
			{
				instance.BeforeConsume(__instance, requirements, qualityLevel, itemQuality, multiplier);
			}
			catch (Exception e)
			{
				instance.Fail("Player.ConsumeResources", e);
			}
		}
	}

	internal sealed class Box
	{
		public Container C;

		public Inventory Inv;

		public ZNetView View;

		public Piece Piece;

		public string Prefab;

		public bool Tomb;

		public bool Cart;

		public bool Ship;

		public bool World;

		public bool Dirty = true;

		public int WorldLevel = int.MinValue;

		public readonly Dictionary<string, int> Counts = new Dictionary<string, int>();

		public bool Alive
		{
			get
			{
				if ((Object)(object)C != (Object)null && (Object)(object)View != (Object)null)
				{
					return View.IsValid();
				}
				return false;
			}
		}

		public bool Owned
		{
			get
			{
				if (Alive)
				{
					return View.IsOwner();
				}
				return false;
			}
		}

		public Vector3 Pos => ((Component)C).transform.position;

		public int Count(string name)
		{
			if (Dirty || WorldLevel != Game.m_worldLevel)
			{
				Recount();
			}
			if (!Counts.TryGetValue(name, out var value))
			{
				return 0;
			}
			return value;
		}

		public void Recount()
		{
			Counts.Clear();
			Dirty = false;
			WorldLevel = Game.m_worldLevel;
			if (Inv == null)
			{
				return;
			}
			foreach (ItemData allItem in Inv.GetAllItems())
			{
				if (allItem != null && allItem.m_shared != null && allItem.m_worldLevel >= Game.m_worldLevel)
				{
					Counts.TryGetValue(allItem.m_shared.m_name, out var value);
					Counts[allItem.m_shared.m_name] = value + allItem.m_stack;
				}
			}
		}
	}

	internal sealed class Stock
	{
		public Vector3 Center;

		public float Range;

		public int Version;

		public float Time;

		public readonly List<Box> Boxes = new List<Box>();

		public readonly Dictionary<string, int> Total = new Dictionary<string, int>();

		public int Count(string name)
		{
			if (!Total.TryGetValue(name, out var value))
			{
				return 0;
			}
			return value;
		}
	}

	[HarmonyPatch(typeof(Container), "Awake")]
	private static class Container_Awake_Patch
	{
		private static void Postfix(Container __instance)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return;
			}
			try
			{
				instance.Register(__instance);
			}
			catch (Exception e)
			{
				instance.Fail("Container.Awake", e);
			}
		}
	}

	internal enum Own
	{
		Ready,
		Pending,
		Failed
	}

	private sealed class Request
	{
		public Box B;

		public float Sent;

		public bool Granted;

		public bool Denied;

		public bool Manual;
	}

	[HarmonyPatch(typeof(Container), "RPC_OpenResponse")]
	private static class Container_RPC_OpenResponse_Patch
	{
		private static bool Prefix(Container __instance, bool granted)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			try
			{
				if (!instance._requests.TryGetValue(__instance, out var value))
				{
					return true;
				}
				if (granted)
				{
					value.Granted = true;
				}
				else
				{
					value.Denied = true;
				}
				return value.Manual || instance.OpenedByHand(__instance);
			}
			catch (Exception e)
			{
				instance.Fail("Container.RPC_OpenResponse", e);
				return true;
			}
		}
	}

	[HarmonyPatch(typeof(Container), "Interact")]
	private static class Container_Interact_Patch
	{
		private static void Prefix(Container __instance, bool hold)
		{
			ChestReachPlugin instance = Instance;
			if (!((Object)(object)instance == (Object)null) && !hold)
			{
				instance._manualAt[__instance] = Time.time;
				if (instance._requests.TryGetValue(__instance, out var value))
				{
					value.Manual = true;
				}
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "RepairOneItem")]
	private static class InventoryGui_RepairOneItem_Patch
	{
		private static bool Prefix(InventoryGui __instance)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return true;
			}
			try
			{
				return instance.BeforeRepairOne(__instance);
			}
			catch (Exception e)
			{
				instance.Fail("InventoryGui.RepairOneItem", e);
				instance._repairingAll = false;
				return true;
			}
		}
	}

	private sealed class Fetched
	{
		public Box B;

		public string Name;

		public int After;
	}

	private sealed class StationRetry
	{
		public Box B;

		public Action Run;

		public float Until;
	}

	[HarmonyPatch(typeof(Fireplace), "Interact")]
	private static class Fireplace_Interact_Patch
	{
		private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || hold || !instance.StationsOn(instance._cfgRefuel))
			{
				return true;
			}
			try
			{
				if (!__instance.m_canRefill || __instance.m_infiniteFuel || (Object)(object)__instance.m_fuelItem == (Object)null)
				{
					return true;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || component.GetZDO() == null)
				{
					return true;
				}
				float num = component.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
				if (__instance.m_canTurnOff && !alt && num > 0f)
				{
					return true;
				}
				if ((float)Mathf.CeilToInt(num) >= __instance.m_maxFuel)
				{
					return true;
				}
				Fireplace fp = __instance;
				Humanoid u = user;
				bool a = alt;
				if (instance.BeforeStation(user, (Component)(object)__instance, Names(__instance.m_fuelItem), delegate
				{
					fp.Interact(u, false, a);
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("Fireplace.Interact", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("Fireplace.Interact", e);
			}
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
	private static class Smelter_OnAddFuel_Patch
	{
		private static bool Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel))
			{
				return true;
			}
			try
			{
				Smelter sm = __instance;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, Names(__instance.m_fuelItem), delegate
				{
					_smelterAddFuel.Invoke(sm, new object[3] { sw, u, null });
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("Smelter.OnAddFuel", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("Smelter.OnAddFuel", e);
			}
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnAddOre")]
	private static class Smelter_OnAddOre_Patch
	{
		private static bool Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgLoad))
			{
				return true;
			}
			try
			{
				List<string> list = new List<string>();
				foreach (ItemConversion item2 in __instance.m_conversion)
				{
					if (item2 != null && (Object)(object)item2.m_from != (Object)null && !list.Contains(item2.m_from.m_itemData.m_shared.m_name))
					{
						list.Add(item2.m_from.m_itemData.m_shared.m_name);
					}
				}
				Smelter sm = __instance;
				Switch s = sw;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate
				{
					_smelterAddOre.Invoke(sm, new object[3] { s, u, null });
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("Smelter.OnAddOre", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("Smelter.OnAddOre", e);
			}
		}
	}

	[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
	private static class CookingStation_OnAddFuelSwitch_Patch
	{
		private static bool Prefix(CookingStation __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel) || !__instance.m_useFuel)
			{
				return true;
			}
			try
			{
				CookingStation cs = __instance;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, Names(__instance.m_fuelItem), delegate
				{
					_cookingAddFuel.Invoke(cs, new object[3] { sw, u, null });
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("CookingStation.OnAddFuelSwitch", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("CookingStation.OnAddFuelSwitch", e);
			}
		}
	}

	[HarmonyPatch(typeof(CookingStation), "OnInteract")]
	private static class CookingStation_OnInteract_Patch
	{
		private static bool Prefix(CookingStation __instance, Humanoid user, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.StationsOn(instance._cfgCook))
			{
				return true;
			}
			try
			{
				if ((bool)_cookingHaveDone.Invoke(__instance, null))
				{
					return true;
				}
				List<string> list = new List<string>();
				foreach (ItemConversion item in __instance.m_conversion)
				{
					if (item != null && (Object)(object)item.m_from != (Object)null && !list.Contains(item.m_from.m_itemData.m_shared.m_name))
					{
						list.Add(item.m_from.m_itemData.m_shared.m_name);
					}
				}
				CookingStation cs = __instance;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate
				{
					_cookingInteract.Invoke(cs, new object[1] { u });
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("CookingStation.OnInteract", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("CookingStation.OnInteract", e);
			}
		}
	}

	[HarmonyPatch(typeof(Fermenter), "Interact")]
	private static class Fermenter_Interact_Patch
	{
		private static bool Prefix(Fermenter __instance, Humanoid user, bool hold, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || hold || !instance.StationsOn(instance._cfgCook))
			{
				return true;
			}
			try
			{
				if (Convert.ToInt32(_fermenterStatus.Invoke(__instance, null)) != 0)
				{
					return true;
				}
				List<string> list = new List<string>();
				foreach (ItemConversion item in __instance.m_conversion)
				{
					if (item != null && (Object)(object)item.m_from != (Object)null && !list.Contains(item.m_from.m_itemData.m_shared.m_name))
					{
						list.Add(item.m_from.m_itemData.m_shared.m_name);
					}
				}
				Fermenter f = __instance;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate
				{
					f.Interact(u, false, false);
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("Fermenter.Interact", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("Fermenter.Interact", e);
			}
		}
	}

	[HarmonyPatch(typeof(ShieldGenerator), "OnAddFuel")]
	private static class ShieldGenerator_OnAddFuel_Patch
	{
		private static bool Prefix(ShieldGenerator __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state)
		{
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel))
			{
				return true;
			}
			try
			{
				ShieldGenerator sg = __instance;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, Names((IEnumerable<ItemDrop>)__instance.m_fuelItems), delegate
				{
					_shieldAddFuel.Invoke(sg, new object[3] { sw, u, null });
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("ShieldGenerator.OnAddFuel", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("ShieldGenerator.OnAddFuel", e);
			}
		}
	}

	[HarmonyPatch(typeof(Turret), "UseItem")]
	private static class Turret_UseItem_Patch
	{
		private static bool Prefix(Turret __instance, Humanoid user, ItemData item, ref bool __result, out Fetched __state)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel))
			{
				return true;
			}
			try
			{
				List<string> list = new List<string>();
				if (__instance.GetAmmo() > 0 && (Object)(object)ZNetScene.instance != (Object)null)
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(__instance.GetAmmoType());
					ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val != (Object)null)
					{
						list.Add(val.m_itemData.m_shared.m_name);
					}
				}
				else
				{
					foreach (AmmoType item2 in __instance.m_allowedAmmo)
					{
						if ((Object)(object)item2.m_ammo != (Object)null && !list.Contains(item2.m_ammo.m_itemData.m_shared.m_name))
						{
							list.Add(item2.m_ammo.m_itemData.m_shared.m_name);
						}
					}
				}
				Turret t = __instance;
				Humanoid u = user;
				if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate
				{
					t.UseItem(u, (ItemData)null);
				}, out __state))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception e)
			{
				instance.Fail("Turret.UseItem", e);
				return true;
			}
		}

		private static void Postfix(Humanoid user, Fetched __state)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null)
			{
				return;
			}
			try
			{
				instance.AfterStation(user, __state);
			}
			catch (Exception e)
			{
				instance.Fail("Turret.UseItem", e);
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "Awake")]
	private static class ZNet_Awake_Patch
	{
		private static void Postfix()
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				instance.RegisterRpc();
			}
			catch (Exception e)
			{
				instance.Fail("ZNet.Awake", e);
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	private static class ZNet_RPC_PeerInfo_Patch
	{
		private static void Postfix(ZNet __instance, ZRpc rpc)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return;
			}
			try
			{
				instance.OnPeerInfo(__instance, rpc);
			}
			catch (Exception e)
			{
				instance.Fail("ZNet.RPC_PeerInfo", e);
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "OnDestroy")]
	private static class ZNet_OnDestroy_Patch
	{
		private static void Postfix()
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				((MonoBehaviour)instance).StopAllCoroutines();
				instance.ResetWorld();
			}
			catch (Exception e)
			{
				instance.Fail("ZNet.OnDestroy", e);
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	private static class InventoryGui_SetupRequirement_Patch
	{
		private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors || !__result)
			{
				return;
			}
			try
			{
				instance.AfterSetupRequirement(elementRoot, req, player, quality, craftMultiplier);
			}
			catch (Exception e)
			{
				instance.Fail("InventoryGui.SetupRequirement", e);
			}
		}
	}

	[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
	private static class Hud_SetupPieceInfo_Patch
	{
		private static void Prefix()
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance._rowsForBuild = true;
			}
		}

		private static Exception Finalizer(Exception __exception)
		{
			ChestReachPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance._rowsForBuild = false;
			}
			return __exception;
		}
	}

	private const float PrefetchInterval = 0.5f;

	private const float PrefetchRepeat = 5f;

	private const float MaxRange = 50f;

	private const float CraftWait = 4f;

	public const string Guid = "j1ga.chestreach";

	public const string Name = "ChestReach";

	public const string Version = "0.1.0";

	private const int MaxErrors = 25;

	private const float RequestTimeout = 3f;

	private const float RefusedPause = 5f;

	private const int RepairsPerFrame = 3;

	private const string RpcName = "j1ga.chestreach.config";

	private const int PacketVersion = 1;

	private float _nextPrefetch;

	private readonly Dictionary<Box, float> _prefetched = new Dictionary<Box, float>();

	private ConfigEntry<bool> _cfgEnabled;

	private ConfigEntry<bool> _cfgDebug;

	private ConfigEntry<bool> _cfgCraft;

	private ConfigEntry<float> _cfgCraftRange;

	private ConfigEntry<bool> _cfgBuild;

	private ConfigEntry<float> _cfgBuildRange;

	private ConfigEntry<bool> _cfgRefuel;

	private ConfigEntry<bool> _cfgLoad;

	private ConfigEntry<bool> _cfgCook;

	private ConfigEntry<float> _cfgStationRange;

	private ConfigEntry<bool> _cfgCarts;

	private ConfigEntry<bool> _cfgShips;

	private ConfigEntry<bool> _cfgDungeon;

	private ConfigEntry<bool> _cfgWardAll;

	private ConfigEntry<string> _cfgExcluded;

	private ConfigEntry<bool> _cfgRepairAll;

	private ConfigEntry<bool> _cfgAreaRepair;

	private ConfigEntry<KeyboardShortcut> _cfgAreaRepairKey;

	private ConfigEntry<float> _cfgAreaRepairRadius;

	private ConfigEntry<bool> _cfgShowTotal;

	private ConfigEntry<bool> _cfgShowTaken;

	private ConfigEntry<bool> _cfgTooltip;

	private ConfigEntry<Color> _cfgCoveredColor;

	private ConfigEntry<bool> _cfgSync;

	private readonly List<ConfigEntryBase> _synced = new List<ConfigEntryBase>();

	private readonly HashSet<string> _excluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private readonly HashSet<string> _serverExcluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private static readonly Color CoveredDefault = new Color(0.3f, 0.72f, 1f, 1f);

	private static readonly Color CoveredDefaultV1 = new Color(0.62f, 0.83f, 1f, 1f);

	private ConsumeContext _consume;

	private bool _craftHold;

	private float _craftHoldStart = -1f;

	public static ChestReachPlugin Instance;

	private Harmony _harmony;

	private int _errorCount;

	private bool _disabledByErrors;

	private readonly HashSet<string> _loggedErrors = new HashSet<string>();

	private string _lastMessage;

	private float _lastMessageTime;

	private static readonly Dictionary<string, string[]> Texts = new Dictionary<string, string[]>
	{
		{
			"fetching",
			new string[2] { "Taking materials from the chests nearby... press again", "Беру материалы из сундуков рядом... нажмите ещё раз" }
		},
		{
			"waiting",
			new string[2] { "Waiting for the chests nearby...", "Жду сундуки рядом..." }
		},
		{
			"busy",
			new string[2] { "A chest nearby is in use or did not answer", "Сундук рядом занят или не ответил" }
		},
		{
			"short",
			new string[2] { "Not enough in the chests nearby: {0}", "Не хватает в сундуках рядом: {0}" }
		},
		{
			"invfull",
			new string[2] { "No room in the inventory for {0}", "Нет места в инвентаре для {0}" }
		},
		{
			"repaired",
			new string[2] { "Items repaired: {0}", "Починено предметов: {0}" }
		},
		{
			"area",
			new string[2] { "Pieces repaired: {0}", "Починено построек: {0}" }
		},
		{
			"area_none",
			new string[2] { "Nothing to repair nearby", "Рядом нечего чинить" }
		},
		{
			"area_station",
			new string[2] { "; {0} need a crafting station that reaches you", "; {0} требуют станцию, достающую до вас" }
		},
		{
			"taken",
			new string[2] { "From the chests: {0}", "Из сундуков: {0}" }
		},
		{
			"tooltip",
			new string[2] { "In inventory: {0} · In chests nearby: {1}", "В инвентаре: {0} · В сундуках рядом: {1}" }
		}
	};

	private readonly List<Box> _boxes = new List<Box>();

	private readonly Dictionary<Container, Box> _byContainer = new Dictionary<Container, Box>();

	private readonly List<Stock> _stocks = new List<Stock>();

	private int _indexVersion;

	private static FieldInfo _containerView;

	private static MethodInfo _containerLoad;

	private static FieldInfo _craftRecipe;

	private static FieldInfo _craftUpgradeItem;

	private static FieldInfo _multiCrafting;

	private static FieldInfo _craftTimer;

	private static FieldInfo _knownStations;

	private static MethodInfo _haveRepairable;

	private static MethodInfo _repairOne;

	private static MethodInfo _smelterAddOre;

	private static MethodInfo _smelterAddFuel;

	private static MethodInfo _cookingInteract;

	private static MethodInfo _cookingAddFuel;

	private static MethodInfo _cookingHaveDone;

	private static MethodInfo _fermenterStatus;

	private static MethodInfo _shieldAddFuel;

	private readonly Dictionary<Container, Request> _requests = new Dictionary<Container, Request>();

	private readonly Dictionary<Box, float> _refusedUntil = new Dictionary<Box, float>();

	private readonly Dictionary<Container, float> _manualAt = new Dictionary<Container, float>();

	private bool _repairingAll;

	private readonly Queue<WearNTear> _repairQueue = new Queue<WearNTear>();

	private int _repairDone;

	private int _repairNoStation;

	private StationRetry _stationRetry;

	private bool _serverSynced;

	private readonly Dictionary<ConfigEntryBase, object> _serverValues = new Dictionary<ConfigEntryBase, object>();

	private bool _syncDirty;

	private bool _rowsForBuild;

	private HashSet<string> Excluded
	{
		get
		{
			if (!_serverSynced || !_serverValues.ContainsKey((ConfigEntryBase)(object)_cfgExcluded))
			{
				return _excluded;
			}
			return _serverExcluded;
		}
	}

	private float CraftRange => Mathf.Clamp(Eff<float>(_cfgCraftRange), 1f, 50f);

	private float BuildRange => Mathf.Clamp(Eff<float>(_cfgBuildRange), 1f, 50f);

	private float StationRange => Mathf.Clamp(Eff<float>(_cfgStationRange), 1f, 50f);

	private bool CraftOn
	{
		get
		{
			if (Ready)
			{
				return Eff<bool>(_cfgCraft);
			}
			return false;
		}
	}

	private bool BuildOn
	{
		get
		{
			if (Ready)
			{
				return Eff<bool>(_cfgBuild);
			}
			return false;
		}
	}

	private bool Ready
	{
		get
		{
			if (!_disabledByErrors)
			{
				return Eff<bool>(_cfgEnabled);
			}
			return false;
		}
	}

	private int PendingRequests => _requests.Count;

	private bool BuildFree(Player p, Piece piece)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		if (p.NoCostCheat())
		{
			return true;
		}
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance != (Object)null)
		{
			return instance.GetGlobalKey(piece.FreeBuildKey());
		}
		return false;
	}

	private void AfterHavePieceRequirements(Player player, Piece piece, RequirementMode mode, ref bool result)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Invalid comparison between Unknown and I4
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Invalid comparison between Unknown and I4
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Invalid comparison between Unknown and I4
		if (result || (Object)(object)piece == (Object)null || (int)mode == 1 || !IsLocal((Humanoid)(object)player) || !BuildOn)
		{
			return;
		}
		if ((Object)(object)piece.m_craftingStation != (Object)null)
		{
			if ((int)mode == 2)
			{
				if (!(_knownStations.GetValue(player) is Dictionary<string, int> dictionary) || !dictionary.ContainsKey(piece.m_craftingStation.m_name))
				{
					return;
				}
			}
			else if (!Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position)) && ((Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27)))
			{
				return;
			}
		}
		if (piece.m_dlc.Length > 0 && ((Object)(object)DLCMan.instance == (Object)null || !DLCMan.instance.IsDLCInstalled(piece.m_dlc)))
		{
			return;
		}
		Stock stock = GetStock(((Component)player).transform.position, BuildRange);
		if (stock.Boxes.Count == 0)
		{
			return;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		Requirement[] resources = piece.m_resources;
		foreach (Requirement val in resources)
		{
			if (val == null || (Object)(object)val.m_resItem == (Object)null || val.m_amount <= 0)
			{
				continue;
			}
			string name = val.m_resItem.m_itemData.m_shared.m_name;
			if ((int)mode == 2)
			{
				if (!inventory.HaveItem(name, true) && stock.Count(name) <= 0)
				{
					return;
				}
			}
			else if (inventory.CountItems(name, -1, true) + stock.Count(name) < val.m_amount)
			{
				return;
			}
		}
		result = true;
	}

	private bool BeforeTryPlacePiece(Player p, Piece piece)
	{
		//IL_004a: 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)
		_consume = null;
		if (!IsLocal((Humanoid)(object)p) || !BuildOn || (Object)(object)piece == (Object)null || BuildFree(p, piece))
		{
			return true;
		}
		Dictionary<string, int> dictionary = Deficits(p, PieceNeeds(piece));
		if (dictionary.Count == 0)
		{
			return true;
		}
		Stock s = GetStock(((Component)p).transform.position, BuildRange);
		HashSet<Box> hashSet = new HashSet<Box>();
		for (int i = 0; i < 3; i++)
		{
			List<Box> list = Plan(s, dictionary, hashSet);
			if (list == null)
			{
				Tell((hashSet.Count > 0) ? T("busy") : T("short", Shortfall(dictionary, s)));
				return false;
			}
			switch (AcquireAll(list, hashSet))
			{
			case Own.Pending:
				Tell(T("fetching"));
				return false;
			case Own.Failed:
				continue;
			}
			if (!LiveCovers(list, dictionary))
			{
				s = BuildStock(((Component)p).transform.position, BuildRange);
				continue;
			}
			ConsumeContext consumeContext = new ConsumeContext();
			consumeContext.Boxes = list;
			_consume = consumeContext;
			return true;
		}
		Tell(T("busy"));
		return false;
	}

	private void UpdateBuildPrefetch()
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		if (Time.time < _nextPrefetch)
		{
			return;
		}
		_nextPrefetch = Time.time + 0.5f;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !BuildOn || !((Character)localPlayer).InPlaceMode() || localPlayer.InRepairMode())
		{
			return;
		}
		Piece selectedPiece = localPlayer.GetSelectedPiece();
		if ((Object)(object)selectedPiece == (Object)null || selectedPiece.m_repairPiece || selectedPiece.m_removePiece || BuildFree(localPlayer, selectedPiece))
		{
			return;
		}
		Dictionary<string, int> dictionary = Deficits(localPlayer, PieceNeeds(selectedPiece));
		if (dictionary.Count == 0)
		{
			return;
		}
		Stock stock = GetStock(((Component)localPlayer).transform.position, BuildRange);
		List<Box> list = Plan(stock, dictionary, null);
		if (list == null)
		{
			return;
		}
		if (_prefetched.Count > 64)
		{
			_prefetched.Clear();
		}
		foreach (Box item in list)
		{
			if (!item.Owned && (!_prefetched.TryGetValue(item, out var value) || !(Time.time - value < 5f)))
			{
				_prefetched[item] = Time.time;
				Acquire(item);
			}
		}
	}

	private void RegisterCommands()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		new ConsoleCommand("chestreach", "ChestReach. 'chestreach status' shows the settings in effect and the chests around you", (ConsoleEvent)delegate(ConsoleEventArgs args)
		{
			RunCommand(args);
		}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private static void Say(ConsoleEventArgs args, string text)
	{
		if (args != null && (Object)(object)args.Context != (Object)null)
		{
			args.Context.AddString(text);
		}
	}

	private void RunCommand(ConsoleEventArgs args)
	{
		try
		{
			string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : "");
			if (text == "status")
			{
				Say(args, StatusText());
			}
			else
			{
				Say(args, "chestreach status");
			}
		}
		catch (Exception ex)
		{
			Say(args, "chestreach: " + ex.Message);
			Fail("command", ex);
		}
	}

	private static string OnOff(bool v)
	{
		if (!v)
		{
			return "off";
		}
		return "on";
	}

	private string StatusValues()
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("enabled ").Append(OnOff(Eff<bool>(_cfgEnabled))).Append("; crafting ")
			.Append(OnOff(Eff<bool>(_cfgCraft)))
			.Append(" ")
			.Append(F(CraftRange))
			.Append(" m")
			.Append("; building ")
			.Append(OnOff(Eff<bool>(_cfgBuild)))
			.Append(" ")
			.Append(F(BuildRange))
			.Append(" m")
			.Append("; stations ")
			.Append(F(StationRange))
			.Append(" m: refuel ")
			.Append(OnOff(Eff<bool>(_cfgRefuel)))
			.Append(", ore ")
			.Append(OnOff(Eff<bool>(_cfgLoad)))
			.Append(", cook ")
			.Append(OnOff(Eff<bool>(_cfgCook)))
			.Append("; carts ")
			.Append(OnOff(Eff<bool>(_cfgCarts)))
			.Append(", ships ")
			.Append(OnOff(Eff<bool>(_cfgShips)))
			.Append(", world chests ")
			.Append(OnOff(Eff<bool>(_cfgDungeon)))
			.Append(", ward for all ")
			.Append(OnOff(Eff<bool>(_cfgWardAll)))
			.Append("; excluded ")
			.Append(Excluded.Count)
			.Append("; repair all ")
			.Append(OnOff(Eff<bool>(_cfgRepairAll)))
			.Append(", area repair ")
			.Append(OnOff(Eff<bool>(_cfgAreaRepair)))
			.Append(" ")
			.Append(F(Eff<float>(_cfgAreaRepairRadius)))
			.Append(" m.");
		return stringBuilder.ToString();
	}

	private string StatusText()
	{
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("ChestReach").Append(" ").Append("0.1.0")
			.Append(_disabledByErrors ? " - DISABLED after errors, see the log" : "")
			.Append('\n');
		stringBuilder.Append(_serverSynced ? "Settings from the server: " : "Local settings: ").Append(StatusValues()).Append('\n');
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			Prune();
			Stock stock = BuildStock(((Component)localPlayer).transform.position, BuildRange);
			int num = 0;
			foreach (Box box in stock.Boxes)
			{
				if (box.Owned)
				{
					num++;
				}
			}
			stringBuilder.Append("Chests loaded: ").Append(_boxes.Count).Append("; within ")
				.Append(F(BuildRange))
				.Append(" m of you and usable: ")
				.Append(stock.Boxes.Count)
				.Append(" (yours now: ")
				.Append(num)
				.Append("), ")
				.Append(stock.Total.Count)
				.Append(" kinds of items")
				.Append("; requests in flight: ")
				.Append(PendingRequests)
				.Append('.');
		}
		return stringBuilder.ToString();
	}

	private ConfigEntry<T> Synced<T>(ConfigEntry<T> e)
	{
		_synced.Add((ConfigEntryBase)(object)e);
		return e;
	}

	private ConfigEntry<float> Range(string section, string what)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		return Synced<float>(((BaseUnityPlugin)this).Config.Bind<float>(section, "RangeMeters", 20f, new ConfigDescription(what, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), new object[0])));
	}

	private void BindConfig()
	{
		//IL_0298: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e7: Expected O, but got Unknown
		//IL_0365: Unknown result type (might be due to invalid IL or missing references)
		_cfgEnabled = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Enabled", true, "Master switch. Off: crafting, building, stations and repair are vanilla."));
		_cfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Debug", false, "Log every chest request and every take.");
		_cfgCraft = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("02 Crafting", "Enabled", true, "Craft and upgrade with materials from the chests around the crafting station (around you when crafting by hand). Your inventory is used first."));
		_cfgCraftRange = Range("02 Crafting", "Chests up to this far from the crafting station count.");
		_cfgBuild = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("03 Building", "Enabled", true, "Build with materials from the chests around you: hammer, hoe, cultivator. Your inventory is used first."));
		_cfgBuildRange = Range("03 Building", "Chests up to this far from you count.");
		_cfgRefuel = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("04 Stations", "Refuel", true, "With nothing to put in in your inventory, take one fuel item from a chest: fires, torches and lamps, smelter and oven fuel, the shield generator, ballista ammo."));
		_cfgLoad = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("04 Stations", "LoadOre", true, "The same for what smelters process: ore into the smelter and furnace, wood into the charcoal kiln, flax and barley into the spinning wheel and windmill, sap into the eitr refinery."));
		_cfgCook = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("04 Stations", "Cook", true, "The same for food: cooking stations, the oven, and mead bases into the fermenter."));
		_cfgStationRange = Range("04 Stations", "Chests up to this far from the station count.");
		_cfgCarts = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "IncludeCarts", true, "Take from carts."));
		_cfgShips = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "IncludeShips", true, "Take from the storage of ships."));
		_cfgDungeon = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "IncludeWorldChests", true, "Take from chests the world placed (dungeons, villages), not only from those built by players."));
		_cfgWardAll = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "RequireWardAccess", false, "Require access to the ward for every chest. The game asks it only of the chests that check wards; those are always respected."));
		_cfgExcluded = Synced<string>(((BaseUnityPlugin)this).Config.Bind<string>("05 Chests", "ExcludedPrefabs", "", "Chest prefabs never taken from, comma separated. Example: piece_chest_private,piece_chest_blackmetal"));
		_cfgExcluded.SettingChanged += delegate
		{
			ReadExcluded();
		};
		ReadExcluded();
		_cfgRepairAll = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("06 Repair", "RepairAll", true, "One press of the repair button at a station repairs every item it can, not one."));
		_cfgAreaRepair = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("06 Repair", "AreaRepair", true, "The key below repairs the damaged buildings around you, as the hammer would one by one: wards and the crafting station a piece needs are respected, nothing is spent."));
		_cfgAreaRepairKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("06 Repair", "AreaRepairKey", new KeyboardShortcut((KeyCode)59, (KeyCode[])(object)new KeyCode[0]), "Key for the area repair. Ignored while typing or in a menu.");
		_cfgAreaRepairRadius = Synced<float>(((BaseUnityPlugin)this).Config.Bind<float>("06 Repair", "AreaRepairRadius", 50f, new ConfigDescription("Radius of the area repair, meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), new object[0])));
		_cfgShowTotal = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Display", "ShowAvailableAmount", true, "A material in a recipe or a piece reads 'available/needed': what you carry plus what is in the chests nearby, over what it takes. Off: only the amount needed, as in vanilla.");
		_cfgShowTaken = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Display", "ShowTakenMessage", true, "After a craft or a placement, a line in the top-left message log says what was taken from the chests.");
		_cfgTooltip = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Display", "ShowCountsInTooltip", true, "The tooltip of a material in a recipe or a piece tells how many you carry and how many are in the chests nearby.");
		_cfgCoveredColor = ((BaseUnityPlugin)this).Config.Bind<Color>("07 Display", "CoveredColor", CoveredDefault, "Colour of a material amount that your inventory alone does not cover but the chests nearby do.");
		_cfgSync = ((BaseUnityPlugin)this).Config.Bind<bool>("08 Sync", "SyncConfig", true, "The server sends its settings of sections 01-06 (except the key) to every connecting client with the mod and again when they change; the client uses them while connected. Players without the mod are never affected. Off on the server: every client uses its own file. Has no effect on a client.");
		MigrateConfig();
		((BaseUnityPlugin)this).Config.SettingChanged += delegate
		{
			_syncDirty = true;
		};
	}

	private void MigrateConfig()
	{
		//IL_0006: 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_0013: 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_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		Color value = _cfgCoveredColor.Value;
		if (Mathf.Abs(value.r - CoveredDefaultV1.r) < 0.01f && Mathf.Abs(value.g - CoveredDefaultV1.g) < 0.01f && Mathf.Abs(value.b - CoveredDefaultV1.b) < 0.01f)
		{
			_cfgCoveredColor.Value = CoveredDefault;
		}
	}

	private void ReadExcluded()
	{
		ReadList(_cfgExcluded.Value, _excluded);
		_indexVersion++;
	}

	private static void ReadList(string text, HashSet<string> into)
	{
		into.Clear();
		if (string.IsNullOrEmpty(text))
		{
			return;
		}
		string[] array = text.Split(',', ';');
		foreach (string text2 in array)
		{
			string text3 = text2.Trim();
			if (text3.Length > 0)
			{
				into.Add(text3);
			}
		}
	}

	private T Eff<T>(ConfigEntry<T> e)
	{
		if (_serverSynced && _serverValues.TryGetValue((ConfigEntryBase)(object)e, out var value) && value is T)
		{
			return (T)value;
		}
		return e.Value;
	}

	private static bool Counts(Requirement req, CraftingStation station)
	{
		if (req == null || (Object)(object)req.m_resItem == (Object)null)
		{
			return false;
		}
		if ((Object)(object)station != (Object)null && station.m_upgrader != req.m_upgraderResource)
		{
			return false;
		}
		if ((Object)(object)station == (Object)null && req.m_upgraderResource)
		{
			return false;
		}
		return true;
	}

	private static Dictionary<string, int> Needs(Player p, Requirement[] reqs, int quality, int multiplier)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		if (reqs == null)
		{
			return dictionary;
		}
		CraftingStation currentCraftingStation = p.GetCurrentCraftingStation();
		foreach (Requirement val in reqs)
		{
			if (Counts(val, currentCraftingStation))
			{
				int num = val.GetAmount(quality) * multiplier;
				if (num > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					dictionary.TryGetValue(name, out var value);
					dictionary[name] = value + num;
				}
			}
		}
		return dictionary;
	}

	private static Dictionary<string, int> PieceNeeds(Piece piece)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		if ((Object)(object)piece == (Object)null || piece.m_resources == null)
		{
			return dictionary;
		}
		Requirement[] resources = piece.m_resources;
		foreach (Requirement val in resources)
		{
			if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
			{
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				dictionary.TryGetValue(name, out var value);
				dictionary[name] = value + val.m_amount;
			}
		}
		return dictionary;
	}

	private static Dictionary<string, int> Deficits(Player p, Dictionary<string, int> need)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		Inventory inventory = ((Humanoid)p).GetInventory();
		foreach (KeyValuePair<string, int> item in need)
		{
			int num = item.Value - inventory.CountItems(item.Key, -1, true);
			if (num > 0)
			{
				dictionary[item.Key] = num;
			}
		}
		return dictionary;
	}

	private static Vector3 CraftCenter(Player p)
	{
		//IL_0022: 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)
		CraftingStation currentCraftingStation = p.GetCurrentCraftingStation();
		if (!((Object)(object)currentCraftingStation != (Object)null))
		{
			return ((Component)p).transform.position;
		}
		return ((Component)currentCraftingStation).transform.position;
	}

	private bool CraftFree(Player p)
	{
		if (!p.NoCostCheat())
		{
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				return ZoneSystem.instance.GetGlobalKey((GlobalKeys)25);
			}
			return false;
		}
		return true;
	}

	private void CraftJob(InventoryGui gui, Player p, out Recipe recipe, out Dictionary<string, int> deficits)
	{
		object? value = _craftRecipe.GetValue(gui);
		recipe = (Recipe)((value is Recipe) ? value : null);
		deficits = null;
		if (!((Object)(object)recipe == (Object)null))
		{
			object? value2 = _craftUpgradeItem.GetValue(gui);
			ItemData val = (ItemData)((value2 is ItemData) ? value2 : null);
			int quality = ((val == null) ? 1 : (val.m_quality + 1));
			int multiplier = ((!(bool)_multiCrafting.GetValue(gui)) ? 1 : Math.Max(1, gui.m_multiCraftAmount));
			if (!recipe.m_requireOnlyOneIngredient)
			{
				deficits = Deficits(p, Needs(p, recipe.m_resources, quality, multiplier));
			}
		}
	}

	private void AfterHaveRequirementItems(Player player, Recipe recipe, bool discover, int quality, int amount, ref bool result)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		if (result || discover || (Object)(object)recipe == (Object)null || recipe.m_requireOnlyOneIngredient || !IsLocal((Humanoid)(object)player) || !CraftOn)
		{
			return;
		}
		Stock stock = GetStock(CraftCenter(player), CraftRange);
		if (stock.Boxes.Count == 0)
		{
			return;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
		Requirement[] resources = recipe.m_resources;
		foreach (Requirement val in resources)
		{
			if (!Counts(val, currentCraftingStation))
			{
				continue;
			}
			int num = val.GetAmount(quality) * amount;
			if (num > 0)
			{
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				if (inventory.CountItems(name, -1, true) + stock.Count(name) < num)
				{
					return;
				}
			}
		}
		result = true;
	}

	private void AfterCraftPressed(InventoryGui gui)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !CraftOn || CraftFree(localPlayer))
		{
			return;
		}
		CraftJob(gui, localPlayer, out var _, out var deficits);
		if (deficits != null && deficits.Count != 0)
		{
			Stock stock = GetStock(CraftCenter(localPlayer), CraftRange);
			List<Box> list = Plan(stock, deficits, null);
			if (list != null)
			{
				AcquireAll(list, null);
			}
		}
	}

	private bool BeforeDoCrafting(InventoryGui gui, Player p)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		_craftHold = false;
		_consume = null;
		if (!IsLocal((Humanoid)(object)p) || !CraftOn || CraftFree(p))
		{
			return true;
		}
		CraftJob(gui, p, out var _, out var deficits);
		if (deficits == null || deficits.Count == 0)
		{
			_craftHoldStart = -1f;
			return true;
		}
		Stock s = GetStock(CraftCenter(p), CraftRange);
		HashSet<Box> hashSet = new HashSet<Box>();
		for (int i = 0; i < 3; i++)
		{
			List<Box> list = Plan(s, deficits, hashSet);
			if (list == null)
			{
				_craftHoldStart = -1f;
				Tell((hashSet.Count > 0) ? T("busy") : T("short", Shortfall(deficits, s)));
				return hashSet.Count == 0;
			}
			switch (AcquireAll(list, hashSet))
			{
			case Own.Pending:
				if (_craftHoldStart < 0f)
				{
					_craftHoldStart = Time.time;
				}
				if (Time.time - _craftHoldStart > 4f)
				{
					_craftHoldStart = -1f;
					Tell(T("busy"));
					return false;
				}
				_craftHold = true;
				return false;
			default:
			{
				if (!LiveCovers(list, deficits))
				{
					s = BuildStock(CraftCenter(p), CraftRange);
					break;
				}
				_craftHoldStart = -1f;
				ConsumeContext consumeContext = new ConsumeContext();
				consumeContext.Boxes = list;
				_consume = consumeContext;
				return true;
			}
			case Own.Failed:
				break;
			}
		}
		_craftHoldStart = -1f;
		Tell(T("busy"));
		return false;
	}

	private void BeforeConsume(Player p, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier)
	{
		ConsumeContext consume = _consume;
		if (consume == null || !IsLocal((Humanoid)(object)p) || requirements == null)
		{
			return;
		}
		_consume = null;
		Inventory inventory = ((Humanoid)p).GetInventory();
		CraftingStation currentCraftingStation = p.GetCurrentCraftingStation();
		List<string> list = new List<string>();
		foreach (Requirement val in requirements)
		{
			if (!Counts(val, currentCraftingStation))
			{
				continue;
			}
			int num = val.GetAmount(qualityLevel) * multiplier;
			if (num <= 0)
			{
				continue;
			}
			string name = val.m_resItem.m_itemData.m_shared.m_name;
			int num2 = num - inventory.CountItems(name, itemQuality, true);
			if (num2 > 0)
			{
				int num3 = Take(consume.Boxes, name, num2);
				if (num3 > 0)
				{
					list.Add(ItemName(name) + " x" + num3);
				}
				if (num3 < num2)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Took " + num3 + " of " + num2 + " " + name + " from the chests; the rest was not there any more."));
				}
			}
		}
		if (list.Count > 0 && _cfgShowTaken.Value)
		{
			((Character)p).Message((MessageType)1, T("taken", string.Join(", ", list.ToArray())), 0, (Sprite)null, false);
		}
	}

	private void Awake()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		try
		{
			Instance = this;
			BindConfig();
			FindReflection();
			RegisterCommands();
			_harmony = new Harmony("j1ga.chestreach");
			_harmony.PatchAll(typeof(ChestReachPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ChestReach 0.1.0 loaded.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Awake failed, mod is inert: " + ex));
			_disabledByErrors = true;
		}
	}

	private void Update()
	{
		if (_disabledByErrors)
		{
			return;
		}
		try
		{
			if (_syncDirty)
			{
				FlushSync();
			}
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				UpdateOwnership();
				UpdateStationRetry();
				UpdateBuildPrefetch();
				UpdateAreaRepair();
			}
		}
		catch (Exception e)
		{
			Fail("Update", e);
		}
	}

	private void OnDestroy()
	{
		try
		{
			((MonoBehaviour)this).StopAllCoroutines();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("OnDestroy: " + ex.Message));
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void ResetWorld()
	{
		ClearIndex();
		ClearOwnership();
		ClearServerValues();
		_consume = null;
		_craftHold = false;
		_stationRetry = null;
		_repairQueue.Clear();
	}

	private static bool IsLocal(Humanoid h)
	{
		if ((Object)(object)h != (Object)null)
		{
			return (Object)(object)h == (Object)(object)Player.m_localPlayer;
		}
		return false;
	}

	private static long MyPlayerId()
	{
		Game instance = Game.instance;
		if (!((Object)(object)instance != (Object)null) || instance.GetPlayerProfile() == null)
		{
			return 0L;
		}
		return instance.GetPlayerProfile().GetPlayerID();
	}

	private static string PrefabName(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return "";
		}
		string name = ((Object)go).name;
		int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
		if (num <= 0)
		{
			return name;
		}
		return name.Substring(0, num);
	}

	private static string F(float v)
	{
		return v.ToString("0.##", CultureInfo.InvariantCulture);
	}

	private void Debug(string text)
	{
		if (_cfgDebug.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)text);
		}
	}

	private void Tell(string text)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && !string.IsNullOrEmpty(text) && (!(text == _lastMessage) || !(Time.time - _lastMessageTime < 1f)))
		{
			_lastMessage = text;
			_lastMessageTime = Time.time;
			((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
	}

	private void Fail(string where, Exception e)
	{
		string text = where + ": " + e.GetType().Name + ": " + e.Message;
		if (_loggedErrors.Add(text))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)(text + "\n" + e.StackTrace));
		}
		if (++_errorCount >= 25 && !_disabledByErrors)
		{
			_disabledByErrors = true;
			_consume = null;
			((BaseUnityPlugin)this).Logger.LogError((object)"Too many errors, ChestReach is now inert until the game restarts.");
		}
	}

	private static bool Russian()
	{
		Localization instance = Localization.instance;
		if (instance != null)
		{
			return instance.GetSelectedLanguage() == "Russian";
		}
		return false;
	}

	private static string T(string key, params object[] args)
	{
		if (!Texts.TryGetValue(key, out var value))
		{
			return key;
		}
		string text = (Russian() ? value[1] : value[0]);
		if (args == null || args.Length <= 0)
		{
			return text;
		}
		return string.Format(text, args);
	}

	private static string ItemName(string sharedName)
	{
		Localization instance = Localization.instance;
		if (instance == null)
		{
			return sharedName;
		}
		return instance.Localize(sharedName);
	}

	private void FindReflection()
	{
		_containerView = AccessTools.Field(typeof(Container), "m_nview");
		_containerLoad = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null);
		_craftRecipe = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");
		_craftUpgradeItem = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem");
		_multiCrafting = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting");
		_craftTimer = AccessTools.Field(typeof(InventoryGui), "m_craftTimer");
		_knownStations = AccessTools.Field(typeof(Player), "m_knownStations");
		_haveRepairable = AccessTools.Method(typeof(InventoryGui), "HaveRepairableItems", (Type[])null, (Type[])null);
		_repairOne = AccessTools.Method(typeof(InventoryGui), "RepairOneItem", (Type[])null, (Type[])null);
		_smelterAddOre = AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null);
		_smelterAddFuel = AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null);
		_cookingInteract = AccessTools.Method(typeof(CookingStation), "OnInteract", (Type[])null, (Type[])null);
		_cookingAddFuel = AccessTools.Method(typeof(CookingStation), "OnAddFuelSwitch", (Type[])null, (Type[])null);
		_cookingHaveDone = AccessTools.Method(typeof(CookingStation), "HaveDoneItem", (Type[])null, (Type[])null);
		_fermenterStatus = AccessTools.Method(typeof(Fermenter), "GetStatus", (Type[])null, (Type[])null);
		_shieldAddFuel = AccessTools.Method(typeof(ShieldGenerator), "OnAddFuel", (Type[])null, (Type[])null);
		if (_containerView == null || _containerLoad == null)
		{
			throw new MissingMemberException("Container.m_nview / Container.Load not found: the game has changed, ChestReach cannot work.");
		}
	}

	private void Register(Container c)
	{
		if ((Object)(object)c == (Object)null || _byContainer.ContainsKey(c))
		{
			return;
		}
		Inventory inventory = c.GetInventory();
		object? value = _containerView.GetValue(c);
		ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
		if (inventory != null && !((Object)(object)val == (Object)null) && val.GetZDO() != null)
		{
			Box b = new Box();
			b.C = c;
			b.Inv = inventory;
			b.View = val;
			b.Piece = ((Component)c).GetComponent<Piece>();
			b.Prefab = PrefabName(((Component)val).gameObject);
			b.Tomb = (Object)(object)((Component)c).GetComponent<TombStone>() != (Object)null;
			b.Cart = (Object)(object)c.m_wagon != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null;
			b.Ship = (Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null;
			b.World = !b.Cart && !b.Ship && ((Object)(object)b.Piece == (Object)null || !b.Piece.IsPlacedByPlayer());
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, (Action)delegate
			{
				b.Dirty = true;
				_indexVersion++;
			});
			_boxes.Add(b);
			_byContainer[c] = b;
			_indexVersion++;
		}
	}

	private Box BoxOf(Container c)
	{
		if (!((Object)(object)c != (Object)null) || !_byContainer.TryGetValue(c, out var value))
		{
			return null;
		}
		return value;
	}

	private void Prune()
	{
		for (int num = _boxes.Count - 1; num >= 0; num--)
		{
			Box box = _boxes[num];
			if (!box.Alive)
			{
				_boxes.RemoveAt(num);
				if (!object.ReferenceEquals(box.C, null))
				{
					_byContainer.Remove(box.C);
				}
				_indexVersion++;
			}
		}
		if (_byContainer.Count == _boxes.Count)
		{
			return;
		}
		_byContainer.Clear();
		foreach (Box box2 in _boxes)
		{
			_byContainer[box2.C] = box2;
		}
	}

	private void ClearIndex()
	{
		_boxes.Clear();
		_byContainer.Clear();
		_stocks.Clear();
		_indexVersion++;
	}

	private bool Eligible(Box b, long me)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Invalid comparison between Unknown and I4
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		if (!b.Alive)
		{
			return false;
		}
		if (b.Tomb)
		{
			return false;
		}
		if (b.Cart && !Eff<bool>(_cfgCarts))
		{
			return false;
		}
		if (b.Ship && !Eff<bool>(_cfgShips))
		{
			return false;
		}
		if (b.World && !Eff<bool>(_cfgDungeon))
		{
			return false;
		}
		if (Excluded.Contains(b.Prefab))
		{
			return false;
		}
		Container c = b.C;
		if ((int)c.m_privacy == 0 && ((Object)(object)b.Piece == (Object)null || b.Piece.GetCreator() != me))
		{
			return false;
		}
		if ((int)c.m_privacy == 1)
		{
			return false;
		}
		if ((c.m_checkGuardStone || Eff<bool>(_cfgWardAll)) && !PrivateArea.CheckAccess(b.Pos, 0f, false, false))
		{
			return false;
		}
		if (!b.View.IsOwner())
		{
			ZDO zDO = b.View.GetZDO();
			if (zDO == null || zDO.GetInt(ZDOVars.s_inUse, 0) == 1)
			{
				return false;
			}
			if ((Object)(object)c.m_wagon != (Object)null && c.m_wagon.InUse())
			{
				return false;
			}
		}
		return true;
	}

	private Stock GetStock(Vector3 center, float range)
	{
		//IL_006e: 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_0043: 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)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		float time = Time.time;
		for (int i = 0; i < _stocks.Count; i++)
		{
			Stock stock = _stocks[i];
			if (stock.Version == _indexVersion && stock.Range == range && time - stock.Time < 1f)
			{
				Vector3 val = stock.Center - center;
				if (((Vector3)(ref val)).sqrMagnitude < 0.25f)
				{
					return stock;
				}
			}
		}
		Stock stock2 = BuildStock(center, range);
		if (_stocks.Count >= 8)
		{
			_stocks.RemoveAt(0);
		}
		_stocks.Add(stock2);
		return stock2;
	}

	private Stock BuildStock(Vector3 center, float range)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		Prune();
		Stock stock = new Stock();
		stock.Center = center;
		stock.Range = range;
		stock.Version = _indexVersion;
		stock.Time = Time.time;
		long me = MyPlayerId();
		float num = range * range;
		List<KeyValuePair<float, Box>> list = new List<KeyValuePair<float, Box>>();
		foreach (Box box in _boxes)
		{
			Vector3 val = box.Pos - center;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (!(sqrMagnitude > num) && Eligible(box, me))
			{
				list.Add(new KeyValuePair<float, Box>(sqrMagnitude, box));
			}
		}
		list.Sort((KeyValuePair<float, Box> a, KeyValuePair<float, Box> z) => a.Key.CompareTo(z.Key));
		foreach (KeyValuePair<float, Box> item in list)
		{
			Box value = item.Value;
			stock.Boxes.Add(value);
			if (value.Dirty || value.WorldLevel != Game.m_worldLevel)
			{
				value.Recount();
			}
			foreach (KeyValuePair<string, int> count in value.Counts)
			{
				stock.Total.TryGetValue(count.Key, out var value2);
				stock.Total[count.Key] = value2 + count.Value;
			}
		}
		return stock;
	}

	private static List<Box> Plan(Stock s, Dictionary<string, int> deficits, HashSet<Box> skip)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>(deficits);
		List<string> list = new List<string>(deficits.Keys);
		List<Box> list2 = new List<Box>();
		int num = 0;
		foreach (int value in dictionary.Values)
		{
			num += Math.Max(0, value);
		}
		if (num == 0)
		{
			return list2;
		}
		for (int i = 0; i < 2; i++)
		{
			foreach (Box box in s.Boxes)
			{
				if (!box.Alive || (skip != null && skip.Contains(box)) || i == 0 != box.Owned)
				{
					continue;
				}
				bool flag = false;
				foreach (string item in list)
				{
					int num2 = dictionary[item];
					if (num2 > 0)
					{
						int num3 = box.Count(item);
						if (num3 > 0)
						{
							int num4 = Math.Min(num2, num3);
							dictionary[item] = num2 - num4;
							num -= num4;
							flag = true;
						}
					}
				}
				if (flag)
				{
					list2.Add(box);
				}
				if (num <= 0)
				{
					return list2;
				}
			}
		}
		return null;
	}

	private static bool LiveCovers(List<Box> plan, Dictionary<string, int> deficits)
	{
		foreach (KeyValuePair<string, int> deficit in deficits)
		{
			if (deficit.Value <= 0)
			{
				continue;
			}
			int num = 0;
			foreach (Box item in plan)
			{
				if (item.Owned)
				{
					num += item.Inv.CountItems(deficit.Key, -1, true);
					if (num >= deficit.Value)
					{
						break;
					}
				}
			}
			if (num < deficit.Value)
			{
				return false;
			}
		}
		return true;
	}

	private int Take(List<Box> boxes, string name, int amount)
	{
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		foreach (Box box in boxes)
		{
			if (amount - num <= 0)
			{
				break;
			}
			if (box.Owned)
			{
				int num2 = box.Inv.CountItems(name, -1, true);
				if (num2 > 0)
				{
					int num3 = Math.Min(num2, amount - num);
					box.Inv.RemoveItem(name, num3, -1, true);
					num += num3;
					Debug("took " + num3 + " " + name + " from " + box.Prefab + " at " + Pos(box.Pos));
				}
			}
		}
		return num;
	}

	private static string Pos(Vector3 p)
	{
		return "(" + F(p.x) + ", " + F(p.y) + ", " + F(p.z) + ")";
	}

	private static string Shortfall(Dictionary<string, int> deficits, Stock s)
	{
		List<string> list = new List<string>();
		foreach (KeyValuePair<string, int> deficit in deficits)
		{
			int num = deficit.Value - s.Count(deficit.Key);
			if (num > 0)
			{
				list.Add(ItemName(deficit.Key) + " x" + num);
			}
		}
		return string.Join(", ", list.ToArray());
	}

	private bool OpenedByHand(Container c)
	{
		if (_manualAt.TryGetValue(c, out var value))
		{
			return Time.time - value < 2f;
		}
		return false;
	}

	private Own Acquire(Box b)
	{
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		if (b == null || !b.Alive)
		{
			return Own.Failed;
		}
		_requests.TryGetValue(b.C, out var value);
		if (b.View.IsOwner())
		{
			if (value != null)
			{
				_requests.Remove(b.C);
				Reload(b);
			}
			return Own.Ready;
		}
		if (value != null)
		{
			if (!value.Denied)
			{
				return Own.Pending;
			}
			return Own.Failed;
		}
		if (OpenedByHand(b.C))
		{
			return Own.Pending;
		}
		if (_refusedUntil.TryGetValue(b, out var value2))
		{
			if (Time.time < value2)
			{
				return Own.Failed;
			}
			_refusedUntil.Remove(b);
		}
		ZDO zDO = b.View.GetZDO();
		if (zDO == null)
		{
			return Own.Failed;
		}
		if (zDO.GetOwner() == 0)
		{
			b.View.ClaimOwnership();
			if (b.View.IsOwner())
			{
				Reload(b);
				return Own.Ready;
			}
		}
		value = new Request();
		value.B = b;
		value.Sent = Time.time;
		_requests[b.C] = value;
		b.View.InvokeRPC("RPC_RequestOpen", new object[1] { MyPlayerId() });
		Debug("asked owner " + zDO.GetOwner() + " for " + b.Prefab + " at " + Pos(b.Pos));
		return Own.Pending;
	}

	private void Reload(Box b)
	{
		try
		{
			_containerLoad.Invoke(b.C, null);
		}
		catch (Exception e)
		{
			Fail("Container.Load", e);
		}
		b.Dirty = true;
		_indexVersion++;
	}

	private void UpdateOwnership()
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		if (_manualAt.Count > 32)
		{
			_manualAt.Clear();
		}
		if (_requests.Count == 0)
		{
			return;
		}
		List<Container> list = null;
		foreach (KeyValuePair<Container, Request> request in _requests)
		{
			Request value = request.Value;
			Box b = value.B;
			bool flag = false;
			if (!b.Alive)
			{
				flag = true;
			}
			else if (b.View.IsOwner())
			{
				Reload(b);
				Debug("got " + b.Prefab + " at " + Pos(b.Pos) + " after " + F(Time.time - value.Sent) + " s");
				flag = true;
			}
			else if (value.Denied || Time.time - value.Sent > 3f)
			{
				_refusedUntil[b] = Time.time + 5f;
				Debug((value.Denied ? "refused: " : "no answer: ") + b.Prefab + " at " + Pos(b.Pos));
				flag = true;
			}
			if (flag)
			{
				if (list == null)
				{
					list = new List<Container>();
				}
				list.Add(request.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		foreach (Container item in list)
		{
			_requests.Remove(item);
		}
	}

	private void ClearOwnership()
	{
		_requests.Clear();
		_refusedUntil.Clear();
		_manualAt.Clear();
	}

	private Own AcquireAll(List<Box> plan, HashSet<Box> failed)
	{
		Own own = Own.Ready;
		foreach (Box item in plan)
		{
			switch (Acquire(item))
			{
			case Own.Failed:
				failed?.Add(item);
				own = Own.Failed;
				break;
			case Own.Pending:
				if (own == Own.Ready)
				{
					own = Own.Pending;
				}
				break;
			}
		}
		return own;
	}

	private bool BeforeRepairOne(InventoryGui gui)
	{
		if (_repairingAll || !Ready || !Eff<bool>(_cfgRepairAll))
		{
			return true;
		}
		int i = 0;
		_repairingAll = true;
		try
		{
			for (; i < 200; i++)
			{
				if (!(bool)_haveRepairable.Invoke(gui, null))
				{
					break;
				}
				_repairOne.Invoke(gui, null);
			}
		}
		finally
		{
			_repairingAll = false;
		}
		if (i == 0)
		{
			return true;
		}
		if (i > 1)
		{
			Tell(T("repaired", i));
		}
		return false;
	}

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

	private void UpdateAreaRepair()
	{
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		if (_repairQueue.Count > 0)
		{
			for (int i = 0; i < 3; i++)
			{
				if (_repairQueue.Count <= 0)
				{
					break;
				}
				WearNTear val = _repairQueue.Dequeue();
				if (!((Object)(object)val == (Object)null) && val.Repair())
				{
					_repairDone++;
					Piece component = ((Component)val).GetComponent<Piece>();
					if ((Object)(object)component != (Object)null && component.m_placeEffect != null)
					{
						component.m_placeEffect.Create(((Component)val).transform.position, ((Component)val).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
					}
				}
			}
			if (_repairQueue.Count == 0)
			{
				ReportAreaRepair();
			}
		}
		else if (Ready && Eff<bool>(_cfgAreaRepair) && !Typing())
		{
			KeyboardShortcut value = _cfgAreaRepairKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				StartAreaRepair();
			}
		}
	}

	private void StartAreaRepair()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: 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_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		float num = Mathf.Clamp(Eff<float>(_cfgAreaRepairRadius), 1f, 100f);
		float num2 = num * num;
		Vector3 position = ((Component)localPlayer).transform.position;
		bool flag = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)27);
		_repairDone = 0;
		_repairNoStation = 0;
		List<KeyValuePair<float, WearNTear>> list = new List<KeyValuePair<float, WearNTear>>();
		Dictionary<string, bool> dictionary = new Dictionary<string, bool>();
		foreach (WearNTear allInstance in WearNTear.GetAllInstances())
		{
			if ((Object)(object)allInstance == (Object)null)
			{
				continue;
			}
			Vector3 position2 = ((Component)allInstance).transform.position;
			Vector3 val = position2 - position;
			if (((Vector3)(ref val)).sqrMagnitude > num2)
			{
				continue;
			}
			Piece component = ((Component)allInstance).GetComponent<Piece>();
			if ((Object)(object)component == (Object)null || !component.IsPlacedByPlayer())
			{
				continue;
			}
			ZNetView component2 = ((Component)allInstance).GetComponent<ZNetView>();
			if ((Object)(object)component2 == (Object)null || component2.GetZDO() == null || component2.GetZDO().GetFloat(ZDOVars.s_health, allInstance.m_health) >= allInstance.m_health || !PrivateArea.CheckAccess(position2, 0f, false, false))
			{
				continue;
			}
			if ((Object)(object)component.m_craftingStation != (Object)null && !flag)
			{
				string name = component.m_craftingStation.m_name;
				if (!dictionary.TryGetValue(name, out var value))
				{
					value = (dictionary[name] = (Object)(object)CraftingStation.HaveBuildStationInRange(name, position) != (Object)null);
				}
				if (!value)
				{
					_repairNoStation++;
					continue;
				}
			}
			Vector3 val2 = position2 - position;
			list.Add(new KeyValuePair<float, WearNTear>(((Vector3)(ref val2)).sqrMagnitude, allInstance));
		}
		list.Sort((KeyValuePair<float, WearNTear> a, KeyValuePair<float, WearNTear> z) => a.Key.CompareTo(z.Key));
		foreach (KeyValuePair<float, WearNTear> item in list)
		{
			_repairQueue.Enqueue(item.Value);
		}
		if (_repairQueue.Count == 0)
		{
			ReportAreaRepair();
		}
	}

	private void ReportAreaRepair()
	{
		string text = ((_repairDone > 0) ? T("area", _repairDone) : T("area_none"));
		if (_repairNoStation > 0)
		{
			text += T("area_station", _repairNoStation);
		}
		Tell(text);
	}

	private bool StationsOn(ConfigEntry<bool> kind)
	{
		if (Ready)
		{
			return Eff<bool>(kind);
		}
		return false;
	}

	private bool BeforeStation(Humanoid user, Component station, List<string> wanted, Action retry, out Fetched fetched)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		fetched = null;
		if (!IsLocal(user) || (Object)(object)station == (Object)null || wanted == null || wanted.Count == 0)
		{
			return true;
		}
		Inventory inventory = user.GetInventory();
		if (inventory == null)
		{
			return true;
		}
		foreach (string item in wanted)
		{
			if (inventory.HaveItem(item, true))
			{
				return true;
			}
		}
		Stock stock = GetStock(station.transform.position, StationRange);
		if (stock.Boxes.Count == 0)
		{
			return true;
		}
		string text = null;
		foreach (string item2 in wanted)
		{
			if (stock.Count(item2) > 0)
			{
				text = item2;
				break;
			}
		}
		if (text == null)
		{
			return true;
		}
		Box box = null;
		for (int i = 0; i < 2; i++)
		{
			if (box != null)
			{
				break;
			}
			foreach (Box box2 in stock.Boxes)
			{
				if (i == 0 == box2.Owned && box2.Count(text) > 0)
				{
					box = box2;
					break;
				}
			}
		}
		if (box == null)
		{
			return true;
		}
		switch (Acquire(box))
		{
		case Own.Pending:
		{
			StationRetry stationRetry = new StationRetry();
			stationRetry.B = box;
			stationRetry.Run = retry;
			stationRetry.Until = Time.time + 3f + 0.5f;
			_stationRetry = stationRetry;
			return false;
		}
		case Own.Failed:
			Tell(T("busy"));
			return false;
		default:
		{
			ItemData val = FirstUsable(box.Inv, text);
			if (val == null)
			{
				return true;
			}
			ItemData val2 = val.Clone();
			val2.m_stack = 1;
			if (!inventory.AddItem(val2))
			{
				Tell(T("invfull", ItemName(text)));
				return false;
			}
			box.Inv.RemoveItem(val, 1);
			fetched = new Fetched();
			fetched.B = box;
			fetched.Name = text;
			fetched.After = inventory.CountItems(text, -1, true);
			Debug("fetched 1 " + text + " from " + box.Prefab + " for " + PrefabName(station.gameObject));
			return true;
		}
		}
	}

	private void AfterStation(Humanoid user, Fetched f)
	{
		if (f == null || (Object)(object)user == (Object)null)
		{
			return;
		}
		Inventory inventory = user.GetInventory();
		if (inventory == null || inventory.CountItems(f.Name, -1, true) < f.After || !f.B.Owned)
		{
			return;
		}
		ItemData val = FirstUsable(inventory, f.Name);
		if (val != null)
		{
			ItemData val2 = val.Clone();
			val2.m_stack = 1;
			if (f.B.Inv.AddItem(val2))
			{
				inventory.RemoveItem(val, 1);
				Debug("returned 1 " + f.Name + " to " + f.B.Prefab);
			}
		}
	}

	private static ItemData FirstUsable(Inventory inv, string name)
	{
		foreach (ItemData allItem in inv.GetAllItems())
		{
			if (allItem != null && allItem.m_shared.m_name == name && allItem.m_worldLevel >= Game.m_worldLevel && allItem.m_stack > 0)
			{
				return allItem;
			}
		}
		return null;
	}

	private void UpdateStationRetry()
	{
		StationRetry stationRetry = _stationRetry;
		if (stationRetry == null)
		{
			return;
		}
		Own own = Acquire(stationRetry.B);
		if (own == Own.Pending && Time.time < stationRetry.Until)
		{
			return;
		}
		_stationRetry = null;
		if (own == Own.Ready)
		{
			try
			{
				if (stationRetry.Run != null)
				{
					stationRetry.Run();
				}
				return;
			}
			catch (Exception e)
			{
				Fail("station retry", e);
				return;
			}
		}
		Tell(T("busy"));
	}

	private static List<string> Names(ItemDrop single)
	{
		List<string> list = new List<string>();
		if ((Object)(object)single != (Object)null)
		{
			list.Add(single.m_itemData.m_shared.m_name);
		}
		return list;
	}

	private static List<string> Names(IEnumerable<ItemDrop> items)
	{
		List<string> list = new List<string>();
		if (items == null)
		{
			return list;
		}
		foreach (ItemDrop item in items)
		{
			if ((Object)(object)item != (Object)null && !list.Contains(item.m_itemData.m_shared.m_name))
			{
				list.Add(item.m_itemData.m_shared.m_name);
			}
		}
		return list;
	}

	private void RegisterRpc()
	{
		if (ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.Register<ZPackage>("j1ga.chestreach.config", (Action<long, ZPackage>)OnConfigPacket);
		}
	}

	private void FlushSync()
	{
		_syncDirty = false;
		_indexVersion++;
		ZNet instance = ZNet.instance;
		if (!((Object)(object)instance == (Object)null) && instance.IsServer() && _cfgSync.Value && ZRoutedRpc.instance != null && instance.GetPeers().Count != 0)
		{
			SendConfig(0L);
			Debug("settings sent to " + instance.GetPeers().Count + " peers");
		}
	}

	private ZPackage BuildPacket()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		ZPackage val = new ZPackage();
		val.Write(1);
		val.Write(_synced.Count);
		foreach (ConfigEntryBase item in _synced)
		{
			val.Write(item.Definition.Section + "/" + item.Definition.Key);
			val.Write(item.GetSerializedValue());
		}
		return val;
	}

	private void SendConfig(long target)
	{
		ZRoutedRpc.instance.InvokeRoutedRPC(target, "j1ga.chestreach.config", new object[1] { BuildPacket() });
	}

	private void OnPeerInfo(ZNet znet, ZRpc rpc)
	{
		if (!znet.IsServer() || !_cfgSync.Value || rpc == null)
		{
			return;
		}
		foreach (ZNetPeer peer in znet.GetPeers())
		{
			if (peer != null && peer.m_rpc == rpc)
			{
				if (peer.m_uid != 0)
				{
					((MonoBehaviour)this).StartCoroutine(SendConfigLater(peer.m_uid));
				}
				break;
			}
		}
	}

	private IEnumerator SendConfigLater(long uid)
	{
		yield return (object)new WaitForSeconds(1f);
		ZNet znet = ZNet.instance;
		if ((Object)(object)znet == (Object)null || !znet.IsServer() || ZRoutedRpc.instance == null || !_cfgSync.Value)
		{
			yield break;
		}
		ZNetPeer peer = znet.GetPeer(uid);
		if (peer != null)
		{
			try
			{
				SendConfig(uid);
				Debug("settings sent to " + peer.m_playerName);
			}
			catch (Exception e)
			{
				Fail("send config", e);
			}
		}
	}

	private void OnConfigPacket(long sender, ZPackage pkg)
	{
		try
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || instance.IsServer() || pkg == null)
			{
				return;
			}
			ZNetPeer serverPeer = instance.GetServerPeer();
			if (serverPeer == null || sender != serverPeer.m_uid)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Settings packet from peer " + sender + ", which is not the server; ignored."));
				return;
			}
			int num = pkg.ReadInt();
			if (num != 1)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("The server runs a ChestReach with packet version " + num + ", this one understands " + 1 + "; using the local settings."));
				return;
			}
			Dictionary<string, ConfigEntryBase> dictionary = new Dictionary<string, ConfigEntryBase>();
			foreach (ConfigEntryBase item in _synced)
			{
				dictionary[item.Definition.Section + "/" + item.Definition.Key] = item;
			}
			int num2 = pkg.ReadInt();
			if (num2 < 0 || num2 > 1000)
			{
				return;
			}
			Dictionary<ConfigEntryBase, object> dictionary2 = new Dictionary<ConfigEntryBase, object>();
			for (int i = 0; i < num2; i++)
			{
				string text = pkg.ReadString();
				string text2 = pkg.ReadString();
				if (dictionary.TryGetValue(text, out var value))
				{
					try
					{
						dictionary2[value] = TomlTypeConverter.ConvertToValue(text2, value.SettingType);
					}
					catch (Exception)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Server setting " + text + " = '" + text2 + "' could not be read; the local value applies."));
					}
				}
			}
			_serverValues.Clear();
			foreach (KeyValuePair<ConfigEntryBase, object> item2 in dictionary2)
			{
				_serverValues[item2.Key] = item2.Value;
			}
			ReadList(_serverValues.TryGetValue((ConfigEntryBase)(object)_cfgExcluded, out var value2) ? (value2 as string) : "", _serverExcluded);
			_serverSynced = true;
			_indexVersion++;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Settings from the server: " + StatusValues()));
		}
		catch (Exception e)
		{
			Fail("config packet", e);
		}
	}

	private void ClearServerValues()
	{
		_serverSynced = false;
		_serverValues.Clear();
		_serverExcluded.Clear();
	}

	private void AfterSetupRequirement(Transform root, Requirement req, Player player, int quality, int multiplier)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)root == (Object)null || req == null || (Object)(object)req.m_resItem == (Object)null || !IsLocal((Humanoid)(object)player))
		{
			return;
		}
		bool rowsForBuild = _rowsForBuild;
		if (rowsForBuild ? (!BuildOn) : (!CraftOn))
		{
			return;
		}
		int num = req.GetAmount(quality) * multiplier;
		if (num <= 0)
		{
			return;
		}
		string name = req.m_resItem.m_itemData.m_shared.m_name;
		int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true);
		Stock stock = (rowsForBuild ? GetStock(((Component)player).transform.position, BuildRange) : GetStock(CraftCenter(player), CraftRange));
		int num3 = stock.Count(name);
		Transform val = root.Find("res_amount");
		TMP_Text val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TMP_Text>() : null);
		if ((Object)(object)val2 != (Object)null)
		{
			if (_cfgShowTotal.Value)
			{
				FitOnOneLine(val2);
				val2.text = Short(num2 + num3) + "/" + num;
			}
			if (num2 < num && num2 + num3 >= num)
			{
				((Graphic)val2).color = _cfgCoveredColor.Value;
			}
		}
		if (_cfgTooltip.Value && num3 > 0)
		{
			UITooltip component = ((Component)root).GetComponent<UITooltip>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_text = (component.m_text ?? "") + "\n" + T("tooltip", num2, num3);
			}
		}
	}

	private static void FitOnOneLine(TMP_Text text)
	{
		if (!text.enableAutoSizing)
		{
			float fontSize = text.fontSize;
			text.textWrappingMode = (TextWrappingModes)0;
			text.fontSizeMax = fontSize;
			text.fontSizeMin = Mathf.Max(6f, fontSize * 0.6f);
			text.enableAutoSizing = true;
		}
	}

	private static string Short(int n)
	{
		if (n < 10000)
		{
			return n.ToString();
		}
		if (n < 1000000)
		{
			return n / 1000 + "k";
		}
		return n / 1000000 + "M";
	}
}