Decompiled source of BetterResourceChest v1.0.1

BepInEx/plugins/BetterResourceChest.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterResourceChest.Configuration;
using BetterResourceChest.Localization;
using BetterResourceChest.Utils;
using HarmonyLib;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace BetterResourceChest
{
	[BepInPlugin("IceBoxStudio.BetterResourceChest", "BetterResourceChest", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class BetterResourceChest : BaseUnityPlugin
	{
		private static BetterResourceChest _instance;

		private Harmony _harmony;

		private bool _patched;

		public static BetterResourceChest Instance => _instance;

		internal static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			_instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"=============================================");
			Logger.LogInfo((object)("BetterResourceChest " + LocalizationManager.Instance.GetLocalizedText("plugin.initializing")));
			Logger.LogInfo((object)(LocalizationManager.Instance.GetLocalizedText("plugin.author_prefix") + "Ice Box Studio(https://steamcommunity.com/id/ibox666/)"));
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			ApplyPatches();
			RegisterModConfig();
			Logger.LogInfo((object)("BetterResourceChest " + LocalizationManager.Instance.GetLocalizedText("plugin.initialized")));
			Logger.LogInfo((object)"=============================================");
		}

		private void ApplyPatches()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			if (_patched)
			{
				Logger.LogInfo((object)LocalizationManager.Instance.GetLocalizedText("plugin.patches_skipped"));
				return;
			}
			_harmony = new Harmony("IceBoxStudio.BetterResourceChest");
			_harmony.PatchAll();
			_patched = true;
		}

		private static void RegisterModConfig()
		{
			try
			{
				Type type = Type.GetType("ModConfigManager.Api.ModConfigManagerApi, ModConfigManager");
				if (!(type == null))
				{
					type.GetMethod("RegisterHotkeyCompatibleByGuid")?.Invoke(null, new object[1] { "IceBoxStudio.BetterResourceChest" });
					type.GetMethod("RegisterModDisplayName")?.Invoke(null, new object[2] { "BetterResourceChest", "更好的材料箱" });
				}
			}
			catch
			{
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "IceBoxStudio.BetterResourceChest";

		public const string PLUGIN_NAME = "BetterResourceChest";

		public const string PLUGIN_VERSION = "1.0.1";
	}
}
namespace BetterResourceChest.Utils
{
	public static class InputActionBindingHelper
	{
		public static InputAction CreateButtonAction(string actionName, string hotkey, Action onPerformed)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			string text = BuildBindingPath(hotkey);
			if (string.IsNullOrWhiteSpace(text))
			{
				return null;
			}
			InputAction val = new InputAction(actionName, (InputActionType)1, text, (string)null, (string)null, (string)null);
			if (onPerformed != null)
			{
				val.performed += delegate
				{
					onPerformed();
				};
			}
			val.Enable();
			return val;
		}

		public static InputAction CreateValueAction(string actionName, string hotkey)
		{
			//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_0023: Expected O, but got Unknown
			string text = BuildBindingPath(hotkey);
			if (string.IsNullOrWhiteSpace(text))
			{
				return null;
			}
			InputAction val = new InputAction(actionName, (InputActionType)0, text, (string)null, (string)null, (string)null);
			val.Enable();
			return val;
		}

		public static string BuildBindingPath(string hotkey)
		{
			if (string.IsNullOrWhiteSpace(hotkey))
			{
				return null;
			}
			string text = hotkey.Trim();
			if (text.Contains("<") && text.Contains(">"))
			{
				return text;
			}
			string text2 = text.ToLowerInvariant();
			switch (text2)
			{
			case "mousewheel":
			case "mousescroll":
				return "<Mouse>/scroll";
			case "leftbutton":
				return "<Mouse>/leftButton";
			case "rightbutton":
				return "<Mouse>/rightButton";
			case "middlebutton":
				return "<Mouse>/middleButton";
			case "backbutton":
				return "<Mouse>/backButton";
			case "forwardbutton":
				return "<Mouse>/forwardButton";
			default:
				return text2 switch
				{
					"buttonsouth" => "<Gamepad>/buttonSouth", 
					"buttoneast" => "<Gamepad>/buttonEast", 
					"buttonwest" => "<Gamepad>/buttonWest", 
					"buttonnorth" => "<Gamepad>/buttonNorth", 
					"leftshoulder" => "<Gamepad>/leftShoulder", 
					"rightshoulder" => "<Gamepad>/rightShoulder", 
					"lefttrigger" => "<Gamepad>/leftTrigger", 
					"righttrigger" => "<Gamepad>/rightTrigger", 
					"dpadup" => "<Gamepad>/dpad/up", 
					"dpaddown" => "<Gamepad>/dpad/down", 
					"dpadleft" => "<Gamepad>/dpad/left", 
					"dpadright" => "<Gamepad>/dpad/right", 
					"startbutton" => "<Gamepad>/start", 
					"selectbutton" => "<Gamepad>/select", 
					"leftstickpress" => "<Gamepad>/leftStickPress", 
					"rightstickpress" => "<Gamepad>/rightStickPress", 
					_ => "<Keyboard>/" + text2, 
				};
			}
		}

		public static string FormatHotkeyForDisplay(string s)
		{
			if (string.IsNullOrWhiteSpace(s))
			{
				return string.Empty;
			}
			s = s.Trim();
			if (s.Length == 1)
			{
				return s.ToUpperInvariant();
			}
			if (s[0] == 'f' || s[0] == 'F')
			{
				bool flag = true;
				for (int i = 1; i < s.Length; i++)
				{
					if (!char.IsDigit(s[i]))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					return ("F" + s.Substring(1)).ToUpperInvariant();
				}
			}
			string text = s.ToLowerInvariant();
			switch (text)
			{
			case "mousewheel":
			case "mousescroll":
				return "Mouse Wheel";
			case "leftbutton":
				return "Mouse Left";
			case "rightbutton":
				return "Mouse Right";
			case "middlebutton":
				return "Mouse Middle";
			case "backbutton":
				return "Mouse Back";
			case "forwardbutton":
				return "Mouse Forward";
			default:
				switch (text)
				{
				case "buttonsouth":
					return "Gamepad A";
				case "buttoneast":
					return "Gamepad B";
				case "buttonwest":
					return "Gamepad X";
				case "buttonnorth":
					return "Gamepad Y";
				case "leftshoulder":
					return "Gamepad LB";
				case "rightshoulder":
					return "Gamepad RB";
				case "lefttrigger":
					return "Gamepad LT";
				case "righttrigger":
					return "Gamepad RT";
				case "dpadup":
					return "D-Pad Up";
				case "dpaddown":
					return "D-Pad Down";
				case "dpadleft":
					return "D-Pad Left";
				case "dpadright":
					return "D-Pad Right";
				case "startbutton":
					return "Gamepad Start";
				case "selectbutton":
					return "Gamepad Select";
				case "leftstickpress":
					return "Left Stick Press";
				case "rightstickpress":
					return "Right Stick Press";
				default:
					switch (text.Length)
					{
					case 5:
						switch (text[0])
						{
						case 's':
							if (!(text == "slash"))
							{
								break;
							}
							return "/";
						case 'm':
							if (!(text == "minus"))
							{
								break;
							}
							return "-";
						case 'c':
							if (!(text == "comma"))
							{
								break;
							}
							return ",";
						case 'q':
							if (!(text == "quote"))
							{
								break;
							}
							return "'";
						}
						break;
					case 9:
						switch (text[4])
						{
						case 's':
							if (!(text == "backslash"))
							{
								break;
							}
							return "\\";
						case 'c':
							if (!(text == "semicolon"))
							{
								break;
							}
							return ";";
						case 'q':
							if (!(text == "backquote"))
							{
								break;
							}
							return "`";
						}
						break;
					case 6:
						switch (text[0])
						{
						case 'e':
							if (!(text == "equals"))
							{
								break;
							}
							return "=";
						case 'p':
							if (!(text == "period"))
							{
								break;
							}
							return ".";
						}
						break;
					case 4:
						if (!(text == "plus"))
						{
							break;
						}
						return "+";
					case 11:
						if (!(text == "leftbracket"))
						{
							break;
						}
						return "[";
					case 12:
						if (!(text == "rightbracket"))
						{
							break;
						}
						return "]";
					}
					break;
				case null:
					break;
				}
				switch (text)
				{
				case "alt":
				case "ctrl":
				case "shift":
				case "enter":
				case "space":
				case "escape":
				case "esc":
				case "tab":
				case "backspace":
				case "capslock":
					return char.ToUpper(s[0]) + s.Substring(1).ToLowerInvariant();
				case "leftalt":
					return "LeftAlt";
				case "rightalt":
					return "RightAlt";
				case "leftctrl":
					return "LeftCtrl";
				case "rightctrl":
					return "RightCtrl";
				case "leftshift":
					return "LeftShift";
				case "rightshift":
					return "RightShift";
				default:
					return char.ToUpper(s[0]) + s.Substring(1).ToLowerInvariant();
				}
			}
		}
	}
}
namespace BetterResourceChest.Patches
{
	[HarmonyPatch(typeof(BlockChest))]
	public static class CheckoutPatch
	{
		[HarmonyPatch("Interact")]
		[HarmonyPrefix]
		public static bool Interact_Prefix(BlockChest __instance)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (!ChestTools.IsEnabled("BulkDeposit"))
			{
				return true;
			}
			if (!((Interactable)__instance).CanInteract())
			{
				return true;
			}
			PlayerInventory localInventory = ChestTools.GetLocalInventory(__instance);
			if ((Object)(object)localInventory == (Object)null)
			{
				return true;
			}
			if (localInventory.GetCurrentInventorySlot().itemId == -1)
			{
				return true;
			}
			ItemSO currentItemSO = localInventory.GetCurrentItemSO();
			ItemSO storedItemSO = __instance.GetStoredItemSO();
			if ((Object)(object)currentItemSO == (Object)null)
			{
				return true;
			}
			if ((Object)(object)storedItemSO != (Object)null && storedItemSO.id != currentItemSO.id)
			{
				return true;
			}
			int maxAmount = __instance.maxCapacity - __instance.GetStoredItemAmountVariable();
			if (GetTotalItemCount(localInventory, currentItemSO, maxAmount) <= 1)
			{
				return true;
			}
			__instance.PlaceItemServerRpc(default(ServerRpcParams));
			return false;
		}

