Decompiled source of VoidChest v0.5.1

VoidChest.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VoidChest
{
	internal static class ExtraSlotsCompat
	{
		private static bool _initialized;

		private static MethodInfo _getEquipped;

		private static bool _warned;

		private static bool _slotLookupInitialized;

		private static MethodInfo _getItemSlot;

		private static bool _slotLookupWarned;

		private static MethodInfo GetMethod()
		{
			if (_initialized)
			{
				return _getEquipped;
			}
			_initialized = true;
			Type type = AccessTools.TypeByName("ExtraSlots.ExtraUtilitySlots");
			if (type == null)
			{
				VLog.Debug("未检测到 ExtraSlots。");
				return null;
			}
			_getEquipped = AccessTools.Method(type, "GetEquippedItems", new Type[1] { typeof(Humanoid) }, (Type[])null);
			if (_getEquipped != null)
			{
				VLog.Info("检测到 ExtraSlots,额外 Utility 槽参与检测。");
			}
			else
			{
				VLog.Warn("检测到 ExtraSlots 但未找到 ExtraUtilitySlots.GetEquippedItems,跳过额外槽检测。");
			}
			return _getEquipped;
		}

		private static MethodInfo GetItemSlotMethod()
		{
			if (_slotLookupInitialized)
			{
				return _getItemSlot;
			}
			_slotLookupInitialized = true;
			Type type = AccessTools.TypeByName("ExtraSlots.Slots");
			if (type == null)
			{
				return null;
			}
			_getItemSlot = AccessTools.Method(type, "GetItemSlot", new Type[1] { typeof(ItemData) }, (Type[])null);
			if (_getItemSlot == null)
			{
				VLog.Warn("未找到 ExtraSlots.Slots.GetItemSlot,专用槽位物品过滤降级。");
			}
			return _getItemSlot;
		}

		internal static bool IsInExtraSlot(ItemData item)
		{
			if (item == null)
			{
				return false;
			}
			MethodInfo itemSlotMethod = GetItemSlotMethod();
			if (itemSlotMethod == null)
			{
				return false;
			}
			try
			{
				return itemSlotMethod.Invoke(null, new object[1] { item }) != null;
			}
			catch (Exception ex)
			{
				if (!_slotLookupWarned)
				{
					_slotLookupWarned = true;
					VLog.Warn("ExtraSlots.GetItemSlot 调用失败,专用槽位过滤降级: " + ex.Message);
				}
				return false;
			}
		}

		internal static List<ItemData> GetEquippedItems(Humanoid humanoid)
		{
			MethodInfo method = GetMethod();
			if (method == null || (Object)(object)humanoid == (Object)null)
			{
				return null;
			}
			try
			{
				return method.Invoke(null, new object[1] { humanoid }) as List<ItemData>;
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					VLog.Warn("ExtraSlots 检测失败,降级跳过额外槽: " + ex.Message);
				}
				return null;
			}
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class ContainerAwakePatch
	{
		private static bool Prefix(Container __instance)
		{
			if (__instance is VirtualContainer virtualContainer)
			{
				virtualContainer.InitVirtual();
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Container), "IsOwner")]
	internal static class ContainerIsOwnerPatch
	{
		private static bool Prefix(Container __instance, ref bool __result)
		{
			if (__instance is VirtualContainer)
			{
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Container), "SetInUse")]
	internal static class ContainerSetInUsePatch
	{
		private static bool Prefix(Container __instance)
		{
			return !(__instance is VirtualContainer);
		}
	}
	[HarmonyPatch(typeof(Container), "IsInUse")]
	internal static class ContainerIsInUsePatch
	{
		private static bool Prefix(Container __instance, ref bool __result)
		{
			if (__instance is VirtualContainer)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Container), "CheckForChanges")]
	internal static class ContainerCheckForChangesPatch
	{
		private static bool Prefix(Container __instance)
		{
			return !(__instance is VirtualContainer);
		}
	}
	[HarmonyPatch(typeof(Player), "Save")]
	internal static class PlayerSavePatch
	{
		private static void Prefix(Player __instance)
		{
			VoidChestManager.FlushActive(__instance);
		}
	}
	[HarmonyPatch(typeof(Inventory), "StackAll")]
	internal static class InventoryStackAllPatch
	{
		private static bool Prefix(Inventory __instance, Inventory fromInventory, ref int __result)
		{
			if (!VoidChestNearbyStore.FilterActive)
			{
				return true;
			}
			__result = VoidChestFilter.StackAllFiltered(__instance, fromInventory);
			return false;
		}
	}
	[HarmonyPatch(typeof(Container), "RPC_StackResponse")]
	internal static class ContainerRpcStackResponsePatch
	{
		private static void Postfix(long uid, bool granted)
		{
			VoidChestNearbyStore.OnStackResponse(granted);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Show")]
	internal static class InventoryGuiShowPatch
	{
		private static void Postfix(Container container)
		{
			VoidChestUi.OnContainerShown(container);
			VoidChestDiagnostics.DumpRecipesAndInventory();
		}
	}
	[HarmonyPatch]
	internal static class InventoryMoveItemToThisAmountPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Inventory), "MoveItemToThis", new Type[5]
			{
				typeof(Inventory),
				typeof(ItemData),
				typeof(int),
				typeof(int),
				typeof(int)
			}, (Type[])null);
		}

		private static bool Prefix(Inventory __instance, ItemData item, ref int amount)
		{
			if (item == null || !VoidChestWeight.IsVirtualInventory(__instance))
			{
				return true;
			}
			int num = VoidChestWeight.AllowedAmount(__instance, item, amount);
			if (num <= 0)
			{
				return false;
			}
			amount = num;
			return true;
		}
	}
	[HarmonyPatch]
	internal static class InventoryMoveItemToThisAllPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Inventory), "MoveItemToThis", new Type[2]
			{
				typeof(Inventory),
				typeof(ItemData)
			}, (Type[])null);
		}

		private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item)
		{
			if (item == null || fromInventory == null || !VoidChestWeight.IsVirtualInventory(__instance))
			{
				return true;
			}
			int num = VoidChestWeight.AllowedAmount(__instance, item, item.m_stack);
			if (num <= 0)
			{
				return false;
			}
			if (num >= item.m_stack)
			{
				return true;
			}
			VoidChestWeight.MovePartialToContainer(__instance, fromInventory, item, num);
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateContainerWeight")]
	internal static class InventoryGuiContainerWeightPatch
	{
		private static void Postfix(InventoryGui __instance)
		{
			VirtualContainer currentContainer = VoidChestManager.CurrentContainer;
			if (!((Object)(object)currentContainer == (Object)null) && !((Object)(object)__instance == (Object)null) && !((Object)(object)VoidChestManager.CurrentOpenedContainer(__instance) != (Object)(object)currentContainer))
			{
				Inventory inventory = ((Container)currentContainer).GetInventory();
				if (inventory != null)
				{
					int num = Mathf.CeilToInt(inventory.GetTotalWeight());
					__instance.m_containerWeight.text = ((currentContainer.MaxWeight > 0f) ? $"{num}/{Mathf.RoundToInt(currentContainer.MaxWeight)}" : num.ToString());
				}
			}
		}
	}
	[BepInPlugin("trigger.valheim.voidchest", "Void Chest", "0.5.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class VoidChestPlugin : BaseUnityPlugin
	{
		public const string Guid = "trigger.valheim.voidchest";

		public const string PluginName = "Void Chest";

		public const string PluginVersion = "0.5.1";

		internal static VoidChestPlugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> OpenHotkey;

		internal static ConfigEntry<bool> DebugLog;

		internal static ConfigEntry<int> CapacityBlackMetalRows;

		internal static ConfigEntry<int> CapacityBlackMetalCols;

		internal static ConfigEntry<int> CapacityMagicRows;

		internal static ConfigEntry<int> CapacityMagicCols;

		internal static ConfigEntry<int> CapacityFlameRows;

		internal static ConfigEntry<int> CapacityFlameCols;

		internal static ConfigEntry<int> CapacityCrystalRows;

		internal static ConfigEntry<int> CapacityCrystalCols;

		internal static ConfigEntry<float> WeightBlackMetal;

		internal static ConfigEntry<float> WeightMagic;

		internal static ConfigEntry<float> WeightFlame;

		internal static ConfigEntry<float> WeightCrystal;

		internal static ConfigEntry<bool> EnableNearbyStore;

		internal static ConfigEntry<float> NearbyStoreRange;

		internal static ConfigEntry<bool> NearbyStoreCheckWard;

		internal static ConfigEntry<bool> NearbyStoreIgnoreHotbar;

		internal static ConfigEntry<bool> NearbyStoreIgnoreFood;

		internal static ConfigEntry<bool> NearbyStoreIgnoreAmmo;

		internal static ConfigEntry<bool> NearbyStoreIgnoreMead;

		internal static ConfigEntry<float> NearbyStoreTimeout;

		internal static ConfigEntry<bool> EnableRemoteStore;

		internal static ConfigEntry<bool> RemoteStoreAlwaysAvailable;

		internal static ConfigEntry<float> RemoteStoreCacheSeconds;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Expected O, but got Unknown
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Expected O, but got Unknown
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Expected O, but got Unknown
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Expected O, but got Unknown
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Expected O, but got Unknown
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Expected O, but got Unknown
			//IL_0510: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			OpenHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "OpenHotkey", (KeyCode)98, "打开/关闭虚空宝箱容器界面的热键。");
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", true, "输出详细调试日志(诊断用,默认开启)。");
			AcceptableValueRange<int> val = new AcceptableValueRange<int>(1, 8);
			CapacityBlackMetalRows = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "BlackMetal.Rows", 2, new ConfigDescription("黑金属虚空宝箱:行数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityBlackMetalCols = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "BlackMetal.Cols", 6, new ConfigDescription("黑金属虚空宝箱:列数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityMagicRows = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "Magic.Rows", 3, new ConfigDescription("魔能虚空宝箱:行数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityMagicCols = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "Magic.Cols", 6, new ConfigDescription("魔能虚空宝箱:列数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityFlameRows = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "Flame.Rows", 3, new ConfigDescription("烈焰虚空宝箱:行数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityFlameCols = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "Flame.Cols", 8, new ConfigDescription("烈焰虚空宝箱:列数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityCrystalRows = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "Crystal.Rows", 4, new ConfigDescription("水晶虚空宝箱:行数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			CapacityCrystalCols = ((BaseUnityPlugin)this).Config.Bind<int>("Capacity", "Crystal.Cols", 8, new ConfigDescription("水晶虚空宝箱:列数。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			AcceptableValueRange<float> val2 = new AcceptableValueRange<float>(0f, 9999f);
			WeightBlackMetal = ((BaseUnityPlugin)this).Config.Bind<float>("Weight", "BlackMetal.Max", 100f, new ConfigDescription("黑金属虚空宝箱:重量上限(0 = 无限制)。", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
			WeightMagic = ((BaseUnityPlugin)this).Config.Bind<float>("Weight", "Magic.Max", 150f, new ConfigDescription("魔能虚空宝箱:重量上限(0 = 无限制)。", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
			WeightFlame = ((BaseUnityPlugin)this).Config.Bind<float>("Weight", "Flame.Max", 300f, new ConfigDescription("烈焰虚空宝箱:重量上限(0 = 无限制)。", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
			WeightCrystal = ((BaseUnityPlugin)this).Config.Bind<float>("Weight", "Crystal.Max", 800f, new ConfigDescription("水晶虚空宝箱:重量上限(0 = 无限制)。", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
			EnableRemoteStore = ((BaseUnityPlugin)this).Config.Bind<bool>("RemoteStore", "Enabled", true, "启用虚空宝箱界面上的远程存入功能(守护石仓库)。仅单机/主机模式可用。");
			RemoteStoreAlwaysAvailable = ((BaseUnityPlugin)this).Config.Bind<bool>("RemoteStore", "AlwaysAvailable", false, "远程存储是否一直可用。false = 需要装备魔能(L2)及以上宝箱才解锁;true = 初始即可用。");
			RemoteStoreCacheSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("RemoteStore", "CacheSeconds", 300f, new ConfigDescription("远程存入的扫描结果缓存时间(秒)。0 = 每次重新扫描(慢)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), Array.Empty<object>()));
			EnableNearbyStore = ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyStore", "Enabled", true, "启用附近存储功能(不影响原版与 V+ 的堆叠按钮行为)。");
			NearbyStoreRange = ((BaseUnityPlugin)this).Config.Bind<float>("NearbyStore", "Range", 30f, new ConfigDescription("附近存储搜索半径(米)。范围 1-100,默认 30。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			NearbyStoreCheckWard = ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyStore", "CheckWard", true, "跳过无权限的领地(守护石)内的容器。");
			NearbyStoreIgnoreHotbar = ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyStore", "IgnoreHotbar", true, "不存储物品栏第一排(快捷栏)的物品(通常放置装备)。");
			NearbyStoreIgnoreFood = ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyStore", "IgnoreFood", false, "不存储食物。");
			NearbyStoreIgnoreAmmo = ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyStore", "IgnoreAmmo", false, "不存储弹药。");
			NearbyStoreIgnoreMead = ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyStore", "IgnoreMead", false, "不存储蜜酒/药水。");
			NearbyStoreTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("NearbyStore", "TimeoutSeconds", 2f, "单个容器等待 RPC 响应超时(秒),超时后跳过。");
			if (Mathf.Approximately(NearbyStoreRange.Value, 10f))
			{
				NearbyStoreRange.Value = 30f;
				VLog.Info("附近存储范围已从旧默认 10 更新为 30(可在 ConfigurationManager 中调整)。");
			}
			VLog.Info("Void Chest v0.5.1 初始化中...");
			_harmony = new Harmony("trigger.valheim.voidchest");
			_harmony.PatchAll(typeof(VoidChestPlugin).Assembly);
			foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
			{
				VLog.Info("  Harmony patch: " + patchedMethod.DeclaringType?.Name + "." + patchedMethod.Name);
			}
			VPlusGate.Install(_harmony);
			VoidChestLocalization.Register();
			VoidChestItems.Register();
			VLog.Info(string.Format("{0} v{1} 初始化完成。热键={2}, Debug={3}, 附近存储={4}, 远程存入={5}(Always={6})", "Void Chest", "0.5.1", OpenHotkey.Value, DebugLog.Value, EnableNearbyStore.Value, EnableRemoteStore.Value, RemoteStoreAlwaysAvailable.Value));
		}

		private void Update()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			VoidChestNearbyStore.Update();
			VoidChestRemoteStore.Update();
			VoidChestRemoteNet.Update();
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)InventoryGui.instance == (Object)null) && Input.GetKeyDown(OpenHotkey.Value))
			{
				VoidChestManager.Toggle(localPlayer);
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
	public class VirtualContainer : Container
	{
		private static readonly FieldRef<Container, Inventory> InventoryRef = AccessTools.FieldRefAccess<Container, Inventory>("m_inventory");

		internal bool SuppressSave;

		internal float MaxWeight;

		internal void InitVirtual()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			SetInventory(new Inventory("Void Chest", (Sprite)null, 6, 2));
			VLog.Debug("VirtualContainer.InitVirtual: 占位 Inventory 6x2 已创建。");
		}

		internal void SetInventory(Inventory inv)
		{
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory != null)
			{
				inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(OnInventoryChanged));
			}
			InventoryRef.Invoke((Container)(object)this) = inv;
			if (inv != null)
			{
				inv.m_onChanged = (Action)Delegate.Combine(inv.m_onChanged, new Action(OnInventoryChanged));
			}
			VLog.Debug("VirtualContainer.SetInventory: " + ((inv != null) ? (inv.GetWidth() + "x" + inv.GetHeight()) : "null"));
		}

		private void OnInventoryChanged()
		{
			if (SuppressSave)
			{
				VLog.Debug("OnInventoryChanged: SuppressSave=true,跳过保存。");
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			Inventory inventory = ((Container)this).GetInventory();
			if ((Object)(object)localPlayer != (Object)null && inventory != null)
			{
				VLog.Debug($"OnInventoryChanged: 库存变更 -> {inventory.NrOfItems()} 件,保存。");
				VoidChestSave.SaveFrom(inventory, localPlayer);
			}
		}
	}
	internal static class VLog
	{
		internal static bool DebugEnabled
		{
			get
			{
				if (VoidChestPlugin.DebugLog != null)
				{
					return VoidChestPlugin.DebugLog.Value;
				}
				return true;
			}
		}

		internal static void Debug(string message)
		{
			if (DebugEnabled)
			{
				VoidChestPlugin.Log.LogInfo((object)("[Debug] " + message));
			}
		}

		internal static void Info(string message)
		{
			VoidChestPlugin.Log.LogInfo((object)message);
		}

		internal static void Warn(string message)
		{
			VoidChestPlugin.Log.LogWarning((object)message);
		}

		internal static void Error(string message, Exception e = null)
		{
			VoidChestPlugin.Log.LogError((object)((e == null) ? message : (message + Environment.NewLine + e)));
		}
	}
	internal static class VoidChestDiagnostics
	{
		private static readonly FieldInfo KnownRecipesField = AccessTools.Field(typeof(Player), "m_knownRecipes");

		private static readonly FieldInfo KnownStationsField = AccessTools.Field(typeof(Player), "m_knownStations");

		private static readonly FieldInfo KnownMaterialField = AccessTools.Field(typeof(Player), "m_knownMaterial");

		private static float _lastDump = -999f;

		internal static void DumpRecipesAndInventory()
		{
			if (VoidChestPlugin.DebugLog == null || !VoidChestPlugin.DebugLog.Value || Time.realtimeSinceStartup - _lastDump < 2f)
			{
				return;
			}
			_lastDump = Time.realtimeSinceStartup;
			try
			{
				Dump();
			}
			catch (Exception ex)
			{
				VLog.Warn("配方诊断失败: " + ex.Message);
			}
		}

		private static void Dump()
		{
			Player localPlayer = Player.m_localPlayer;
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null)
			{
				return;
			}
			HashSet<string> hashSet = (KnownRecipesField?.GetValue(localPlayer) as HashSet<string>) ?? new HashSet<string>();
			Dictionary<string, int> dictionary = (KnownStationsField?.GetValue(localPlayer) as Dictionary<string, int>) ?? new Dictionary<string, int>();
			HashSet<string> hashSet2 = (KnownMaterialField?.GetValue(localPlayer) as HashSet<string>) ?? new HashSet<string>();
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			StringBuilder stringBuilder = new StringBuilder(2048);
			stringBuilder.AppendLine("========== 虚空宝箱配方诊断 ==========");
			foreach (Recipe recipe in instance.m_recipes)
			{
				if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null)
				{
					continue;
				}
				string name = ((Object)recipe.m_item).name;
				if (!name.StartsWith("VoidChest"))
				{
					continue;
				}
				ItemDrop component = ((Component)recipe.m_item).GetComponent<ItemDrop>();
				string text = (((Object)(object)component != (Object)null) ? component.m_itemData.m_shared.m_name : "?");
				string text2 = Localization.instance.Localize(text);
				bool flag = hashSet.Contains(text);
				string text3 = (((Object)(object)recipe.m_craftingStation != (Object)null) ? ((Object)recipe.m_craftingStation).name : "(无)");
				string text4 = (((Object)(object)recipe.m_craftingStation != (Object)null) ? Localization.instance.Localize(recipe.m_craftingStation.m_name) : "(无)");
				int value = -1;
				if ((Object)(object)recipe.m_craftingStation != (Object)null)
				{
					dictionary.TryGetValue(recipe.m_craftingStation.m_name, out value);
				}
				string text5 = ((value < 0) ? "未记录" : value.ToString());
				stringBuilder.AppendLine("[" + name + "] 成品=" + text2 + "(" + text + ")");
				stringBuilder.AppendLine($"    解锁={flag} | 工作台={text4}({text3}) | 需要等级={recipe.m_minStationLevel} | 玩家已知该工作台等级={text5} | 只需一种材料={recipe.m_requireOnlyOneIngredient}");
				List<string> list = new List<string>();
				if (recipe.m_resources != null)
				{
					Requirement[] resources = recipe.m_resources;
					foreach (Requirement val in resources)
					{
						if (val == null || (Object)(object)val.m_resItem == (Object)null)
						{
							stringBuilder.AppendLine("    材料: <null 引用>");
							continue;
						}
						string name2 = val.m_resItem.m_itemData.m_shared.m_name;
						string text6 = Localization.instance.Localize(name2);
						int num = inventory.CountItems(name2, -1, true);
						bool flag2 = hashSet2.Contains(name2);
						stringBuilder.AppendLine($"    材料: {((Object)val.m_resItem).name}({text6}) 需要={val.m_amount} 背包数量={num} 已见过={flag2}");
						if (!flag2)
						{
							list.Add(text6 + "/" + ((Object)val.m_resItem).name);
						}
					}
				}
				List<string> list2 = new List<string>();
				if (!flag)
				{
					if (list.Count > 0)
					{
						list2.Add("材料未见过: " + string.Join(", ", list));
					}
					if ((Object)(object)recipe.m_craftingStation != (Object)null && value < recipe.m_minStationLevel)
					{
						list2.Add($"工作台等级不足/未知(玩家={text5},需要={recipe.m_minStationLevel})");
					}
				}
				stringBuilder.AppendLine(flag ? "    状态: 已解锁" : ("    未解锁原因: " + ((list2.Count > 0) ? string.Join("; ", list2) : "未知(其他条件)")));
			}
			List<ItemData> allItems = inventory.GetAllItems();
			stringBuilder.AppendLine($"---- 玩家背包物品({allItems.Count})----");
			foreach (ItemData item in allItems)
			{
				if (item != null)
				{
					string arg = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "(无prefab)");
					stringBuilder.AppendLine($"    {arg} | {Localization.instance.Localize(item.m_shared.m_name)} | x{item.m_stack}");
				}
			}
			stringBuilder.AppendLine($"---- 玩家已记录工作台({dictionary.Count})----");
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				stringBuilder.AppendLine($"    {Localization.instance.Localize(item2.Key)} = {item2.Value}");
			}
			stringBuilder.Append("=======================================");
			VoidChestPlugin.Log.LogInfo((object)stringBuilder.ToString());
		}
	}
	internal static class VoidChestFilter
	{
		internal static bool ShouldSkip(ItemData item)
		{
			//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)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			if (VoidChestPlugin.NearbyStoreIgnoreHotbar.Value && item.m_gridPos.y == 0)
			{
				VLog.Debug("存储过滤:跳过快捷栏物品 " + item.m_shared.m_name);
				return true;
			}
			if (ExtraSlotsCompat.IsInExtraSlot(item))
			{
				VLog.Debug("存储过滤:跳过额外槽位物品 " + item.m_shared.m_name);
				return true;
			}
			SharedData shared = item.m_shared;
			ItemType itemType = shared.m_itemType;
			if (VoidChestPlugin.NearbyStoreIgnoreAmmo.Value && ((int)itemType == 9 || (int)itemType == 23))
			{
				return true;
			}
			if ((int)itemType == 2)
			{
				bool flag = shared.m_food > 0f;
				if (flag && VoidChestPlugin.NearbyStoreIgnoreFood.Value)
				{
					return true;
				}
				if (!flag && VoidChestPlugin.NearbyStoreIgnoreMead.Value)
				{
					return true;
				}
			}
			return false;
		}

		internal static int StackAllRaw(Inventory container, Inventory from)
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			List<ItemData> list = new List<ItemData>(from.GetAllItems());
			int num = 0;
			foreach (ItemData item in list)
			{
				if (item != null && item.m_shared != null && container.ContainsItemByName(item.m_shared.m_name) && container.AddItem(item))
				{
					from.RemoveItem(item);
					num++;
				}
			}
			stopwatch.Stop();
			VoidChestPerf.AddStack(stopwatch.Elapsed.TotalMilliseconds);
			VLog.Debug($"StackAllRaw: {container.GetName()} 移动 {num} 堆叠,耗时 {stopwatch.Elapsed.TotalMilliseconds:F2}ms");
			return num;
		}

		internal static int StackAllFiltered(Inventory container, Inventory from)
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			List<ItemData> list = new List<ItemData>(from.GetAllItems());
			int num = 0;
			Player localPlayer = Player.m_localPlayer;
			foreach (ItemData item in list)
			{
				if (item != null && container.ContainsItemByName(item.m_shared.m_name) && (!((Object)(object)localPlayer != (Object)null) || !((Humanoid)localPlayer).IsItemEquiped(item)) && !ShouldSkip(item) && container.AddItem(item))
				{
					from.RemoveItem(item);
					num++;
				}
			}
			stopwatch.Stop();
			VoidChestPerf.AddStack(stopwatch.Elapsed.TotalMilliseconds);
			VLog.Debug($"StackAllFiltered: {container.GetName()} 移动 {num} 堆叠,耗时 {stopwatch.Elapsed.TotalMilliseconds:F2}ms");
			return num;
		}
	}
	internal static class VoidChestItemIdentity
	{
		internal static string Of(ItemData item)
		{
			StringBuilder stringBuilder = new StringBuilder(96);
			stringBuilder.Append(((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "?").Append('|');
			stringBuilder.Append(item.m_quality).Append('|');
			stringBuilder.Append(item.m_variant).Append('|');
			stringBuilder.Append(item.m_worldLevel).Append('|');
			stringBuilder.Append(Mathf.RoundToInt(item.m_durability * 100f)).Append('|');
			stringBuilder.Append(item.m_crafterID).Append('|');
			stringBuilder.Append(item.m_crafterName).Append('|');
			stringBuilder.Append(item.m_pickedUp ? '1' : '0').Append('|');
			stringBuilder.Append(item.m_cheated ? '1' : '0');
			Dictionary<string, string> customData = item.m_customData;
			if (customData != null && customData.Count > 0)
			{
				List<string> list = new List<string>(customData.Keys);
				list.Sort(StringComparer.Ordinal);
				foreach (string item2 in list)
				{
					string text = customData[item2] ?? string.Empty;
					stringBuilder.Append('|').Append(item2.Length).Append(':')
						.Append(item2)
						.Append('=')
						.Append(text.Length)
						.Append(':')
						.Append(text);
				}
			}
			return stringBuilder.ToString();
		}

		internal static Dictionary<string, int> Totals(Inventory inv)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			if (inv == null)
			{
				return dictionary;
			}
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (allItem != null && allItem.m_shared != null)
				{
					string key = Of(allItem);
					dictionary.TryGetValue(key, out var value);
					dictionary[key] = value + allItem.m_stack;
				}
			}
			return dictionary;
		}
	}
	internal static class VoidChestItems
	{
		internal const string BlackMetal = "VoidChestBlackMetal";

		internal const string Magic = "VoidChestMagic";

		internal const string Flame = "VoidChestFlame";

		internal const string Crystal = "VoidChestCrystal";

		private const string BasePrefab = "chest_hildir2";

		private static bool _registered;

		internal static readonly Dictionary<string, Color> Tints = new Dictionary<string, Color>
		{
			{
				"VoidChestBlackMetal",
				Color32.op_Implicit(new Color32((byte)208, (byte)120, byte.MaxValue, byte.MaxValue))
			},
			{
				"VoidChestMagic",
				Color32.op_Implicit(new Color32((byte)24, (byte)231, (byte)169, byte.MaxValue))
			},
			{
				"VoidChestFlame",
				Color32.op_Implicit(new Color32(byte.MaxValue, (byte)172, (byte)89, byte.MaxValue))
			},
			{
				"VoidChestCrystal",
				Color32.op_Implicit(new Color32(byte.MaxValue, (byte)69, (byte)69, byte.MaxValue))
			}
		};

		internal static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += RegisterItems;
			VLog.Info("已订阅 PrefabManager.OnVanillaPrefabsAvailable");
		}

		private static void RegisterItems()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			if (_registered)
			{
				VLog.Debug("物品已注册过,跳过。");
				return;
			}
			VLog.Info("原版 prefab 可用,开始注册虚空宝箱...");
			try
			{
				Add("VoidChestBlackMetal", "$item_voidchest_blackmetal", "$item_voidchest_blackmetal_desc", "forge", (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig("DragonTear", 5, 0, true),
					new RequirementConfig("FineWood", 10, 0, true),
					new RequirementConfig("BlackMetal", 20, 0, true)
				});
				Add("VoidChestMagic", "$item_voidchest_magic", "$item_voidchest_magic_desc", "forge", (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig("VoidChestBlackMetal", 1, 0, true),
					new RequirementConfig("Eitr", 10, 0, true),
					new RequirementConfig("YagluthDrop", 2, 0, true)
				});
				Add("VoidChestFlame", "$item_voidchest_flame", "$item_voidchest_flame_desc", "blackforge", (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig("VoidChestMagic", 1, 0, true),
					new RequirementConfig("FlametalNew", 10, 0, true),
					new RequirementConfig("FaderDrop", 2, 0, true)
				});
				Add("VoidChestCrystal", "$item_voidchest_crystal", "$item_voidchest_crystal_desc", "blackforge", (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig("VoidChestFlame", 1, 0, true),
					new RequirementConfig("Gold", 10, 0, true),
					new RequirementConfig("FrozenFuel", 10, 0, true)
				});
				_registered = true;
				VLog.Info("虚空宝箱物品与配方注册完成。");
			}
			catch (Exception e)
			{
				VLog.Error("注册虚空宝箱失败: ", e);
			}
		}

		private static void Add(string prefabName, string displayName, string description, string station, RequirementConfig[] requirements)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			List<string> list = new List<string>();
			foreach (RequirementConfig val in requirements)
			{
				list.Add($"{val.Item}x{val.Amount}");
			}
			VLog.Info("注册 [" + prefabName + "] 名称=" + displayName + " 工作台=" + station + " 材料=" + string.Join(", ", list));
			ItemConfig val2 = new ItemConfig
			{
				Name = prefabName,
				Description = prefabName,
				CraftingStation = station,
				MinStationLevel = 1,
				Amount = 1,
				Requirements = requirements,
				Weight = 2f
			};
			CustomItem val3 = new CustomItem(prefabName, "chest_hildir2", val2);
			if ((Object)(object)val3.ItemPrefab == (Object)null)
			{
				VLog.Error("[" + prefabName + "] CustomItem.ItemPrefab 为空(克隆 chest_hildir2 失败)");
			}
			Sanitize(val3, prefabName, displayName, description);
			ItemManager.Instance.AddItem(val3);
			CustomRecipe recipe = val3.Recipe;
			if (recipe == null)
			{
				VLog.Warn("[" + prefabName + "] 配方未生成(Recipe 为空)。");
				return;
			}
			object arg = (recipe.Recipe?.m_resources?.Length).GetValueOrDefault();
			Recipe recipe2 = recipe.Recipe;
			object arg2;
			if (recipe2 == null)
			{
				arg2 = null;
			}
			else
			{
				CraftingStation craftingStation = recipe2.m_craftingStation;
				arg2 = ((craftingStation != null) ? ((Object)craftingStation).name : null);
			}
			VLog.Info($"[{prefabName}] 配方已生成: {arg} 项材料, 工作台={arg2}");
		}

		private static void Sanitize(CustomItem item, string prefabName, string displayName, string description)
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			GameObject itemPrefab = item.ItemPrefab;
			if ((Object)(object)itemPrefab == (Object)null)
			{
				VLog.Error("[" + prefabName + "] 克隆失败:prefab 为空。");
				return;
			}
			Component[] componentsInChildren = itemPrefab.GetComponentsInChildren<Component>(true);
			List<string> list = new List<string>();
			Component[] array = componentsInChildren;
			foreach (Component val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					list.Add(((object)val).GetType().Name);
				}
			}
			VLog.Info("[" + prefabName + "] 组件结构: " + string.Join(", ", list));
			array = componentsInChildren;
			foreach (Component val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && (val2 is Container || val2 is Piece || val2 is WearNTear || val2 is Destructible || val2 is PrivateArea))
				{
					VLog.Info("[" + prefabName + "] 移除组件: " + ((object)val2).GetType().Name);
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			ItemDrop itemDrop = item.ItemDrop;
			if ((Object)(object)itemDrop == (Object)null)
			{
				VLog.Error("[" + prefabName + "] 没有 ItemDrop 组件,无法作为物品。");
				return;
			}
			SharedData shared = itemDrop.m_itemData.m_shared;
			shared.m_itemType = (ItemType)18;
			shared.m_maxStackSize = 1;
			shared.m_weight = 2f;
			shared.m_teleportable = true;
			shared.m_questItem = false;
			shared.m_name = displayName;
			shared.m_description = description;
			object[] obj = new object[5] { prefabName, shared.m_name, shared.m_itemType, shared.m_weight, null };
			Sprite[] icons = shared.m_icons;
			obj[4] = ((icons != null) ? icons.Length : 0);
			VLog.Info(string.Format("[{0}] ItemDrop: name={1}, type={2}, weight={3}, icons={4}", obj));
			Color val3 = Tints[prefabName];
			if (shared.m_icons != null && shared.m_icons.Length != 0)
			{
				for (int j = 0; j < shared.m_icons.Length; j++)
				{
					Sprite val4 = shared.m_icons[j];
					Sprite val5 = RecolorSprite(val4, val3);
					shared.m_icons[j] = val5;
					VLog.Info($"[{prefabName}] 图标[{j}] {SpriteInfo(val4)} -> {SpriteInfo(val5)}");
				}
			}
			else
			{
				VLog.Warn("[" + prefabName + "] 没有图标(m_icons 为空)。");
			}
			int num = RecolorRenderers(itemPrefab, val3);
			VLog.Info($"[{prefabName}] 材质换色: {num} 个材质设置 tint={ColorUtility.ToHtmlStringRGB(val3)}");
		}

		private static string SpriteInfo(Sprite sprite)
		{
			//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)
			if ((Object)(object)sprite == (Object)null)
			{
				return "null";
			}
			Texture2D texture = sprite.texture;
			Rect textureRect = sprite.textureRect;
			return string.Format("{0}/rect({1},{2},{3},{4})/ppu{5}", ((Object)(object)texture != (Object)null) ? (((Texture)texture).width + "x" + ((Texture)texture).height) : "no-tex", ((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, ((Rect)(ref textureRect)).width, ((Rect)(ref textureRect)).height, sprite.pixelsPerUnit);
		}

		private static Sprite RecolorSprite(Sprite src, Color tint)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)src == (Object)null)
			{
				return null;
			}
			Texture2D texture = src.texture;
			if ((Object)(object)texture == (Object)null)
			{
				return src;
			}
			Rect textureRect = src.textureRect;
			int num = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).width));
			int num2 = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).height));
			int num3 = Mathf.Max(1, ((Texture)texture).width);
			int num4 = Mathf.Max(1, ((Texture)texture).height);
			RenderTexture temporary = RenderTexture.GetTemporary(num3, num4, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			RenderTexture active = RenderTexture.active;
			try
			{
				Graphics.Blit((Texture)(object)texture, temporary);
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
				val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
				val.Apply();
				Color32[] pixels = val.GetPixels32();
				for (int i = 0; i < pixels.Length; i++)
				{
					Color32 val2 = pixels[i];
					if (val2.a != 0)
					{
						float num5 = (float)Mathf.Max((int)val2.r, Mathf.Max((int)val2.g, (int)val2.b)) / 255f;
						num5 = Mathf.Clamp01(0.2f + 0.8f * num5);
						pixels[i] = new Color32((byte)(tint.r * 255f * num5), (byte)(tint.g * 255f * num5), (byte)(tint.b * 255f * num5), val2.a);
					}
				}
				val.SetPixels32(pixels);
				val.Apply();
				return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), src.pixelsPerUnit, 0u, (SpriteMeshType)0);
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		private static int RecolorRenderers(GameObject root, Color tint)
		{
			//IL_0041: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = componentsInChildren[i].materials;
				foreach (Material val in materials)
				{
					if (!((Object)(object)val == (Object)null))
					{
						if (val.HasProperty("_Color"))
						{
							val.SetColor("_Color", tint);
							num++;
						}
						if (val.HasProperty("_EmissionColor"))
						{
							val.SetColor("_EmissionColor", tint * 0.35f);
						}
					}
				}
			}
			return num;
		}
	}
	internal static class VoidChestLocalization
	{
		internal const string ItemBlackMetal = "$item_voidchest_blackmetal";

		internal const string ItemBlackMetalDesc = "$item_voidchest_blackmetal_desc";

		internal const string ItemMagic = "$item_voidchest_magic";

		internal const string ItemMagicDesc = "$item_voidchest_magic_desc";

		internal const string ItemFlame = "$item_voidchest_flame";

		internal const string ItemFlameDesc = "$item_voidchest_flame_desc";

		internal const string ItemCrystal = "$item_voidchest_crystal";

		internal const string ItemCrystalDesc = "$item_voidchest_crystal_desc";

		internal const string StoreNearby = "$vc_store_nearby";

		internal const string StoreRemote = "$vc_store_remote";

		internal const string NearbyInProgress = "$vc_nearby_in_progress";

		internal const string NearbyNone = "$vc_nearby_none";

		internal const string NearbyStored = "$vc_nearby_stored";

		internal const string NearbyNothing = "$vc_nearby_nothing";

		internal const string NearbyRejected = "$vc_nearby_rejected";

		internal const string NearbyTimeout = "$vc_nearby_timeout";

		internal const string RemoteInProgress = "$vc_remote_in_progress";

		internal const string RemoteRequested = "$vc_remote_requested";

		internal const string RemoteServerMissing = "$vc_remote_server_missing";

		internal const string RemoteDisabled = "$vc_remote_disabled";

		internal const string RemoteNoGuardstone = "$vc_remote_no_guardstone";

		internal const string RemoteNoAccess = "$vc_remote_no_access";

		internal const string RemoteStored = "$vc_remote_stored";

		internal const string RemoteNothing = "$vc_remote_nothing";

		internal const string RemoteSkipped = "$vc_remote_skipped";

		private static readonly (string, string, string, string)[] Translations = new(string, string, string, string)[25]
		{
			("$item_voidchest_blackmetal", "Black Metal Void Chest", "黑金属虚空宝箱", "黑金屬虛空寶箱"),
			("$item_voidchest_blackmetal_desc", "A personal void container bound to your character - its contents follow you across worlds and servers. Equip it and press the hotkey to open. Supports nearby storage and guard-stone remote deposit. Capacity: 2x6 (configurable).", "角色绑定的个人虚空容器——匣中之物跨世界、跨服务器随身携带。装备后按热键打开;支持附近存储与守护石远程存入。容量:2×6(可配置)。", "角色綁定的個人虛空容器——匣中之物跨世界、跨伺服器隨身攜帶。裝備後按熱鍵打開;支援附近存儲與守護石遠端存入。容量:2×6(可配置)。"),
			("$item_voidchest_magic", "Eitr Void Chest", "魔能虚空宝箱", "魔能虛空寶箱"),
			("$item_voidchest_magic_desc", "A void chest infused with refined eitr - same character-bound storage, larger space. Equip it and press the hotkey to open. Supports nearby storage and guard-stone remote deposit. Capacity: 3x6 (configurable).", "铸入埃达精华的虚空宝箱——同样角色绑定,容量更大。装备后按热键打开;支持附近存储与守护石远程存入。容量:3×6(可配置)。", "鑄入埃達精華的虛空寶箱——同樣角色綁定,容量更大。裝備後按熱鍵打開;支援附近存儲與守護石遠端存入。容量:3×6(可配置)。"),
			("$item_voidchest_flame", "Flametal Void Chest", "烈焰虚空宝箱", "烈焰虛空寶箱"),
			("$item_voidchest_flame_desc", "A void chest tempered by the Emerald Flame - same character-bound storage, even larger space. Equip it and press the hotkey to open. Supports nearby storage and guard-stone remote deposit. Capacity: 3x8 (configurable).", "经青焰淬炼的虚空宝箱——同样角色绑定,容量更大。装备后按热键打开;支持附近存储与守护石远程存入。容量:3×8(可配置)。", "經青焰淬鍊的虛空寶箱——同樣角色綁定,容量更大。裝備後按熱鍵打開;支援附近存儲與守護石遠端存入。容量:3×8(可配置)。"),
			("$item_voidchest_crystal", "Crystal Void Chest", "水晶虚空宝箱", "水晶虛空寶箱"),
			("$item_voidchest_crystal_desc", "The final void chest, born of blood-gold and liquid frost - the largest character-bound storage. Equip it and press the hotkey to open. Supports nearby storage and guard-stone remote deposit. Capacity: 4x8 (configurable).", "霜与血的造物、终极虚空宝箱——角色绑定的最大容量。装备后按热键打开;支持附近存储与守护石远程存入。容量:4×8(可配置)。", "霜與血的造物、終極虛空寶箱——角色綁定的最大容量。裝備後按熱鍵打開;支援附近存儲與守護石遠端存入。容量:4×8(可配置)。"),
			("$vc_store_nearby", "Nearby Storage", "附近存储", "附近存儲"),
			("$vc_store_remote", "Remote Deposit", "远程存入", "遠端存入"),
			("$vc_nearby_in_progress", "Nearby storage is in progress, please try again later.", "附近存储正在进行中,请稍后再试。", "附近儲存正在進行中,請稍後再試。"),
			("$vc_nearby_none", "No containers nearby to store into.", "附近没有可存储的箱子。", "附近沒有可儲存的箱子。"),
			("$vc_nearby_stored", "Stored {0} items into {1} containers", "已存入 {0} 件物品到 {1} 个箱子", "已存入 {0} 件物品到 {1} 個箱子"),
			("$vc_nearby_nothing", "Nothing to store (scanned {0} containers)", "没有可存入的物品(扫描 {0} 个箱子)", "沒有可存入的物品(掃描 {0} 個箱子)"),
			("$vc_nearby_rejected", "({0} in use / rejected)", "({0} 个使用中/被拒绝)", "({0} 個使用中/被拒絕)"),
			("$vc_nearby_timeout", "({0} timed out)", "({0} 个超时)", "({0} 個超時)"),
			("$vc_remote_in_progress", "Remote deposit is already in progress...", "远程存入正在进行中...", "遠端存入正在進行中..."),
			("$vc_remote_requested", "Remote deposit request sent, waiting for the server...", "已向服务器发送远程存入请求,正在等待处理...", "已向伺服器發送遠端存入請求,正在等待處理..."),
			("$vc_remote_server_missing", "No response from the server: remote deposit requires the mod on the server.", "服务器未响应:远程存入需要服务端也安装本 mod。", "伺服器未回應:遠端存入需要伺服器也安裝本 mod。"),
			("$vc_remote_disabled", "Remote deposit is disabled on the server.", "服务器已禁用远程存入。", "伺服器已停用遠端存入。"),
			("$vc_remote_no_guardstone", "No guard stone found in the world.", "世界中未找到守护石。", "世界中未找到守護石。"),
			("$vc_remote_no_access", "You have access to no guard stone.", "没有找到你有权限的守护石", "沒有找到你有權限的守護石"),
			("$vc_remote_stored", "Deposited {0} items into your home containers ({1} containers)", "已远程存入 {0} 件物品到家的箱子({1} 个箱子)", "已遠端存入 {0} 件物品到家的箱子({1} 個箱子)"),
			("$vc_remote_nothing", "Nothing to deposit (scanned {0} containers)", "没有可远程存入的物品(扫描 {0} 个箱子)", "沒有可遠端存入的物品(掃描 {0} 個箱子)"),
			("$vc_remote_skipped", "({0} in use / invalid skipped)", "(跳过 {0} 个使用中/无效箱子)", "(跳過 {0} 個使用中/無效箱子)")
		};

		internal static void Register()
		{
			try
			{
				CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
				(string, string, string, string)[] translations = Translations;
				for (int i = 0; i < translations.Length; i++)
				{
					(string, string, string, string) tuple = translations[i];
					string text = "English";
					localization.AddTranslation(ref text, ref tuple.Item1, tuple.Item2);
					text = "Chinese";
					localization.AddTranslation(ref text, ref tuple.Item1, tuple.Item3);
					text = "Chinese_Trad";
					localization.AddTranslation(ref text, ref tuple.Item1, tuple.Item4);
				}
				VLog.Info($"本地化已注册:{Translations.Length} 个条目 × 3 种语言(English/Chinese/Chinese_Trad)。");
			}
			catch (Exception e)
			{
				VLog.Error("本地化注册失败: ", e);
			}
		}

		internal static string L(string token)
		{
			Localization instance = Localization.instance;
			if (instance == null)
			{
				return token;
			}
			return instance.Localize(token);
		}

		internal static string L(string token, params object[] args)
		{
			string text = L(token);
			if (args == null)
			{
				return text;
			}
			for (int i = 0; i < args.Length; i++)
			{
				text = text.Replace("{" + i + "}", (args[i] != null) ? args[i].ToString() : "");
			}
			return text;
		}
	}
	internal static class VoidChestManager
	{
		internal const string PrefabPrefix = "VoidChest";

		internal static readonly FieldRef<InventoryGui, Container> CurrentContainerRef = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

		private static VirtualContainer _container;

		private static ItemData _openItem;

		internal static VirtualContainer CurrentContainer => _container;

		internal static Container CurrentOpenedContainer(InventoryGui gui)
		{
			if (!((Object)(object)gui != (Object)null))
			{
				return null;
			}
			return CurrentContainerRef.Invoke(gui);
		}

		internal static void Toggle(Player player)
		{
			if ((Object)(object)InventoryGui.instance == (Object)null)
			{
				return;
			}
			bool flag = InventoryGui.instance.IsContainerOpen();
			bool flag2 = flag && IsVoidChestOpen();
			VLog.Debug($"Toggle: containerOpen={flag}, isOurContainer={flag2}");
			if (flag)
			{
				if (flag2)
				{
					InventoryGui.instance.Hide();
					VLog.Info("关闭虚空宝箱界面。");
				}
			}
			else
			{
				ItemData equippedChest = GetEquippedChest(player);
				if (equippedChest == null)
				{
					VLog.Debug("未装备虚空宝箱,无法打开。");
				}
				else
				{
					Open(player, equippedChest);
				}
			}
		}

		internal static bool IsVoidChestOpen()
		{
			if ((Object)(object)InventoryGui.instance != (Object)null)
			{
				return CurrentContainerRef.Invoke(InventoryGui.instance) is VirtualContainer;
			}
			return false;
		}

		internal static ItemData GetEquippedChest(Player player)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory != null)
			{
				foreach (ItemData equippedItem in inventory.GetEquippedItems())
				{
					if (IsVoidChestItem(equippedItem))
					{
						VLog.Debug("原版装备槽检测到虚空宝箱: prefab=" + ((Object)equippedItem.m_dropPrefab).name + ", name=" + equippedItem.m_shared.m_name);
						return equippedItem;
					}
				}
			}
			List<ItemData> equippedItems = ExtraSlotsCompat.GetEquippedItems((Humanoid)(object)player);
			if (equippedItems != null)
			{
				foreach (ItemData item in equippedItems)
				{
					if (IsVoidChestItem(item))
					{
						VLog.Debug("ExtraSlots 额外槽检测到虚空宝箱: prefab=" + ((Object)item.m_dropPrefab).name + ", name=" + item.m_shared.m_name);
						return item;
					}
				}
			}
			return null;
		}

		private static bool IsVoidChestItem(ItemData item)
		{
			if ((Object)(object)item?.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name.StartsWith("VoidChest");
			}
			return false;
		}

		private static VirtualContainer EnsureContainer(Player player)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_container != (Object)null)
			{
				return _container;
			}
			GameObject val = new GameObject("VoidChest_VirtualContainer");
			val.transform.SetParent(((Component)player).transform, false);
			val.transform.localPosition = Vector3.zero;
			_container = val.AddComponent<VirtualContainer>();
			VLog.Info("虚拟容器已创建。");
			return _container;
		}

		internal static void Open(Player player, ItemData item)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			VirtualContainer virtualContainer = EnsureContainer(player);
			(int, int) size = GetSize(item);
			string text = (((Container)virtualContainer).m_name = item.m_shared.m_name);
			((Container)virtualContainer).m_width = size.Item2;
			((Container)virtualContainer).m_height = size.Item1;
			virtualContainer.MaxWeight = GetMaxWeight(item);
			Inventory val = new Inventory(text, (Sprite)null, size.Item2, size.Item1);
			virtualContainer.SuppressSave = true;
			int num;
			try
			{
				virtualContainer.SetInventory(val);
				VoidChestSave.LoadInto(val, player);
				num = val.NrOfItems();
			}
			finally
			{
				virtualContainer.SuppressSave = false;
			}
			_openItem = item;
			InventoryGui.instance.Show((Container)(object)virtualContainer, 1);
			VLog.Info($"打开虚空宝箱: {text} ({size.Item1}行x{size.Item2}列),加载 {num} 件物品。");
		}

		internal static (int rows, int cols) GetSize(ItemData item)
		{
			return (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "") switch
			{
				"VoidChestMagic" => (rows: VoidChestPlugin.CapacityMagicRows.Value, cols: VoidChestPlugin.CapacityMagicCols.Value), 
				"VoidChestFlame" => (rows: VoidChestPlugin.CapacityFlameRows.Value, cols: VoidChestPlugin.CapacityFlameCols.Value), 
				"VoidChestCrystal" => (rows: VoidChestPlugin.CapacityCrystalRows.Value, cols: VoidChestPlugin.CapacityCrystalCols.Value), 
				_ => (rows: VoidChestPlugin.CapacityBlackMetalRows.Value, cols: VoidChestPlugin.CapacityBlackMetalCols.Value), 
			};
		}

		internal static float GetMaxWeight(ItemData item)
		{
			return (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "") switch
			{
				"VoidChestMagic" => VoidChestPlugin.WeightMagic.Value, 
				"VoidChestFlame" => VoidChestPlugin.WeightFlame.Value, 
				"VoidChestCrystal" => VoidChestPlugin.WeightCrystal.Value, 
				_ => VoidChestPlugin.WeightBlackMetal.Value, 
			};
		}

		internal static int GetTier(ItemData item)
		{
			return (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "") switch
			{
				"VoidChestMagic" => 2, 
				"VoidChestFlame" => 3, 
				"VoidChestCrystal" => 4, 
				_ => 1, 
			};
		}

		internal static bool CanUseRemote(Player player)
		{
			if (VoidChestPlugin.EnableRemoteStore == null || !VoidChestPlugin.EnableRemoteStore.Value)
			{
				return false;
			}
			if (VoidChestPlugin.RemoteStoreAlwaysAvailable != null && VoidChestPlugin.RemoteStoreAlwaysAvailable.Value)
			{
				return true;
			}
			ItemData equippedChest = GetEquippedChest(player);
			if (equippedChest != null)
			{
				return GetTier(equippedChest) >= 2;
			}
			return false;
		}

		internal static void FlushActive(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)_container == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				Inventory inventory = ((Container)_container).GetInventory();
				if (inventory != null)
				{
					VLog.Debug($"Player.Save 触发 flush,当前库存 {inventory.NrOfItems()} 件。");
					VoidChestSave.SaveFrom(inventory, player);
				}
			}
		}

		internal static void Message(Player player, string text)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)MessageHud.instance == (Object)null))
			{
				((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class VoidChestNearbyStore
	{
		private static readonly List<Container> _queue = new List<Container>();

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

		private static readonly FieldRef<Container, ZNetView> NViewRef = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

		private static bool _running;

		private static Container _current;

		private static float _waitTimer;

		private static int _beforeCount;

		private static int _processed;

		private static int _timedOut;

		private static int _rejected;

		private static float _currentSentAt;

		internal static bool FilterActive { get; private set; }

		internal static bool IsRunning => _running;

		internal static void Start(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			if (_running || VoidChestRemoteStore.IsRunning)
			{
				VoidChestManager.Message(player, VoidChestLocalization.L("$vc_nearby_in_progress"));
				return;
			}
			List<Container> list = FindContainers(player);
			if (list.Count == 0)
			{
				VoidChestManager.Message(player, VoidChestLocalization.L("$vc_nearby_none"));
				VLog.Info("附近存储:未找到可用容器。");
				return;
			}
			_queue.Clear();
			_queue.AddRange(list);
			_beforeCount = ((Humanoid)player).GetInventory().CountItems((string)null, -1, true);
			_processed = 0;
			_timedOut = 0;
			_rejected = 0;
			_running = true;
			FilterActive = true;
			_waitTimer = 0f;
			_current = null;
			VoidChestPerf.Reset();
			VLog.Info($"附近存储开始:{list.Count} 个容器,背包物品 {_beforeCount}。");
			SendNext();
		}

		internal static void Update()
		{
			if (!_running)
			{
				return;
			}
			float num = Time.realtimeSinceStartup + 0.008f;
			while (true)
			{
				if ((Object)(object)_current == (Object)null)
				{
					if (_queue.Count == 0)
					{
						Finish();
						break;
					}
					SendNext();
					if ((Object)(object)_current != (Object)null || Time.realtimeSinceStartup >= num)
					{
						break;
					}
				}
				else
				{
					_waitTimer += Time.deltaTime;
					if (!(_waitTimer > Timeout()))
					{
						break;
					}
					VLog.Warn("附近存储:" + ((Object)((Component)_current).gameObject).name + " 响应超时,跳过。");
					_timedOut++;
					_current = null;
				}
			}
		}

		internal static void OnStackResponse(bool granted)
		{
			if (_running && !((Object)(object)_current == (Object)null))
			{
				VoidChestPerf.NoteStep((double)(Time.realtimeSinceStartup - _currentSentAt) * 1000.0);
				_processed++;
				if (!granted)
				{
					_rejected++;
					VLog.Debug("附近存储:" + ((Object)((Component)_current).gameObject).name + " 被拒绝(使用中/无权限)。");
				}
				_current = null;
			}
		}

		private static void SendNext()
		{
			if (!_running)
			{
				return;
			}
			if (_queue.Count == 0)
			{
				Finish();
				return;
			}
			_current = _queue[0];
			_queue.RemoveAt(0);
			_waitTimer = 0f;
			_currentSentAt = Time.realtimeSinceStartup;
			try
			{
				VLog.Debug("附近存储:请求 " + ((Object)((Component)_current).gameObject).name + " (" + _current.m_name + ")");
				_current.StackAll();
			}
			catch (Exception ex)
			{
				VLog.Warn("附近存储:请求失败 " + (((Object)(object)_current != (Object)null) ? ((Object)((Component)_current).gameObject).name : "?") + ": " + ex.Message);
				_timedOut++;
				_current = null;
			}
		}

		private static void Finish()
		{
			_running = false;
			_current = null;
			FilterActive = false;
			Player localPlayer = Player.m_localPlayer;
			int num = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory().CountItems((string)null, -1, true) : _beforeCount);
			int num2 = _beforeCount - num;
			string text = ((num2 > 0) ? VoidChestLocalization.L("$vc_nearby_stored", num2, _processed) : ((_processed <= 0) ? VoidChestLocalization.L("$vc_nearby_none") : VoidChestLocalization.L("$vc_nearby_nothing", _processed)));
			if (_rejected > 0)
			{
				text += VoidChestLocalization.L("$vc_nearby_rejected", _rejected);
			}
			if (_timedOut > 0)
			{
				text += VoidChestLocalization.L("$vc_nearby_timeout", _timedOut);
			}
			if ((Object)(object)localPlayer != (Object)null)
			{
				VoidChestManager.Message(localPlayer, text);
			}
			VLog.Info($"附近存储完成:移动 {num2} 件,容器 {_processed},拒绝 {_rejected},超时 {_timedOut}。");
			VLog.Info(VoidChestPerf.Summary("附近存储", num2, _processed, _rejected, _timedOut));
		}

		private static List<Container> FindContainers(Player player)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			Stopwatch stopwatch = Stopwatch.StartNew();
			_seen.Clear();
			List<Container> list = new List<Container>();
			int mask = LayerMask.GetMask(new string[3] { "piece", "item", "vehicle" });
			Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, VoidChestPlugin.NearbyStoreRange.Value, mask);
			VLog.Debug($"附近存储:OverlapSphere 命中 {array.Length} 个碰撞体,半径 {VoidChestPlugin.NearbyStoreRange.Value}。");
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Container componentInParent = ((Component)val).GetComponentInParent<Container>();
				if (!((Object)(object)componentInParent == (Object)null) && !(componentInParent is VirtualContainer) && !_seen.Contains(componentInParent) && componentInParent.GetInventory() != null)
				{
					if (IsContainerBusy(componentInParent, out var reason))
					{
						VLog.Debug("附近存储:跳过容器 " + ((Object)((Component)componentInParent).gameObject).name + "(" + reason + ")");
					}
					else if (VoidChestPlugin.NearbyStoreCheckWard.Value && !PrivateArea.CheckAccess(((Component)val).transform.position, 0f, false, false))
					{
						VLog.Debug("附近存储:跳过无权限容器 " + ((Object)((Component)componentInParent).gameObject).name);
					}
					else
					{
						_seen.Add(componentInParent);
						list.Add(componentInParent);
					}
				}
			}
			list.Sort((Container a, Container b) => Vector3.Distance(((Component)player).transform.position, ((Component)a).transform.position).CompareTo(Vector3.Distance(((Component)player).transform.position, ((Component)b).transform.position)));
			stopwatch.Stop();
			VoidChestPerf.AddScan(stopwatch.Elapsed.TotalMilliseconds);
			return list;
		}

		private static bool IsContainerBusy(Container container, out string reason)
		{
			reason = null;
			if (container.IsInUse())
			{
				reason = "本地使用中";
				return true;
			}
			try
			{
				ZNetView val = NViewRef.Invoke(container);
				ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null);
				if (val2 != null && val2.GetInt(ZDOVars.s_inUse, 0) == 1)
				{
					reason = "其他玩家使用中(ZDO)";
					return true;
				}
			}
			catch (Exception ex)
			{
				VLog.Debug("ZDO 占用检查失败: " + ex.Message);
			}
			return false;
		}

		private static float Timeout()
		{
			return Mathf.Max(0.2f, VoidChestPlugin.NearbyStoreTimeout.Value);
		}
	}
	internal static class VoidChestPerf
	{
		internal const float FrameBudgetSeconds = 0.008f;

		internal static float StartRealtime;

		internal static float ScanMs;

		internal static int ScanBatches;

		internal static float ClassifyMs;

		internal static float FilterMs;

		internal static int StackCalls;

		internal static double StackMs;

		internal static float MaxStepMs;

		internal static int DataWriteCount;

		internal static double DataWriteMs;

		internal static void Reset()
		{
			StartRealtime = Time.realtimeSinceStartup;
			ScanMs = 0f;
			ScanBatches = 0;
			ClassifyMs = 0f;
			FilterMs = 0f;
			StackCalls = 0;
			StackMs = 0.0;
			MaxStepMs = 0f;
			DataWriteCount = 0;
			DataWriteMs = 0.0;
		}

		internal static void AddScan(double ms)
		{
			ScanMs += (float)ms;
			ScanBatches++;
		}

		internal static void AddClassify(double ms)
		{
			ClassifyMs += (float)ms;
		}

		internal static void AddFilter(double ms)
		{
			FilterMs += (float)ms;
		}

		internal static void AddStack(double ms)
		{
			StackCalls++;
			StackMs += ms;
		}

		internal static void AddDataWrite(double ms)
		{
			DataWriteCount++;
			DataWriteMs += ms;
		}

		internal static void NoteStep(double ms)
		{
			if (ms > (double)MaxStepMs)
			{
				MaxStepMs = (float)ms;
			}
		}

		internal static double TotalMs()
		{
			return (double)(Time.realtimeSinceStartup - StartRealtime) * 1000.0;
		}

		internal static string Summary(string tag, int moved, int containers, int rejected, int skipped)
		{
			return $"{tag}性能:总耗时 {TotalMs():F0}ms | 快照 {ScanMs:F1}ms({ScanBatches}批) | 分类 {ClassifyMs:F1}ms | 筛选 {FilterMs:F1}ms | 容器 {containers}(拒绝{rejected}/跳过{skipped}) | 堆叠 {StackCalls} 次 {StackMs:F1}ms | 最长步骤 {MaxStepMs:F0}ms | 数据写入 {DataWriteCount} 次 {DataWriteMs:F1}ms | 移动 {moved} 件";
		}
	}
	internal static class VoidChestRemoteNet
	{
		internal enum Status
		{
			Ok,
			Busy,
			NoGuardstone,
			NoAccess,
			Disabled,
			Invalid
		}

		internal const string RequestRpc = "VoidChest_RemoteDepositRequest";

		internal const string ResultRpc = "VoidChest_RemoteDepositResult";

		private const int ProtocolVersion = 1;

		private const float ResponseTimeout = 30f;

		private static ZRoutedRpc _registeredOn;

		private static bool _pending;

		private static long _activeSeq;

		private static float _sentAt;

		private static bool _timeoutWarned;

		internal static void Update()
		{
			EnsureRegistered();
			if (!_pending || Time.realtimeSinceStartup - _sentAt < 30f)
			{
				return;
			}
			_pending = false;
			if (!_timeoutWarned)
			{
				_timeoutWarned = true;
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					VoidChestManager.Message(localPlayer, BuildStatusMessage(Status.Invalid, 0, 0, 0));
				}
				VLog.Warn($"远程存入:等待服务端响应超过 {30f:F0} 秒(服务端可能未安装本 mod)。");
			}
		}

		private static void EnsureRegistered()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null || _registeredOn == instance)
			{
				return;
			}
			try
			{
				instance.Register<ZPackage>("VoidChest_RemoteDepositRequest", (Action<long, ZPackage>)OnRequest);
				instance.Register<ZPackage>("VoidChest_RemoteDepositResult", (Action<long, ZPackage>)OnResult);
				_registeredOn = instance;
				_pending = false;
				_timeoutWarned = false;
				VLog.Info("远程存入 RPC 已注册。");
			}
			catch (Exception e)
			{
				_registeredOn = instance;
				VLog.Error("远程存入 RPC 注册失败: ", e);
			}
		}

		internal static string BuildStatusMessage(Status status, int moved, int processed, int skipped)
		{
			string text;
			switch (status)
			{
			case Status.Ok:
				text = ((moved > 0) ? VoidChestLocalization.L("$vc_remote_stored", moved, processed) : VoidChestLocalization.L("$vc_remote_nothing", processed));
				if (skipped > 0)
				{
					text += VoidChestLocalization.L("$vc_remote_skipped", skipped);
				}
				break;
			case Status.Busy:
				text = VoidChestLocalization.L("$vc_remote_in_progress");
				break;
			case Status.NoGuardstone:
				text = VoidChestLocalization.L("$vc_remote_no_guardstone");
				break;
			case Status.NoAccess:
				text = VoidChestLocalization.L("$vc_remote_no_access");
				break;
			case Status.Disabled:
				text = VoidChestLocalization.L("$vc_remote_disabled");
				break;
			default:
				text = VoidChestLocalization.L("$vc_remote_server_missing");
				break;
			}
			return text;
		}

		internal static void RequestRemote(Player player)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			if (_pending)
			{
				VoidChestManager.Message(player, VoidChestLocalization.L("$vc_remote_in_progress"));
				return;
			}
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null)
			{
				VoidChestManager.Message(player, BuildStatusMessage(Status.Invalid, 0, 0, 0));
				return;
			}
			Inventory val;
			try
			{
				val = BuildFilteredSnapshot(player);
			}
			catch (Exception e)
			{
				VLog.Error("远程存入:构建背包快照失败: ", e);
				VoidChestManager.Message(player, BuildStatusMessage(Status.Invalid, 0, 0, 0));
				return;
			}
			long num = ++_activeSeq;
			_pending = true;
			_timeoutWarned = false;
			_sentAt = Time.realtimeSinceStartup;
			try
			{
				ZPackage val2 = new ZPackage();
				val.Save(val2);
				ZPackage val3 = new ZPackage();
				val3.Write(player.GetPlayerID());
				val3.Write(num);
				val3.Write(1);
				val3.Write(val.GetWidth());
				val3.Write(val.GetHeight());
				val3.Write(val2.GetArray());
				instance.InvokeRoutedRPC("VoidChest_RemoteDepositRequest", new object[1] { val3 });
				VoidChestManager.Message(player, VoidChestLocalization.L("$vc_remote_requested"));
				VLog.Info($"远程存入:已向服务端发送请求 #{num}(玩家 {player.GetPlayerID()},物品 {val.NrOfItems()} 件,背包数据 {val2.GetArray().Length} 字节)。");
			}
			catch (Exception e2)
			{
				_pending = false;
				VLog.Error("远程存入:发送请求失败: ", e2);
				VoidChestManager.Message(player, BuildStatusMessage(Status.Invalid, 0, 0, 0));
			}
		}

		private static Inventory BuildFilteredSnapshot(Player player)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			Inventory inventory = ((Humanoid)player).GetInventory();
			int num = Mathf.Clamp(inventory.GetWidth(), 1, 64);
			int num2 = Mathf.Clamp(inventory.GetHeight(), 1, 64);
			Inventory val = new Inventory("VoidChestRemoteDeposit", (Sprite)null, num, num2);
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem != null && allItem.m_shared != null && !((Humanoid)player).IsItemEquiped(allItem) && !VoidChestFilter.ShouldSkip(allItem))
				{
					val.AddItem(allItem.Clone());
				}
			}
			return val;
		}

		private static void OnResult(long sender, ZPackage payload)
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				return;
			}
			long num;
			Status status;
			int num2;
			int num3;
			int num4;
			try
			{
				num = payload.ReadLong();
				status = (Status)payload.ReadInt();
				num2 = payload.ReadInt();
				num3 = payload.ReadInt();
				num4 = payload.ReadInt();
			}
			catch (Exception e)
			{
				VLog.Error("远程存入:解析服务端结果头失败: ", e);
				return;
			}
			if (num != _activeSeq)
			{
				VLog.Info($"远程存入:忽略过期的服务端结果 #{num}(当前 #{_activeSeq})。");
				return;
			}
			_pending = false;
			_timeoutWarned = false;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (status == Status.Ok)
			{
				try
				{
					int num5 = ApplyMovedItems(localPlayer, payload);
					VLog.Info($"远程存入:服务端结果 #{num} 移动 {num2} 堆叠,本地扣除 {num5} 件。");
				}
				catch (Exception e2)
				{
					VLog.Error("远程存入:应用服务端结果失败: ", e2);
				}
			}
			VoidChestManager.Message(localPlayer, BuildStatusMessage(status, num2, num3, num4));
			VLog.Info($"远程存入:服务端结果 #{num} status={status} 移动={num2} 箱子={num3} 跳过={num4}。");
		}

		private static int ApplyMovedItems(Player player, ZPackage payload)
		{
			int num = payload.ReadInt();
			if (num <= 0)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> list = new List<ItemData>(inventory.GetAllItems());
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				string b = payload.ReadString();
				int num3 = payload.ReadInt();
				if (num3 <= 0)
				{
					continue;
				}
				int num4 = num3;
				foreach (ItemData item in list)
				{
					if (num4 <= 0)
					{
						break;
					}
					if (item != null && item.m_shared != null && item.m_stack > 0 && string.Equals(VoidChestItemIdentity.Of(item), b, StringComparison.Ordinal))
					{
						int num5 = Mathf.Min(num4, item.m_stack);
						inventory.RemoveItem(item, num5);
						num4 -= num5;
						num2 += num5;
					}
				}
				if (num4 > 0)
				{
					VLog.Warn($"远程存入:本地背包未找到可扣除的物品(还差 {num4} 件,物品可能已被移动/消耗)。");
				}
			}
			return num2;
		}

		private static void OnRequest(long sender, ZPackage payload)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				long num = payload.ReadLong();
				long seq = payload.ReadLong();
				int num2 = payload.ReadInt();
				int num3 = Mathf.Clamp(payload.ReadInt(), 1, 64);
				int num4 = Mathf.Clamp(payload.ReadInt(), 1, 64);
				byte[] array = payload.ReadByteArray();
				if (num2 != 1 || num == 0L || array == null || array.Length == 0)
				{
					SendResult(sender, seq, Status.Invalid, 0, 0, 0, null);
					return;
				}
				if (!VoidChestPlugin.EnableRemoteStore.Value)
				{
					SendResult(sender, seq, Status.Disabled, 0, 0, 0, null);
					return;
				}
				Inventory val = new Inventory("VoidChestRemoteRequest", (Sprite)null, num3, num4);
				val.Load(new ZPackage(array));
				VoidChestRemoteStore.StartRemoteJob(sender, seq, num, val);
			}
			catch (Exception ex)
			{
				VLog.Warn("远程存入:处理服务端请求失败: " + ex.Message);
			}
		}

		internal static void SendResult(long peer, long seq, Status status, int moved, int processed, int skipped, List<KeyValuePair<string, int>> movedEntries)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null || peer == 0L)
			{
				return;
			}
			try
			{
				ZPackage val = new ZPackage();
				val.Write(seq);
				val.Write((int)status);
				val.Write(moved);
				val.Write(processed);
				val.Write(skipped);
				int num = movedEntries?.Count ?? 0;
				val.Write(num);
				for (int i = 0; i < num; i++)
				{
					val.Write(movedEntries[i].Key);
					val.Write(movedEntries[i].Value);
				}
				instance.InvokeRoutedRPC(peer, "VoidChest_RemoteDepositResult", new object[1] { val });
			}
			catch (Exception ex)
			{
				VLog.Warn($"远程存入:发送结果到 {peer} 失败: {ex.Message}");
			}
		}
	}
	internal static class VoidChestRemoteStore
	{
		private enum Phase
		{
			Idle,
			FullScan,
			ChestFilter,
			Guards,
			Chests,
			Stacking
		}

		private struct GuardInfo
		{
			public Vector3 Pos;

			public float Radius;
		}

		private struct SnapshotEntry
		{
			public ZDOID Id;

			public int Prefab;
		}

		private static Phase _phase = Phase.Idle;

		private static Player _player;

		private static long _playerId;

		private static Inventory _targetInv;

		private static bool _preFiltered;

		private static long _responsePeer;

		private static long _responseSeq;

		private static Dictionary<string, int> _initialTotals;

		private static bool _objectsByIdInit;

		private static FieldRef<ZDOMan, Dictionary<ZDOID, ZDO>> _objectsByIdRef;

		private static List<SnapshotEntry> _snapshot;

		private static int _cursor;

		private static readonly List<ZDOID> _chestCandidates = new List<ZDOID>();

		private static int _candidateCursor;

		private static readonly Dictionary<int, byte> _prefabKind = new Dictionary<int, byte>();

		private static List<string> _prefabNames = new List<string>();

		private static int _prefabIndex;

		private static readonly List<ZDO> _found = new List<ZDO>();

		private static int _iter;

		private static readonly List<GuardInfo> _guards = new List<GuardInfo>();

		private static readonly List<ZDOID> _guardIds = new List<ZDOID>();

		private static readonly List<ZDOID> _chests = new List<ZDOID>();

		private static readonly HashSet<ZDOID> _chestSeen = new HashSet<ZDOID>();

		private static int _chestIndex;

		private static int _moved;

		private static int _processed;

		private static int _skipped;

		private static float _cacheTime = -99999f;

		private static long _cachePlayerId;

		private static readonly List<ZDOID> _cachedGuardIds = new List<ZDOID>();

		private static readonly List<ZDOID> _cachedChestIds = new List<ZDOID>();

		private static readonly Dictionary<int, float> _guardRadiusCache = new Dictionary<int, float>();

		private static readonly Dictionary<int, Vector2i> _containerSizeCache = new Dictionary<int, Vector2i>();

		internal static bool IsRunning => _phase != Phase.Idle;

		internal static void Start(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				if (_phase != Phase.Idle)
				{
					VoidChestManager.Message(player, VoidChestLocalization.L("$vc_remote_in_progress"));
					VLog.Info("远程存入:已有流程进行中,忽略本次点击。");
				}
				else if (VoidChestNearbyStore.IsRunning)
				{
					VoidChestManager.Message(player, VoidChestLocalization.L("$vc_nearby_in_progress"));
				}
				else if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
				{
					VoidChestRemoteNet.RequestRemote(player);
				}
				else
				{
					BeginJob(0L, 0L, player.GetPlayerID(), ((Humanoid)player).GetInventory(), preFiltered: false, player);
				}
			}
		}

		internal static void StartRemoteJob(long peer, long seq, long playerId, Inventory snapshot)
		{
			if (peer != 0L && snapshot != null)
			{
				if (_phase != Phase.Idle)
				{
					VoidChestRemoteNet.SendResult(peer, seq, VoidChestRemoteNet.Status.Busy, 0, 0, 0, null);
					VLog.Info("远程存入:服务端已有任务在运行,拒绝客户端请求。");
				}
				else
				{
					BeginJob(peer, seq, playerId, snapshot, preFiltered: true, null);
				}
			}
		}

		private static void BeginJob(long peer, long seq, long playerId, Inventory targetInv, bool preFiltered, Player localPlayer)
		{
			_responsePeer = peer;
			_responseSeq = seq;
			_playerId = playerId;
			_targetInv = targetInv;
			_preFiltered = preFiltered;
			_player = localPlayer;
			_initialTotals = (preFiltered ? VoidChestItemIdentity.Totals(targetInv) : null);
			_guards.Clear();
			_guardIds.Clear();
			_chests.Clear();
			_chestSeen.Clear();
			_chestCandidates.Clear();
			_found.Clear();
			_moved = 0;
			_processed = 0;
			_skipped = 0;
			_chestIndex = 0;
			_candidateCursor = 0;
			VoidChestPerf.Reset();
			if (TryUseCache())
			{
				_phase = Phase.Stacking;
				VLog.Info($"远程存入开始:缓存命中(守护石 {_guards.Count},箱子 {_chests.Count})。");
				return;
			}
			if (EnsureObjectsByIdRef())
			{
				_snapshot = SnapshotZdos();
				_cursor = 0;
				_phase = Phase.FullScan;
				VLog.Info($"远程存入开始:全量快照 {((_snapshot != null) ? _snapshot.Count : 0)} 个 ZDO(玩家 ID {_playerId})。");
				return;
			}
			List<string> list = CollectPrefabs((GameObject go) => (Object)(object)go.GetComponent<PrivateArea>() != (Object)null);
			if (list.Count == 0)
			{
				Finish(VoidChestRemoteNet.Status.NoGuardstone);
				VLog.Info("远程存入:未找到守护石 prefab。");
				return;
			}
			_prefabNames = list;
			_prefabIndex = 0;
			_iter = 0;
			_phase = Phase.Guards;
			VLog.Info($"远程存入开始:降级 prefab 扫描模式(守护石 prefab {list.Count} 种,玩家 ID {_playerId})。");
		}

		internal static void Update()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if (_phase == Phase.Idle)
			{
				return;
			}
			float num = Time.realtimeSinceStartup + 0.008f;
			if (_phase == Phase.FullScan)
			{
				UpdateFullScan(num);
			}
			else if (_phase == Phase.ChestFilter)
			{
				UpdateChestFilter(num);
			}
			else if (_phase == Phase.Guards)
			{
				UpdateGuards(num);
			}
			else if (_phase == Phase.Chests)
			{
				UpdateChests(num);
			}
			else
			{
				if (_phase != Phase.Stacking)
				{
					return;
				}
				while (Time.realtimeSinceStartup < num)
				{
					if (_chestIndex >= _chests.Count)
					{
						Finish(VoidChestRemoteNet.Status.Ok);
						break;
					}
					ProcessChest(_chests[_chestIndex++]);
				}
			}
		}

		private static bool EnsureObjectsByIdRef()
		{
			if (_objectsByIdInit)
			{
				return _objectsByIdRef != null;
			}
			_objectsByIdInit = true;
			try
			{
				_objectsByIdRef = AccessTools.FieldRefAccess<ZDOMan, Dictionary<ZDOID, ZDO>>("m_objectsByID");
			}
			catch (Exception ex)
			{
				_objectsByIdRef = null;
				VLog.Warn("ZDOMan.m_objectsByID 反射失败,降级为 prefab 扫描模式: " + ex.Message);
			}
			return _objectsByIdRef != null;
		}

		private static List<SnapshotEntry> SnapshotZdos()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Stopwatch stopwatch = Stopwatch.StartNew();
			Dictionary<ZDOID, ZDO> obj = _objectsByIdRef.Invoke(ZDOMan.instance);
			List<SnapshotEntry> list = new List<SnapshotEntry>(obj.Count);
			foreach (KeyValuePair<ZDOID, ZDO> item in obj)
			{
				ZDO value = item.Value;
				if (value != null)
				{
					list.Add(new SnapshotEntry
					{
						Id = item.Key,
						Prefab = value.GetPrefab()
					});
				}
			}
			stopwatch.Stop();
			VoidChestPerf.AddScan(stopwatch.Elapsed.TotalMilliseconds);
			return list;
		}

		private static void UpdateFullScan(float budgetEnd)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (_snapshot == null)
			{
				_phase = Phase.ChestFilter;
				return;
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			int num = 0;
			while (_cursor < _snapshot.Count)
			{
				SnapshotEntry snapshotEntry = _snapshot[_cursor++];
				num++;
				byte b;
				try
				{
					b = ClassifyPrefab(snapshotEntry.Prefab);
				}
				catch
				{
					b = 0;
				}
				switch (b)
				{
				case 1:
				{
					ZDO zDO = ZDOMan.instance.GetZDO(snapshotEntry.Id);
					if (zDO != null && HasAccess(zDO))
					{
						_guards.Add(new GuardInfo
						{
							Pos = zDO.GetPosition(),
							Radius = GetGuardRadius(snapshotEntry.Prefab)
						});
						_guardIds.Add(snapshotEntry.Id);
					}
					break;
				}
				case 2:
					_chestCandidates.Add(snapshotEntry.Id);
					break;
				}
				if ((num & 0x3FF) == 0 && Time.realtimeSinceStartup >= budgetEnd)
				{
					break;
				}
			}
			stopwatch.Stop();
			VoidChestPerf.AddClassify(stopwatch.Elapsed.TotalMilliseconds);
			if (_cursor >= _snapshot.Count)
			{
				_snapshot = null;
				if (_guards.Count == 0)
				{
					Finish(VoidChestRemoteNet.Status.NoAccess);
					return;
				}
				_candidateCursor = 0;
				_phase = Phase.ChestFilter;
				VLog.Info($"远程存入:快照分类完成,守护石 {_guards.Count},容器候选 {_chestCandidates.Count}。");
			}
		}

		private static void UpdateChestFilter(float budgetEnd)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			Stopwatch stopwatch = Stopwatch.StartNew();
			int num = 0;
			while (_candidateCursor < _chestCandidates.Count)
			{
				ZDOID val = _chestCandidates[_candidateCursor++];
				num++;
				if (!_chestSeen.Contains(val))
				{
					ZDO zDO = ZDOMan.instance.GetZDO(val);
					if (zDO != null && IsInAnyGuard(zDO.GetPosition()))
					{
						if (zDO.GetInt(ZDOVars.s_inUse, 0) == 1)
						{
							_skipped++;
						}
						else
						{
							_chestSeen.Add(val);
							_chests.Add(val);
						}
					}
				}
				if ((num & 0x3FF) == 0 && Time.realtimeSinceStartup >= budgetEnd)
				{
					break;
				}
			}
			stopwatch.Stop();
			VoidChestPerf.AddFilter(stopwatch.Elapsed.TotalMilliseconds);
			if (_candidateCursor >= _chestCandidates.Count)
			{
				_chestCandidates.Clear();
				_chestIndex = 0;
				UpdateCache();
				_phase = Phase.Stacking;
				VLog.Info($"远程存入:目标箱子 {_chests.Count} 个(有权限守护石 {_guards.Count} 个)。");
			}
		}

		private static byte ClassifyPrefab(int prefabHash)
		{
			if (_prefabKind.TryGetValue(prefabHash, out var value))
			{
				return value;
			}
			byte b = 0;
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabHash) : null);
			if ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)val.GetComponent<PrivateArea>() != (Object)null)
				{
					b = 1;
				}
				else if ((Object)(object)val.GetComponent<Container>() != (Object)null && (Object)(object)val.GetComponent<Ship>() == (Object)null && (Object)(object)val.GetComponent<Vagon>() == (Object)null && !((Object)val).name.ToLower().Contains("tombstone"))
				{
					b = 2;
				}
			}
			_prefabKind[prefabHash] = b;
			return b;
		}

		private static void UpdateGuards(float budgetEnd)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			while (Time.realtimeSinceStartup < budgetEnd)
			{
				if (_prefabIndex >= _prefabNames.Count)
				{
					if (_guards.Count == 0)
					{
						Finish(VoidChestRemoteNet.Status.NoAccess);
					}
					else
					{
						BeginChestScan();
					}
					break;
				}
				string text = _prefabNames[_prefabIndex];
				Stopwatch stopwatch = Stopwatch.StartNew();
				bool allZDOsWithPrefabIterative = ZDOMan.instance.GetAllZDOsWithPrefabIterative(text, _found, ref _iter);
				stopwatch.Stop();
				VoidChestPerf.AddScan(stopwatch.Elapsed.TotalMilliseconds);
				if (!allZDOsWithPrefabIterative)
				{
					continue;
				}
				foreach (ZDO item in _found)
				{
					if (item.IsValid() && HasAccess(item))
					{
						_guards.Add(new GuardInfo
						{
							Pos = item.GetPosition(),
							Radius = GetGuardRadius(item.GetPrefab())
						});
						_guardIds.Add(item.m_uid);
					}
				}
				_found.Clear();
				_iter = 0;
				_prefabIndex++;
			}
		}

		private static void BeginChestScan()
		{
			_prefabNames = CollectPrefabs(delegate(GameObject go)
			{
				if ((Object)(object)go.GetComponent<Container>() == (Object)null)
				{
					return false;
				}
				if ((Object)(object)go.GetComponent<Ship>() != (Object)null || (Object)(object)go.GetComponent<Vagon>() != (Object)null)
				{
					return false;
				}
				return !((Object)go).name.ToLower().Contains("tombstone");
			});
			_prefabIndex = 0;
			_found.Clear();
			_iter = 0;
			_phase = Phase.Chests;
			VLog.Info($"远程存入:开始扫描容器({_prefabNames.Count} 种 prefab),有权限守护石 {_guards.Count} 个。");
		}

		private static void UpdateChests(float budgetEnd)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			while (Time.realtimeSinceStartup < budgetEnd)
			{
				if (_prefabIndex >= _prefabNames.Count)
				{
					_chestIndex = 0;
					UpdateCache();
					_phase = Phase.Stacking;
					VLog.Info($"远程存入:目标箱子 {_chests.Count} 个(有权限守护石 {_guards.Count} 个)。");
					break;
				}
				string text = _prefabNames[_prefabIndex];
				Stopwatch stopwatch = Stopwatch.StartNew();
				bool allZDOsWithPrefabIterative = ZDOMan.instance.GetAllZDOsWithPrefabIterative(text, _found, ref _iter);
				stopwatch.Stop();
				VoidChestPerf.AddScan(stopwatch.Elapsed.TotalMilliseconds);
				if (!allZDOsWithPrefabIterative)
				{
					continue;
				}
				foreach (ZDO item in _found)
				{
					if (item.IsValid() && !_chestSeen.Contains(item.m_uid) && IsInAnyGuard(item.GetPosition()))
					{
						if (item.GetInt(ZDOVars.s_inUse, 0) == 1)
						{
							_skipped++;
							continue;
						}
						_chestSeen.Add(item.m_uid);
						_chests.Add(item.m_uid);
					}
				}
				_found.Clear();
				_iter = 0;
				_prefabIndex++;
			}
		}

		private static bool TryUseCache()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			if (VoidChestPlugin.RemoteStoreCacheSeconds.Value <= 0f)
			{
				return false;
			}
			if (_cachePlayerId != _playerId)
			{
				return false;
			}
			if (_cachedGuardIds.Count == 0 && _cachedChestIds.Count == 0)
			{
				return false;
			}
			if (Time.realtimeSinceStartup - _cacheTime > VoidChestPlugin.RemoteStoreCacheSeconds.Value)
			{
				return false;
			}
			foreach (ZDOID cachedGuardId in _cachedGuardIds)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(cachedGuardId);
				if (zDO != null && zDO.IsValid())
				{
					_guards.Add(new GuardInfo
					{
						Pos = zDO.GetPosition(),
						Radius = GetGuardRadius(zDO.GetPrefab())
					});
					_guardIds.Add(cachedGuardId);
				}
			}
			if (_guards.Count == 0)
			{
				return false;
			}
			foreach (ZDOID cachedChestId in _cachedChestIds)
			{
				ZDO zDO2 = ZDOMan.instance.GetZDO(cachedChestId);
				if (zDO2 != null && zDO2.IsValid())
				{
					if (zDO2.GetInt(ZDOVars.s_inUse, 0) == 1)
					{
						_skipped++;
					}
					else if (_chestSeen.Add(cachedChestId))
					{
						_chests.Add(cachedChestId);
					}
				}
			}
			if (_chests.Count == 0)
			{
				return false;
			}
			VLog.Info($"远程存入:缓存命中(缓存于 {Time.realtimeSinceStartup - _cacheTime:F0}s 前,守护石 {_guards.Count},箱子 {_chests.Count})。");
			return true;
		}

		private static void UpdateCache()
		{
			_cachedGuardIds.Clear();
			_cachedGuardIds.AddRange(_guardIds);
			_cachedChestIds.Clear();
			_cachedChestIds.AddRange(_chests);
			_cachePlayerId = _playerId;
			_cacheTime = Time.realtimeSinceStartup;
			VLog.Debug($"远程存入:缓存已更新(守护石 {_cachedGuardIds.Count},箱子 {_cachedChestIds.Count})。");
		}

		private static void ProcessChest(ZDOID id)
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			Inventory targetInv = _targetInv;
			if (targetInv == null)
			{
				return;
			}
			try
			{
				ZDO zDO = ZDOMan.instance.GetZDO(id);
				if (zDO == null || !zDO.IsValid())
				{
					_skipped++;
					return;
				}
				if (zDO.GetInt(ZDOVars.s_inUse, 0) == 1)
				{
					_skipped++;
					return;
				}
				Stopwatch stopwatch = Stopwatch.StartNew();
				Vector2i containerSize = GetContainerSize(zDO.GetPrefab());
				Inventory val = new Inventory("RemoteContainer", (Sprite)null, containerSize.x, containerSize.y);
				byte[] byteArray = zDO.GetByteArray(ZDOVars.s_items, (byte[])null);
				if (byteArray != null)
				{
					val.Load(new ZPackage(byteArray));
				}
				int num = (_preFiltered ? VoidChestFilter.StackAllRaw(val, targetInv) : VoidChestFilter.StackAllFiltered(val, targetInv));
				if (num > 0)
				{
					Stopwatch stopwatch2 = Stopwatch.StartNew();
					ZPackage val2 = new ZPackage();
					val.Save(val2);
					zDO.Set(ZDOVars.s_items, val2.GetArray());
					stopwatch2.Stop();
					VoidChestPerf.AddDataWrite(stopwatch2.Elapsed.TotalMilliseconds);
					_moved += num;
				}
				_processed++;
				stopwatch.Stop();
				VoidChestPerf.NoteStep(stopwatch.Elapsed.TotalMilliseconds);
			}
			catch (Exception ex)
			{
				VLog.Warn($"远程存入:处理箱子 {id} 失败: {ex.Message}");
				_skipped++;
			}
		}

		private static void Finish(VoidChestRemoteNet.Status status)
		{
			_phase = Phase.Idle;
			if (_responsePeer != 0L)
			{
				List<KeyValuePair<string, int>> movedEntries = null;
				if (status == VoidChestRemoteNet.Status.Ok && _initialTotals != null && _targetInv != null)
				{
					movedEntries = BuildMovedEntries();
				}
				VoidChestRemoteNet.SendResult(_responsePeer, _responseSeq, status, _moved, _processed, _skipped, movedEntries);
			}
			else if ((Object)(object)_player != (Object)null)
			{
				VoidChestManager.Message(_player, VoidChestRemoteNet.BuildStatusMessage(status, _moved, _processed, _skipped));
			}
			VLog.Info($"远程存入完成:状态={status},移动 {_moved} 堆叠,箱子 {_processed},跳过 {_skipped},守护石 {_guards.Count}。");
			VLog.Info(VoidChestPerf.Summary("远程存储", _moved, _processed, 0, _skipped));
			_player = null;
			_targetInv = null;
			_initialTotals = null;
			_responsePeer = 0L;
			_responseSeq = 0L;
			_preFiltered = false;
		}

		private static List<KeyValuePair<string, int>> BuildMovedEntries()
		{
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>();
			Dictionary<string, int> dictionary = VoidChestItemIdentity.Totals(_targetInv);
			foreach (KeyValuePair<string, int> initialTotal in _initialTotals)
			{
				dictionary.TryGetValue(initialTotal.Key, out var value);
				int num = initialTotal.Value - value;
				if (num > 0)