		[HarmonyPatch("PlaceItemServerRpc")]
		[HarmonyPrefix]
		public static bool PlaceItemServerRpc_Prefix(BlockChest __instance, ServerRpcParams serverRpcParams = default(ServerRpcParams))
		{
			//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_005a: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!ChestTools.IsEnabled("BulkDeposit"))
			{
				return true;
			}
			if (!ChestTools.IsExecuteStage((NetworkBehaviour)(object)__instance) || (!((NetworkBehaviour)__instance).NetworkManager.IsServer && !((NetworkBehaviour)__instance).NetworkManager.IsHost))
			{
				return true;
			}
			ulong senderClientId = serverRpcParams.Receive.SenderClientId;
			PlayerInventory component = ((Component)NetworkManager.Singleton.ConnectedClients[senderClientId].PlayerObject).GetComponent<PlayerInventory>();
			InventorySlot currentInventorySlot = component.GetCurrentInventorySlot();
			if (currentInventorySlot.itemId == -1)
			{
				return true;
			}
			ItemSO currentItemSO = component.GetCurrentItemSO();
			if ((Object)(object)currentItemSO == (Object)null)
			{
				return true;
			}
			NetworkVariable<long> storedItemId = ChestTools.GetStoredItemId(__instance);
			NetworkVariable<int> storedItemAmount = ChestTools.GetStoredItemAmount(__instance);
			if (storedItemId == null || storedItemAmount == null)
			{
				return true;
			}
			if (storedItemId.Value == -1)
			{
				if (!__instance.allowedItems.Contains(currentItemSO))
				{
					return true;
				}
			}
			else if (storedItemId.Value != currentItemSO.id)
			{
				return true;
			}
			int maxAmount = __instance.maxCapacity - storedItemAmount.Value;
			int totalItemCount = GetTotalItemCount(component, currentItemSO, maxAmount);
			if (totalItemCount <= 1)
			{
				return true;
			}
			if (storedItemId.Value == -1)
			{
				storedItemId.Value = currentInventorySlot.itemId;
			}
			storedItemAmount.Value += totalItemCount;
			component.RemoveItem(currentItemSO, totalItemCount);
			return false;
		}

		private static int GetTotalItemCount(PlayerInventory inventory, ItemSO item, int maxAmount)
		{
			if ((Object)(object)inventory == (Object)null || (Object)(object)item == (Object)null || maxAmount <= 0)
			{
				return 0;
			}
			return Mathf.Min(inventory.GetItemCount(item), maxAmount);
		}
	}
	[HarmonyPatch(typeof(ChestPickup))]
	public static class ChestPickupPatch
	{
		[HarmonyPatch("GetDescription")]
		[HarmonyPostfix]
		public static void GetDescription_Postfix(ref string __result)
		{
			if (!string.IsNullOrEmpty(__result))
			{
				__result = __result + "\n" + ChestTools.GetTakeAmountHint();
			}
		}

		[HarmonyPatch("Interact")]
		[HarmonyPrefix]
		public static bool Interact_Prefix(ChestPickup __instance)
		{
			//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 ((Object)(object)__instance.blockChest == (Object)null || !((Interactable)__instance).CanInteract())
			{
				return true;
			}
			ItemSO storedItemSO = __instance.blockChest.GetStoredItemSO();
			if ((Object)(object)storedItemSO == (Object)null)
			{
				return true;
			}
			PlayerInventory localInventory = ChestTools.GetLocalInventory(__instance.blockChest);
			if ((Object)(object)localInventory == (Object)null)
			{
				return true;
			}
			int freeSpace = ChestTools.GetFreeSpace(localInventory, storedItemSO);
			int num = Mathf.Min(ChestTools.GetTakeAmount(), Mathf.Min(freeSpace, __instance.blockChest.GetStoredItemAmountVariable()));
			if (num <= 1)
			{
				return true;
			}
			for (int i = 0; i < num; i++)
			{
				__instance.blockChest.TakeItemServerRpc(default(ServerRpcParams));
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerInteraction))]
	public static class PlayerInteractionPatch
	{
		private static readonly FieldInfo MainCameraField = AccessTools.Field(typeof(PlayerInteraction), "mainCamera");

		[HarmonyPatch("InteractionRay")]
		[HarmonyPostfix]
		public static void InteractionRay_Postfix(PlayerInteraction __instance)
		{
			if (TryGetChestPickup(__instance, out var pickup) && ChestTools.UpdateTakeAmountInput())
			{
				((TMP_Text)__instance.textPrimaryInteraction).text = ((Interactable)pickup).GetDescription();
			}
		}

		internal static bool TryGetChestPickup(PlayerInteraction interaction, out ChestPickup pickup)
		{
			//IL_0020: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			pickup = null;
			object? value = MainCameraField.GetValue(interaction);
			Camera val = (Camera)((value is Camera) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			RaycastHit val2 = default(RaycastHit);
			if (!Physics.Raycast(val.ViewportPointToRay(Vector3.one / 2f), ref val2, interaction.interactionDistance, LayerMask.op_Implicit(interaction.layerMask), (QueryTriggerInteraction)1))
			{
				return false;
			}
			pickup = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<ChestPickup>();
			return (Object)(object)pickup != (Object)null;
		}
	}
	internal static class ChestTools
	{
		private static readonly FieldInfo CurrentSlotField = AccessTools.Field(typeof(PlayerInventory), "currentSlot");

		private static readonly FieldInfo ActiveSlotsField = AccessTools.Field(typeof(PlayerInventory), "activeSlots");

		private static readonly FieldInfo LocalPlayerInventoryField = AccessTools.Field(typeof(BlockChest), "localPlayerInventory");

		private static readonly FieldInfo StoredItemIdField = AccessTools.Field(typeof(BlockChest), "storedItemID");

		private static readonly FieldInfo StoredItemAmountField = AccessTools.Field(typeof(BlockChest), "storedItemAmount");

		private static readonly FieldInfo RpcExecStageField = AccessTools.Field(typeof(NetworkBehaviour), "__rpc_exec_stage");

		private static int _takeAmount = -1;

		private static InputAction _takeAmountWheelAction;

		private static InputAction _takeAmountUpAction;

		private static InputAction _takeAmountDownAction;

		private static string _takeAmountUpBinding = "";

		private static string _takeAmountDownBinding = "";

		private static InputAction _quickStackAction;

		private static string _quickStackBinding;

		public static int GetCapacity()
		{
			if (ConfigManager.Instance == null)
			{
				return 250;
			}
			return Mathf.Max(1, ConfigManager.Instance.GetInt("Capacity", 250));
		}

		public static int GetTakeAmount()
		{
			if (_takeAmount < 1)
			{
				if (ConfigManager.Instance == null)
				{
					_takeAmount = 5;
				}
				else
				{
					_takeAmount = Mathf.Max(1, ConfigManager.Instance.GetInt("DefaultTakeAmount", 5));
				}
			}
			return _takeAmount;
		}

		public static void ChangeTakeAmount(int delta)
		{
			_takeAmount = Mathf.Clamp(GetTakeAmount() + delta, 1, 999);
		}

		private static string GetUpInput()
		{
			if (ConfigManager.Instance == null)
			{
				return "";
			}
			return ConfigManager.Instance.GetString("TakeAmountUp");
		}

		private static string GetDownInput()
		{
			if (ConfigManager.Instance == null)
			{
				return "";
			}
			return ConfigManager.Instance.GetString("TakeAmountDown");
		}

		public static bool UpdateTakeAmountInput()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			EnsureWheel();
			EnsureTakeAmountButtons();
			if (_takeAmountWheelAction != null)
			{
				Vector2 val = _takeAmountWheelAction.ReadValue<Vector2>();
				if (val.y > 0.01f)
				{
					ChangeTakeAmount(1);
					return true;
				}
				if (val.y < -0.01f)
				{
					ChangeTakeAmount(-1);
					return true;
				}
			}
			if (_takeAmountUpAction != null && _takeAmountUpAction.WasPerformedThisFrame())
			{
				ChangeTakeAmount(1);
				return true;
			}
			if (_takeAmountDownAction != null && _takeAmountDownAction.WasPerformedThisFrame())
			{
				ChangeTakeAmount(-1);
				return true;
			}
			return false;
		}

		public static string GetTakeAmountHint()
		{
			string upInput = GetUpInput();
			string downInput = GetDownInput();
			string text = ((string.IsNullOrEmpty(upInput) || string.IsNullOrEmpty(downInput)) ? InputActionBindingHelper.FormatHotkeyForDisplay("MouseWheel") : (InputActionBindingHelper.FormatHotkeyForDisplay(upInput) + "/" + InputActionBindingHelper.FormatHotkeyForDisplay(downInput)));
			return LocalizationManager.Instance.GetLocalizedText("hint.take_amount", GetTakeAmount(), text);
		}

		public static bool IsEnabled(string key)
		{
			if (ConfigManager.Instance != null)
			{
				return ConfigManager.Instance.IsPatchEnabled(key);
			}
			return false;
		}

		public static PlayerInventory GetLocalInventory(BlockChest chest)
		{
			object? value = LocalPlayerInventoryField.GetValue(chest);
			PlayerInventory val = (PlayerInventory)((value is PlayerInventory) ? value : null);
			if ((Object)(object)val == (Object)null && (Object)(object)((NetworkBehaviour)chest).NetworkManager != (Object)null && ((NetworkBehaviour)chest).NetworkManager.LocalClient != null && (Object)(object)((NetworkBehaviour)chest).NetworkManager.LocalClient.PlayerObject != (Object)null)
			{
				val = ((Component)((NetworkBehaviour)chest).NetworkManager.LocalClient.PlayerObject).GetComponent<PlayerInventory>();
				LocalPlayerInventoryField.SetValue(chest, val);
			}
			return val;
		}

		public static int GetCurrentSlotIndex(PlayerInventory inventory)
		{
			if (!(CurrentSlotField.GetValue(inventory) is NetworkVariable<int> val))
			{
				return 0;
			}
			return val.Value;
		}

		public static int GetActiveSlotCount(PlayerInventory inventory)
		{
			object value = ActiveSlotsField.GetValue(inventory);
			if (value is int)
			{
				return (int)value;
			}
			return 0;
		}

		public static void RemoveCurrentItem(PlayerInventory inventory, int amount)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)inventory == (Object)null || amount <= 0)
			{
				return;
			}
			InventorySlot currentInventorySlot = inventory.GetCurrentInventorySlot();
			if (currentInventorySlot.itemId != -1)
			{
				int num = currentInventorySlot.amount - amount;
				if (num > 0)
				{
					inventory.slots[GetCurrentSlotIndex(inventory)] = new InventorySlot
					{
						itemId = currentInventorySlot.itemId,
						amount = num,
						cost = currentInventorySlot.cost,
						dayCounter = 0
					};
				}
				else
				{
					inventory.UseItem();
				}
			}
		}

		public static int GetFreeSpace(PlayerInventory inventory, ItemSO item)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)inventory == (Object)null || (Object)(object)item == (Object)null || inventory.slots == null)
			{
				return 0;
			}
			int num = Mathf.Min(GetActiveSlotCount(inventory), inventory.slots.Count);
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				InventorySlot val = inventory.slots[i];
				if (val.itemId == -1)
				{
					num2 += item.stackSize;
				}
				else if (val.itemId == item.id && val.amount < item.stackSize)
				{
					num2 += item.stackSize - val.amount;
				}
			}
			return num2;
		}

		public static NetworkVariable<long> GetStoredItemId(BlockChest chest)
		{
			return StoredItemIdField.GetValue(chest) as NetworkVariable<long>;
		}

		public static NetworkVariable<int> GetStoredItemAmount(BlockChest chest)
		{
			return StoredItemAmountField.GetValue(chest) as NetworkVariable<int>;
		}

		public static bool IsExecuteStage(NetworkBehaviour behaviour)
		{
			object value = RpcExecStageField.GetValue(behaviour);
			if (value != null)
			{
				return value.ToString() == "Execute";
			}
			return false;
		}

		public static bool UsesMouseWheel()
		{
			return true;
		}

		private static void EnsureWheel()
		{
			if (_takeAmountWheelAction == null)
			{
				_takeAmountWheelAction = InputActionBindingHelper.CreateValueAction("TakeAmountWheel", "MouseWheel");
			}
		}

		private static void EnsureTakeAmountButtons()
		{
			string upInput = GetUpInput();
			string downInput = GetDownInput();
			bool flag = _takeAmountUpBinding != upInput;
			bool flag2 = _takeAmountDownBinding != downInput;
			if (!flag && !flag2)
			{
				return;
			}
			if (flag)
			{
				InputAction takeAmountUpAction = _takeAmountUpAction;
				if (takeAmountUpAction != null)
				{
					takeAmountUpAction.Disable();
				}
				InputAction takeAmountUpAction2 = _takeAmountUpAction;
				if (takeAmountUpAction2 != null)
				{
					takeAmountUpAction2.Dispose();
				}
				_takeAmountUpAction = null;
				_takeAmountUpBinding = null;
			}
			if (flag2)
			{
				InputAction takeAmountDownAction = _takeAmountDownAction;
				if (takeAmountDownAction != null)
				{
					takeAmountDownAction.Disable();
				}
				InputAction takeAmountDownAction2 = _takeAmountDownAction;
				if (takeAmountDownAction2 != null)
				{
					takeAmountDownAction2.Dispose();
				}
				_takeAmountDownAction = null;
				_takeAmountDownBinding = null;
			}
			if (!string.IsNullOrEmpty(upInput))
			{
				_takeAmountUpBinding = upInput;
				_takeAmountUpAction = InputActionBindingHelper.CreateButtonAction("TakeAmountUp", upInput, delegate
				{
				});
				if (_takeAmountUpAction != null)
				{
					_takeAmountUpAction.Enable();
				}
			}
			if (!string.IsNullOrEmpty(downInput))
			{
				_takeAmountDownBinding = downInput;
				_takeAmountDownAction = InputActionBindingHelper.CreateButtonAction("TakeAmountDown", downInput, delegate
				{
				});
				if (_takeAmountDownAction != null)
				{
					_takeAmountDownAction.Enable();
				}
			}
		}

		public static void SetupQuickStack()
		{
			bool flag = ConfigManager.Instance?.IsPatchEnabled("QuickStackEnabled") ?? true;
			string text = ConfigManager.Instance?.GetString("QuickStackKey", "T") ?? "T";
			if (_quickStackAction == null || !(_quickStackBinding == text))
			{
				InputAction quickStackAction = _quickStackAction;
				if (quickStackAction != null)
				{
					quickStackAction.Disable();
				}
				InputAction quickStackAction2 = _quickStackAction;
				if (quickStackAction2 != null)
				{
					quickStackAction2.Dispose();
				}
				_quickStackAction = null;
				_quickStackBinding = null;
				if (flag)
				{
					_quickStackBinding = text;
					_quickStackAction = InputActionBindingHelper.CreateButtonAction("QuickStack", text, QuickStack);
				}
			}
		}

		private static void QuickStack()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || singleton.LocalClient == null || (Object)(object)singleton.LocalClient.PlayerObject == (Object)null)
			{
				return;
			}
			PlayerInventory component = ((Component)singleton.LocalClient.PlayerObject).GetComponent<PlayerInventory>();
			if ((Object)(object)component == (Object)null || component.slots == null)
			{
				return;
			}
			Vector3 position = ((Component)singleton.LocalClient.PlayerObject).transform.position;
			int num = Mathf.Min(GetActiveSlotCount(component), component.slots.Count);
			float num2 = ConfigManager.Instance?.GetFloat("QuickStackRange", 5f) ?? 5f;
			int num3 = 0;
			BlockChest[] array = Object.FindObjectsOfType<BlockChest>();
			foreach (BlockChest val in array)
			{
				if ((Object)(object)val == (Object)null || Vector3.Distance(((Component)val).transform.position, position) > num2)
				{
					continue;
				}
				NetworkVariable<long> storedItemId = GetStoredItemId(val);
				if (storedItemId == null || storedItemId.Value <= 0)
				{
					continue;
				}
				int num4 = -1;
				int num5 = 0;
				for (int j = 0; j < num; j++)
				{
					if (component.slots[j].itemId == storedItemId.Value)
					{
						if (num4 < 0)
						{
							num4 = j;
						}
						num5 += component.slots[j].amount;
					}
				}
				if (num4 < 0 || num5 <= 0)
				{
					continue;
				}
				int num6 = GetStoredItemAmount(val)?.Value ?? 0;
				int num7 = val.maxCapacity - num6;
				if (num7 > 0)
				{
					int num8 = Mathf.Min(num5, num7);
					num3 += num8;
					if (CurrentSlotField.GetValue(component) is NetworkVariable<int> val2)
					{
						val2.Value = num4;
					}
					val.PlaceItemServerRpc(default(ServerRpcParams));
				}
			}
			if (num3 > 0 && (Object)(object)UIManager.Instance != (Object)null)
			{
				string localizedText = LocalizationManager.Instance.GetLocalizedText("hint.quick_stack_result", num3);
				UIManager.Instance.ShowNotification(localizedText, false, 3f, false);
			}
		}
	}
	[HarmonyPatch(typeof(BlockChest))]
	public static class GameManagerPatch
	{
		[HarmonyPatch("OnNetworkSpawn")]
		[HarmonyPostfix]
		public static void OnNetworkSpawn_Postfix(BlockChest __instance)
		{
			__instance.maxCapacity = ChestTools.GetCapacity();
		}
	}
	[HarmonyPatch(typeof(PlayerInventory))]
	public static class PlayerInventoryPatch
	{
		[HarmonyPatch("HandleScroll")]
		[HarmonyPrefix]
		public static bool HandleScroll_Prefix(PlayerInventory __instance)
		{
			if (!ChestTools.UsesMouseWheel())
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.playerInteraction == (Object)null)
			{
				return true;
			}
			ChestPickup pickup;
			return !PlayerInteractionPatch.TryGetChestPickup(__instance.playerInteraction, out pickup);
		}
	}
	[HarmonyPatch(typeof(UIManager))]
	internal static class UIManagerHotkeyPatch
	{
		private static bool _init;

		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void Awake_Postfix()
		{
			if (!_init)
			{
				_init = true;
				ChestTools.SetupQuickStack();
			}
		}
	}
}
namespace BetterResourceChest.Localization
{
	public static class LocalizationHelper
	{
		public static Dictionary<string, string> GetDefaultTranslations(string language)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			switch (language)
			{
			case "zh":
				dictionary.Add("plugin.initializing", "开始初始化...");
				dictionary.Add("plugin.author_prefix", "作者:");
				dictionary.Add("plugin.initialized", "初始化成功!");
				dictionary.Add("plugin.patches_skipped", "补丁已应用,跳过...");
				dictionary.Add("config.section.resource_chest", "材料箱");
				dictionary.Add("config.bulk_deposit", "一次性放置背包内相同物品");
				dictionary.Add("config.default_take_amount", "默认取出数量\n默认:5");
				dictionary.Add("config.take_amount_up", "增加取出数量的快捷键\n留空使用鼠标滚轮\n默认:无");
				dictionary.Add("config.take_amount_down", "减少取出数量的快捷键\n留空使用鼠标滚轮\n默认:无");
				dictionary.Add("config.capacity", "材料箱容量\n默认:250");
				dictionary.Add("config.quick_stack_enabled", "启用快速堆叠");
				dictionary.Add("config.quick_stack_key", "快速堆叠快捷键\n默认:T");
				dictionary.Add("config.quick_stack_range", "快速堆叠范围(米)\n默认:5");
				dictionary.Add("hint.take_amount", "当前取出: {0} | 使用 {1} 调整取出数量");
				dictionary.Add("hint.quick_stack_result", "已将 {0} 件物品存入附近的材料箱。");
				break;
			case "zh-Hant":
				dictionary.Add("plugin.initializing", "開始初始化...");
				dictionary.Add("plugin.author_prefix", "作者:");
				dictionary.Add("plugin.initialized", "初始化成功!");
				dictionary.Add("plugin.patches_skipped", "補丁已應用,跳過...");
				dictionary.Add("config.section.resource_chest", "材料箱");
				dictionary.Add("config.bulk_deposit", "一次性放置背包內相同物品");
				dictionary.Add("config.default_take_amount", "預設取出數量\n預設:5");
				dictionary.Add("config.take_amount_up", "增加取出數量的快捷鍵\n留空使用滑鼠滾輪\n預設:無");
				dictionary.Add("config.take_amount_down", "減少取出數量的快捷鍵\n留空使用滑鼠滾輪\n預設:無");
				dictionary.Add("config.capacity", "材料箱容量\n預設:250");
				dictionary.Add("config.quick_stack_enabled", "啟用快速堆疊");
				dictionary.Add("config.quick_stack_key", "快速堆疊快捷鍵\n預設:T");
				dictionary.Add("config.quick_stack_range", "快速堆疊範圍(公尺)\n預設:5");
				dictionary.Add("hint.take_amount", "目前取出: {0} | 使用 {1} 調整取出數量");
				dictionary.Add("hint.quick_stack_result", "已將 {0} 件物品存入附近的材料箱。");
				break;
			case "en":
				dictionary.Add("plugin.initializing", "Initializing...");
				dictionary.Add("plugin.author_prefix", "Author: ");
				dictionary.Add("plugin.initialized", "Initialized");
				dictionary.Add("plugin.patches_skipped", "Patches already applied");
				dictionary.Add("config.section.resource_chest", "Resource chest");
				dictionary.Add("config.bulk_deposit", "Deposit all matching items at once");
				dictionary.Add("config.default_take_amount", "Default take amount\nDefault: 5");
				dictionary.Add("config.take_amount_up", "Increase take amount hotkey\nLeave empty to use mouse wheel\nDefault: None");
				dictionary.Add("config.take_amount_down", "Decrease take amount hotkey\nLeave empty to use mouse wheel\nDefault: None");
				dictionary.Add("config.capacity", "Resource chest capacity\nDefault: 250");
				dictionary.Add("config.quick_stack_enabled", "Enable quick stack");
				dictionary.Add("config.quick_stack_key", "Quick stack hotkey\nDefault: T");
				dictionary.Add("config.quick_stack_range", "Quick stack range (m)\nDefault: 5");
				dictionary.Add("hint.take_amount", "Take amount: {0} | Use {1} to adjust");
				dictionary.Add("hint.quick_stack_result", "Deposited {0} items to nearby chests.");
				break;
			case "ja":
				dictionary.Add("plugin.initializing", "初期化中...");
				dictionary.Add("plugin.author_prefix", "作者:");
				dictionary.Add("plugin.initialized", "初期化に成功しました!");
				dictionary.Add("plugin.patches_skipped", "パッチは既に適用されています。スキップします...");
				dictionary.Add("config.section.resource_chest", "資源箱");
				dictionary.Add("config.bulk_deposit", "同じアイテムを一度に預ける");
				dictionary.Add("config.default_take_amount", "デフォルト取出数\nデフォルト:5");
				dictionary.Add("config.take_amount_up", "取出数を増やすホットキー\n空の場合はマウスホイール\nデフォルト:なし");
				dictionary.Add("config.take_amount_down", "取出数を減らすホットキー\n空の場合はマウスホイール\nデフォルト:なし");
				dictionary.Add("config.capacity", "資源箱の容量\nデフォルト:250");
				dictionary.Add("config.quick_stack_enabled", "クイックスタックを有効にする");
				dictionary.Add("config.quick_stack_key", "クイックスタックホットキー\nデフォルト:T");
				dictionary.Add("config.quick_stack_range", "クイックスタック範囲(m)\nデフォルト:5");
				dictionary.Add("hint.take_amount", "取出数: {0} | {1}で調整");
				dictionary.Add("hint.quick_stack_result", "{0}個のアイテムを近くの資源箱に預けました。");
				break;
			}
			return dictionary;
		}
	}
	public class LocalizationManager
	{
		private static LocalizationManager _instance;

		private readonly Dictionary<string, Dictionary<string, string>> _localizations = new Dictionary<string, Dictionary<string, string>>();

		private string _currentLocale = "zh";

		public static readonly string[] SupportedLanguages = new string[12]
		{
			"zh", "zh-Hant", "en", "fr", "de", "ja", "ko", "pt", "ru", "es",
			"tr", "uk"
		};

		public static LocalizationManager Instance => _instance ?? (_instance = new LocalizationManager());

		private LocalizationManager()
		{
			Initialize();
		}

		public void Initialize()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)LocalizationSettings.SelectedLocale != (Object)null)
			{
				LocaleIdentifier identifier = LocalizationSettings.SelectedLocale.Identifier;
				_currentLocale = ((LocaleIdentifier)(ref identifier)).Code;
			}
			string[] supportedLanguages = SupportedLanguages;
			foreach (string text in supportedLanguages)
			{
				Dictionary<string, string> defaultTranslations = LocalizationHelper.GetDefaultTranslations(text);
				if (defaultTranslations != null && defaultTranslations.Count > 0)
				{
					_localizations[text] = defaultTranslations;
				}
			}
			LocalizationSettings.SelectedLocaleChanged += OnGameLanguageChanged;
		}

		private void OnGameLanguageChanged(Locale locale)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)locale != (Object)null)
			{
				LocaleIdentifier identifier = locale.Identifier;
				string code = ((LocaleIdentifier)(ref identifier)).Code;
				if (_localizations.ContainsKey(code))
				{
					_currentLocale = code;
				}
				else
				{
					_currentLocale = "en";
				}
			}
		}

		public string GetLocalizedText(string key, params object[] args)
		{
			if (string.IsNullOrEmpty(_currentLocale) || !_localizations.ContainsKey(_currentLocale))
			{
				_currentLocale = "en";
			}
			if (_localizations.ContainsKey(_currentLocale) && _localizations[_currentLocale].TryGetValue(key, out var value))
			{
				if (args.Length == 0)
				{
					return value;
				}
				return string.Format(value, args);
			}
			if (_currentLocale != "en" && _localizations.ContainsKey("en") && _localizations["en"].TryGetValue(key, out var value2))
			{
				if (args.Length == 0)
				{
					return value2;
				}
				return string.Format(value2, args);
			}
			if (_localizations.ContainsKey("zh") && _localizations["zh"].TryGetValue(key, out var value3))
			{
				if (args.Length == 0)
				{
					return value3;
				}
				return string.Format(value3, args);
			}
			return key;
		}
	}
}
namespace BetterResourceChest.Configuration
{
	public class ConfigManager
	{
		private static ConfigManager _instance;

		private readonly ConfigFile _configFile;

		private readonly Dictionary<string, ConfigEntry<bool>> _boolConfigs;

		private readonly Dictionary<string, ConfigEntry<string>> _stringConfigs;

		private readonly Dictionary<string, ConfigEntry<int>> _intConfigs;

		private readonly Dictionary<string, ConfigEntry<float>> _floatConfigs;

		public static ConfigManager Instance => _instance;

		private ConfigManager(ConfigFile configFile)
		{
			_configFile = configFile;
			_boolConfigs = new Dictionary<string, ConfigEntry<bool>>();
			_stringConfigs = new Dictionary<string, ConfigEntry<string>>();
			_intConfigs = new Dictionary<string, ConfigEntry<int>>();
			_floatConfigs = new Dictionary<string, ConfigEntry<float>>();
			InitializeDefaultConfigs();
		}

		public static void Initialize(ConfigFile configFile)
		{
			if (_instance == null)
			{
				_instance = new ConfigManager(configFile);
			}
		}

		private void InitializeDefaultConfigs()
		{
			string section = Text("config.section.resource_chest");
			RegisterBool(section, "BulkDeposit", Text("config.bulk_deposit"), defaultValue: true);
			RegisterInt(section, "DefaultTakeAmount", Text("config.default_take_amount"), 5);
			RegisterString(section, "TakeAmountUp", Text("config.take_amount_up"), "");
			RegisterString(section, "TakeAmountDown", Text("config.take_amount_down"), "");
			RegisterInt(section, "Capacity", Text("config.capacity"), 300);
			RegisterBool(section, "QuickStackEnabled", Text("config.quick_stack_enabled"), defaultValue: true);
			RegisterString(section, "QuickStackKey", Text("config.quick_stack_key"), "T");
			RegisterFloat(section, "QuickStackRange", Text("config.quick_stack_range"), 5f);
		}

		private string Text(string key)
		{
			return LocalizationManager.Instance?.GetLocalizedText(key);
		}

		public ConfigEntry<bool> RegisterBool(string section, string key, string description, bool defaultValue)
		{
			ConfigEntry<bool> val = _configFile.Bind<bool>(section, key, defaultValue, description);
			_boolConfigs[key] = val;
			return val;
		}

		public ConfigEntry<string> RegisterString(string section, string key, string description, string defaultValue)
		{
			ConfigEntry<string> val = _configFile.Bind<string>(section, key, defaultValue, description);
			_stringConfigs[key] = val;
			return val;
		}

		public ConfigEntry<int> RegisterInt(string section, string key, string description, int defaultValue)
		{
			ConfigEntry<int> val = _configFile.Bind<int>(section, key, defaultValue, description);
			_intConfigs[key] = val;
			return val;
		}

		public ConfigEntry<float> RegisterFloat(string section, string key, string description, float defaultValue)
		{
			ConfigEntry<float> val = _configFile.Bind<float>(section, key, defaultValue, description);
			_floatConfigs[key] = val;
			return val;
		}

		public bool IsPatchEnabled(string key)
		{
			if (_boolConfigs.TryGetValue(key, out var value))
			{
				return value.Value;
			}
			return false;
		}

		public float GetFloat(string key, float defaultValue = 0f)
		{
			if (_floatConfigs.TryGetValue(key, out var value))
			{
				return value.Value;
			}
			return defaultValue;
		}

		public int GetInt(string key, int defaultValue = 0)
		{
			if (_intConfigs.TryGetValue(key, out var value))
			{
				return value.Value;
			}
			return defaultValue;
		}

		public string GetString(string key, string defaultValue = "")
		{
			if (_stringConfigs.TryGetValue(key, out var value))
			{
				return value.Value;
			}
			return defaultValue;
		}
	}
}