Decompiled source of ItemDrawers v1.2.6

kg_ItemDrawers.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using kg_ItemDrawers;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace kg_ItemDrawers
{
	internal static class BuildBridge
	{
		private const float BuildRange = 20f;

		private static bool _applied;

		internal static void Apply(Harmony harmony)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			if (_applied)
			{
				return;
			}
			_applied = true;
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo.Name != "HaveRequirements"))
				{
					MethodInfo method = typeof(BuildBridge).GetMethod("HaveRequirementsPostfix", BindingFlags.Static | BindingFlags.NonPublic);
					try
					{
						harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						ItemDrawers.Instance.Log.LogInfo((object)("BuildBridge: patched HaveRequirements(" + string.Join(", ", GetParamTypes(methodInfo)) + ")"));
					}
					catch (Exception ex)
					{
						ItemDrawers.Instance.Log.LogWarning((object)("BuildBridge: failed to patch HaveRequirements: " + ex.Message));
					}
				}
			}
			methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "ConsumeResources"))
				{
					MethodInfo method2 = typeof(BuildBridge).GetMethod("ConsumeResourcesPrefix", BindingFlags.Static | BindingFlags.NonPublic);
					try
					{
						harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						ItemDrawers.Instance.Log.LogInfo((object)("BuildBridge: patched ConsumeResources(" + string.Join(", ", GetParamTypes(methodInfo2)) + ")"));
					}
					catch (Exception ex2)
					{
						ItemDrawers.Instance.Log.LogWarning((object)("BuildBridge: failed to patch ConsumeResources: " + ex2.Message));
					}
				}
			}
		}

		private static string[] GetParamTypes(MethodInfo mi)
		{
			ParameterInfo[] parameters = mi.GetParameters();
			string[] array = new string[parameters.Length];
			for (int i = 0; i < parameters.Length; i++)
			{
				array[i] = parameters[i].ParameterType.Name;
			}
			return array;
		}

		[UsedImplicitly]
		private static void HaveRequirementsPostfix(Player __instance, ref bool __result, object[] __args)
		{
			if (__result || (Object)(object)__instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			Requirement[] array = null;
			int quality = 0;
			if (__args != null)
			{
				foreach (object obj in __args)
				{
					Piece val = (Piece)((obj is Piece) ? obj : null);
					if (val != null && val?.m_resources != null)
					{
						array = val.m_resources;
						continue;
					}
					Recipe val2 = (Recipe)((obj is Recipe) ? obj : null);
					if (val2 != null && val2?.m_resources != null)
					{
						array = val2.m_resources;
					}
					else if (obj is Requirement[] array2)
					{
						array = array2;
					}
					else if (obj is int num)
					{
						quality = num;
					}
				}
			}
			if (array != null)
			{
				CheckAndSupplement(__instance, array, quality, ref __result);
			}
		}

		private static void CheckAndSupplement(Player player, Requirement[] resources, int quality, ref bool __result)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (resources == null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			List<DrawerComponent> list = FindNearbyDrawers(((Component)player).transform.position);
			if (list.Count == 0)
			{
				return;
			}
			foreach (Requirement val in resources)
			{
				if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0)
				{
					int num = val.m_amount * (quality + 1);
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					Inventory inventory = ((Humanoid)player).GetInventory();
					int num2 = ((inventory != null) ? inventory.CountItems(name, -1, true) : 0);
					int num3 = CountInDrawers(list, name);
					if (num2 + num3 < num)
					{
						return;
					}
				}
			}
			__result = true;
		}

		[UsedImplicitly]
		private static void ConsumeResourcesPrefix(Player __instance, object[] __args)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			Requirement[] array = null;
			int quality = 0;
			if (__args != null)
			{
				foreach (object obj in __args)
				{
					Piece val = (Piece)((obj is Piece) ? obj : null);
					if (val != null && val?.m_resources != null)
					{
						array = val.m_resources;
						continue;
					}
					Recipe val2 = (Recipe)((obj is Recipe) ? obj : null);
					if (val2 != null && val2?.m_resources != null)
					{
						array = val2.m_resources;
					}
					else if (obj is Requirement[] array2)
					{
						array = array2;
					}
					else if (obj is int num)
					{
						quality = num;
					}
				}
			}
			if (array != null)
			{
				ConsumeFromDrawers(__instance, array, quality);
			}
		}

		private static void ConsumeFromDrawers(Player player, Requirement[] resources, int quality)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (resources == null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			List<DrawerComponent> list = FindNearbyDrawers(((Component)player).transform.position);
			if (list.Count == 0)
			{
				return;
			}
			foreach (Requirement val in resources)
			{
				if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0)
				{
					int num = val.m_amount * (quality + 1);
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					Inventory inventory = ((Humanoid)player).GetInventory();
					int num2 = ((inventory != null) ? inventory.CountItems(name, -1, true) : 0);
					int num3 = num - num2;
					if (num3 > 0)
					{
						WithdrawFromDrawers(list, name, num3);
					}
				}
			}
		}

		private static List<DrawerComponent> FindNearbyDrawers(Vector3 pos)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			List<DrawerComponent> list = new List<DrawerComponent>();
			foreach (DrawerComponent allDrawer in DrawerComponent.AllDrawers)
			{
				if ((Object)(object)allDrawer == (Object)null || (Object)(object)allDrawer._znv == (Object)null || !allDrawer._znv.IsValid())
				{
					continue;
				}
				Component val = (Component)(object)allDrawer;
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					if (Vector3.Distance(val.transform.position, pos) <= 20f)
					{
						list.Add(allDrawer);
					}
				}
				catch
				{
				}
			}
			return list;
		}

		private static int CountInDrawers(List<DrawerComponent> drawers, string itemName)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return 0;
			}
			int num = 0;
			foreach (DrawerComponent drawer in drawers)
			{
				if ((Object)(object)drawer == (Object)null || (Object)(object)drawer._znv == (Object)null || !drawer._znv.IsValid())
				{
					continue;
				}
				ZDO zDO = drawer._znv.GetZDO();
				if (zDO == null)
				{
					continue;
				}
				string text = zDO.GetString("Prefab", "");
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
				if (!((Object)(object)itemPrefab == (Object)null))
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && component.m_itemData.m_shared.m_name == itemName)
					{
						num += zDO.GetInt("Amount", 0) + DrawerComponent.CountEnchantedFromZdo(zDO);
					}
				}
			}
			return num;
		}

		private static int WithdrawFromDrawers(List<DrawerComponent> drawers, string itemName, int needed)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return 0;
			}
			int num = 0;
			foreach (DrawerComponent drawer in drawers)
			{
				if (num >= needed)
				{
					break;
				}
				if ((Object)(object)drawer == (Object)null || (Object)(object)drawer._znv == (Object)null || !drawer._znv.IsValid())
				{
					continue;
				}
				ZDO zDO = drawer._znv.GetZDO();
				if (zDO == null)
				{
					continue;
				}
				string text = zDO.GetString("Prefab", "");
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
				if ((Object)(object)itemPrefab == (Object)null)
				{
					continue;
				}
				ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
				if (!((Object)(object)component == (Object)null) && !(component.m_itemData.m_shared.m_name != itemName))
				{
					int num2 = zDO.GetInt("Amount", 0);
					int num3 = Mathf.Min(needed - num, num2);
					if (num3 > 0)
					{
						drawer._znv.InvokeRPC("ForceRemove", new object[1] { num3 });
						num += num3;
					}
				}
			}
			return num;
		}
	}
	public class DrawerComponent : MonoBehaviour, Interactable, Hoverable
	{
		private struct DrawerOptions : ISerializableParameter
		{
			public DrawerComponent drawer;

			public Color32 color;

			public int pickupRange;

			public void Serialize(ref ZPackage pkg)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				pkg.Write(Utils.ColorToVec3(color));
				pkg.Write(pickupRange);
			}

			public void Deserialize(ref ZPackage pkg)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				color = Utils.Vec3ToColor(pkg.ReadVector3());
				pickupRange = pkg.ReadInt();
			}
		}

		[HarmonyPatch]
		private static class IsVisible
		{
			[HarmonyTargetMethods]
			[UsedImplicitly]
			private static IEnumerable<MethodInfo> Methods()
			{
				yield return AccessTools.Method(typeof(TextInput), "IsVisible", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(StoreGui), "IsVisible", (Type[])null, (Type[])null);
			}

			[HarmonyPostfix]
			[UsedImplicitly]
			private static void SetTrue(ref bool __result)
			{
				__result |= ShowUI;
			}
		}

		[CompilerGenerated]
		private static class DisplayClassO
		{
			public static WindowFunction CachedWindow;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static WindowFunction <0>__Window;
		}

		public static readonly List<DrawerComponent> AllDrawers = new List<DrawerComponent>();

		private static readonly FieldInfo F_s_instances = AccessTools.Field(typeof(ItemDrop), "s_instances");

		private static Sprite _defaultSprite;

		private static Sprite _circleSprite;

		private Image _image;

		private TMP_Text _text;

		private Transform _stars;

		private TMP_Text _starsText;

		private Transform _starIcon;

		private Image _rarityCircle;

		private static bool ShowUI;

		private static DrawerOptions CurrentOptions;

		private static bool _effectsLogged;

		public ZNetView _znv { get; private set; }

		public string CurrentPrefab
		{
			get
			{
				return _znv.GetZDO().GetString("Prefab", "");
			}
			set
			{
				_znv.GetZDO().Set("Prefab", value);
			}
		}

		public int CurrentAmount
		{
			get
			{
				return _znv.GetZDO().GetInt("Amount", 0);
			}
			set
			{
				_znv.GetZDO().Set("Amount", value);
			}
		}

		public int PickupRange
		{
			get
			{
				return _znv.GetZDO().GetInt("PickupRange", ItemDrawers.DrawerPickupRange.Value);
			}
			set
			{
				_znv.GetZDO().Set("PickupRange", value);
			}
		}

		public int Quality
		{
			get
			{
				return _znv.GetZDO().GetInt("Quality", 1);
			}
			set
			{
				_znv.GetZDO().Set("Quality", value);
			}
		}

		private string EnchantedData
		{
			get
			{
				return _znv.GetZDO().GetString("EnchantedB64", "");
			}
			set
			{
				_znv.GetZDO().Set("EnchantedB64", value ?? "");
			}
		}

		public int EnchantedCount
		{
			get
			{
				ZNetView znv = _znv;
				return CountEnchantedFromZdo((znv != null) ? znv.GetZDO() : null);
			}
		}

		public int TotalCount => CurrentAmount + EnchantedCount;

		private Color CurrentColor
		{
			get
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				return Color32.op_Implicit(Utils.Vec3ToColor(_znv.GetZDO().GetVec3("Color", ItemDrawers.DefaultColor.Value)));
			}
			set
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				_znv.GetZDO().Set("Color", Utils.ColorToVec3(Color32.op_Implicit(value)));
			}
		}

		public bool ItemValid
		{
			get
			{
				if (!string.IsNullOrEmpty(CurrentPrefab))
				{
					return (Object)(object)ObjectDB.instance.GetItemPrefab(CurrentPrefab) != (Object)null;
				}
				return false;
			}
		}

		private int ItemMaxStack => ObjectDB.instance.GetItemPrefab(CurrentPrefab).GetComponent<ItemDrop>().m_itemData.m_shared.m_maxStackSize;

		private string LocalizedName
		{
			get
			{
				if (EnchantedCount > 0)
				{
					List<(string, ItemData)> enchantedItems = GetEnchantedItems();
					if (enchantedItems.Count > 0)
					{
						string epicLootDisplayName = Utils.GetEpicLootDisplayName(enchantedItems[0].Item2);
						if (!string.IsNullOrEmpty(epicLootDisplayName))
						{
							return epicLootDisplayName;
						}
					}
				}
				return ObjectDB.instance.GetItemPrefab(CurrentPrefab).GetComponent<ItemDrop>().m_itemData.m_shared.m_name.Localize();
			}
		}

		private bool DoRepeat
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Expected O, but got Unknown
				if (Object.op_Implicit((Object)Player.m_localPlayer) && ItemValid)
				{
					return PickupRange > 0;
				}
				return false;
			}
		}

		public List<(string prefabName, ItemData item)> GetEnchantedItems()
		{
			string enchantedData = EnchantedData;
			if (string.IsNullOrEmpty(enchantedData))
			{
				return new List<(string, ItemData)>();
			}
			byte[] bytes;
			try
			{
				bytes = Convert.FromBase64String(enchantedData);
			}
			catch
			{
				return new List<(string, ItemData)>();
			}
			return Utils.DeserializeNamedItemList(bytes, (string name) => ObjectDB.instance.GetItemPrefab(name));
		}

		private void SetEnchantedItems(List<(string prefabName, ItemData item)> items)
		{
			ZDO zDO = _znv.GetZDO();
			if (items == null || items.Count == 0)
			{
				EnchantedData = "";
				zDO.Set("EncCount", 0);
				return;
			}
			byte[] array = Utils.SerializeNamedItemList(items);
			if (array == null || array.Length == 0)
			{
				EnchantedData = "";
				zDO.Set("EncCount", 0);
			}
			else
			{
				EnchantedData = Convert.ToBase64String(array);
				zDO.Set("EncCount", items.Count);
			}
		}

		public static int CountEnchantedFromZdo(ZDO zdo)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null)
			{
				return 0;
			}
			string text = zdo.GetString("EnchantedB64", "");
			if (string.IsNullOrEmpty(text))
			{
				if (zdo.IsOwner() && zdo.GetInt("EncCount", 0) != 0)
				{
					zdo.Set("EncCount", 0);
				}
				return 0;
			}
			int num = zdo.GetInt("EncCount", 0);
			if (num > 0)
			{
				return num;
			}
			try
			{
				byte[] array = Convert.FromBase64String(text);
				if (array == null || array.Length < 4)
				{
					return 0;
				}
				int num2 = new ZPackage(array).ReadInt();
				if (num2 < 0)
				{
					return 0;
				}
				if (num2 > 0 && zdo.IsOwner())
				{
					zdo.Set("EncCount", num2);
				}
				return num2;
			}
			catch
			{
				return 0;
			}
		}

		private void InvokeUpdateIcon()
		{
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			string currentPrefab = CurrentPrefab;
			int totalCount = TotalCount;
			int quality = Quality;
			ZDO zDO = _znv.GetZDO();
			if (zDO != null)
			{
				zDO.Set("Total", totalCount);
			}
			if (ItemDrawers.RarityColorEnabled != null && ItemDrawers.RarityColorEnabled.Value && EnchantedCount > 0 && !string.IsNullOrEmpty(currentPrefab) && ItemValidCheck(currentPrefab))
			{
				List<(string, ItemData)> enchantedItems = GetEnchantedItems();
				if (enchantedItems.Count > 0)
				{
					ItemData item = enchantedItems[0].Item2;
					int epicLootRarity = Utils.GetEpicLootRarity(item);
					ItemDrawers.DLog($"InvokeUpdateIcon: rarity={epicLootRarity} encCount={EnchantedCount} customDataKeys={(item?.m_customData?.Count).GetValueOrDefault()} prefab={currentPrefab}");
					if (epicLootRarity > 0)
					{
						Color rarityColor = Utils.GetRarityColor(epicLootRarity);
						Vector3 val = Utils.ColorToVec3(Color32.op_Implicit(rarityColor));
						zDO.Set("RarityColor", val);
						ItemDrawers.DLog($"InvokeUpdateIcon: rarity={epicLootRarity} color=({rarityColor.r},{rarityColor.g},{rarityColor.b}) vec=({val.x},{val.y},{val.z}) applied");
					}
					else
					{
						ItemDrawers.DLog("InvokeUpdateIcon: rarity<=0, no color set. customData keys: " + string.Join(",", item?.m_customData?.Keys ?? new Dictionary<string, string>().Keys));
					}
				}
				else
				{
					ItemDrawers.DLog($"InvokeUpdateIcon: GetEnchantedItems returned {enchantedItems.Count} items, encCount={EnchantedCount}");
				}
			}
			else if (EnchantedCount <= 0)
			{
				zDO.Set("RarityColor", new Vector3(-1f, -1f, -1f));
			}
			if (string.IsNullOrEmpty(currentPrefab) || !ItemValidCheck(currentPrefab))
			{
				_znv.InvokeRPC(ZNetView.Everybody, "UpdateIcon", new object[3] { "", 0, 0 });
			}
			else
			{
				_znv.InvokeRPC(ZNetView.Everybody, "UpdateIcon", new object[3] { currentPrefab, totalCount, quality });
			}
		}

		public bool ItemValidCheck(string prefab)
		{
			if (!string.IsNullOrEmpty(prefab))
			{
				return (Object)(object)ObjectDB.instance.GetItemPrefab(prefab) != (Object)null;
			}
			return false;
		}

		private void OnDestroy()
		{
			AllDrawers.Remove(this);
		}

		private static void PurgeLegacyEnchantedByteArray(ZDO zdo)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null)
			{
				return;
			}
			try
			{
				int stableHashCode = StringExtensionMethods.GetStableHashCode("EnchantedData");
				FieldInfo fieldInfo = AccessTools.Field(typeof(ZDOExtraData), "s_byteArrays");
				if (fieldInfo == null)
				{
					return;
				}
				object value = fieldInfo.GetValue(null);
				if (value == null)
				{
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(value.GetType(), "TryGetValue", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					return;
				}
				object[] array = new object[2] { zdo.m_uid, null };
				if ((bool)methodInfo.Invoke(value, array))
				{
					object obj = array[1];
					if (obj != null)
					{
						AccessTools.Method(obj.GetType(), "Remove", new Type[1] { typeof(int) }, (Type[])null)?.Invoke(obj, new object[1] { stableHashCode });
					}
				}
			}
			catch (Exception ex)
			{
				try
				{
					ItemDrawers instance = ItemDrawers.Instance;
					if (instance != null)
					{
						ManualLogSource log = instance.Log;
						if (log != null)
						{
							log.LogWarning((object)("PurgeLegacyEnchantedByteArray: " + ex.Message));
						}
					}
				}
				catch
				{
				}
			}
		}

		private static Sprite GetCircleSprite()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0137: 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)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_circleSprite != (Object)null)
			{
				return _circleSprite;
			}
			int num = 32;
			Texture2D val = new Texture2D(num, num, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)1;
			Color32[] array = (Color32[])(object)new Color32[num * num];
			float num2 = (float)num / 2f;
			float num3 = (float)num / 2f - 1f;
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					float num4 = (float)j + 0.5f - num2;
					float num5 = (float)i + 0.5f - num2;
					float num6 = Mathf.Sqrt(num4 * num4 + num5 * num5);
					if (num6 <= num3)
					{
						array[i * num + j] = Color32.op_Implicit(Color.white);
					}
					else if (num6 <= num3 + 1f)
					{
						float num7 = Mathf.Clamp01(num3 + 1f - num6);
						array[i * num + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num7 * 255f));
					}
					else
					{
						array[i * num + j] = new Color32((byte)0, (byte)0, (byte)0, (byte)0);
					}
				}
			}
			val.SetPixels32(array);
			val.Apply();
			_circleSprite = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f);
			return _circleSprite;
		}

		private void CreateRarityCircle(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("RarityCircle");
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.GetComponent<RectTransform>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.AddComponent<RectTransform>();
			}
			val2.anchorMin = new Vector2(1f, 1f);
			val2.anchorMax = new Vector2(1f, 1f);
			val2.pivot = new Vector2(0.5f, 0.5f);
			val2.sizeDelta = new Vector2(16f, 16f);
			val2.anchoredPosition = new Vector2(-8f, -8f);
			_rarityCircle = val.AddComponent<Image>();
			_rarityCircle.sprite = GetCircleSprite();
			((Graphic)_rarityCircle).color = Color.white;
			((Graphic)_rarityCircle).raycastTarget = false;
			((Component)_rarityCircle).gameObject.SetActive(false);
		}

		private void Awake()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			_znv = ((Component)this).GetComponent<ZNetView>();
			if (_znv.IsValid())
			{
				AllDrawers.Add(this);
				_image = ((Component)((Component)this).transform.Find("Cube/Canvas/Image")).GetComponent<Image>();
				if ((Object)(object)_defaultSprite == (Object)null)
				{
					_defaultSprite = _image.sprite;
				}
				_text = ((Component)((Component)this).transform.Find("Cube/Canvas/Text")).GetComponent<TMP_Text>();
				if ((Object)(object)ItemDrawers.NorseFont != (Object)null)
				{
					_text.font = ItemDrawers.NorseFont;
				}
				_text.fontSize /= 2f;
				((Graphic)_text).color = CurrentColor;
				_stars = ((Component)this).transform.Find("Cube/Canvas/Stars");
				_starsText = ((Component)_stars.Find("Quality")).GetComponent<TMP_Text>();
				_starIcon = _stars.Find("Img");
				CreateRarityCircle(((Component)_image).transform);
				ApplyTextEffects(_text);
				ApplyTextEffects(_starsText);
				PurgeLegacyEnchantedByteArray(_znv.GetZDO());
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && !_znv.IsOwner())
				{
					_znv.ClaimOwnership();
					ItemDrawers.DLog("Awake: claimed ZDO ownership on server for drawer");
				}
				_znv.Register<string, int, int>("AddItem_Request", (Action<long, string, int, int>)RPC_AddItem);
				_znv.Register<string, int, int>("AddItem_Player", (Action<long, string, int, int>)RPC_AddItem_Player);
				_znv.Register<int>("WithdrawItem_Request", (Action<long, int>)RPC_WithdrawItem_Request);
				_znv.Register<string, int, int>("UpdateIcon", (Action<long, string, int, int>)RPC_UpdateIcon);
				_znv.Register<int>("ForceRemove", (Action<long, int>)RPC_ForceRemove);
				_znv.Register<DrawerOptions>("ApplyOptions", (Action<long, DrawerOptions>)RPC_ApplyOptions);
				_znv.Register<string, int, string>("AddEnchanted_Request", (Action<long, string, int, string>)RPC_AddEnchanted);
				_znv.Register<string>("AddEnchanted_Player", (Action<long, string>)RPC_AddEnchanted_Player);
				_znv.Register<int>("WithdrawEnchanted_Request", (Action<long, int>)RPC_WithdrawEnchanted_Request);
				RPC_UpdateIcon(0L, CurrentPrefab, TotalCount, Quality);
				float num = Random.Range(2.5f, 3f);
				((MonoBehaviour)this).InvokeRepeating("Repeat", num, num);
			}
		}

		private static void ApplyTextEffects(TMP_Text text)
		{
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)text == (Object)null)
			{
				return;
			}
			try
			{
				Material fontMaterial = text.fontMaterial;
				if ((Object)(object)fontMaterial == (Object)null)
				{
					return;
				}
				Shader val = Shader.Find("TextMeshPro/Distance Field") ?? Shader.Find("Hidden/TextMeshPro/Distance Field");
				if ((Object)(object)val != (Object)null && (Object)(object)fontMaterial.shader != (Object)(object)val)
				{
					string text2 = (((Object)(object)fontMaterial.shader != (Object)null) ? ((Object)fontMaterial.shader).name : "null");
					fontMaterial.shader = val;
					if (!_effectsLogged)
					{
						_effectsLogged = true;
						ItemDrawers.Instance.Log.LogInfo((object)("ApplyTextEffects: shader was '" + text2 + "', switched to '" + ((Object)val).name + "'"));
					}
				}
				else if ((Object)(object)val == (Object)null && !_effectsLogged)
				{
					_effectsLogged = true;
					ItemDrawers.Instance.Log.LogInfo((object)"ApplyTextEffects: full SDF shader not found — outline/shadow will not work.");
				}
				if (ItemDrawers.TextOutlineEnabled != null && ItemDrawers.TextOutlineEnabled.Value)
				{
					fontMaterial.EnableKeyword("OUTLINE_ON");
					fontMaterial.SetFloat("_OutlineWidth", ItemDrawers.TextOutlineWidth.Value);
					fontMaterial.SetColor("_OutlineColor", ItemDrawers.TextOutlineColor.Value);
					fontMaterial.SetFloat("_OutlineSoftness", 0f);
				}
				if (ItemDrawers.TextShadowEnabled != null && ItemDrawers.TextShadowEnabled.Value)
				{
					fontMaterial.EnableKeyword("UNDERLAY_ON");
					fontMaterial.SetColor("_UnderlayColor", ItemDrawers.TextShadowColor.Value);
					fontMaterial.SetFloat("_UnderlayOffsetX", ItemDrawers.TextShadowOffset.Value);
					fontMaterial.SetFloat("_UnderlayOffsetY", 0f - ItemDrawers.TextShadowOffset.Value);
					fontMaterial.SetFloat("_UnderlaySoftness", ItemDrawers.TextShadowSoftness.Value);
					fontMaterial.SetFloat("_UnderlayDilate", 0f);
				}
				text.havePropertiesChanged = true;
				((Graphic)text).SetAllDirty();
			}
			catch (Exception ex)
			{
				try
				{
					ItemDrawers.Instance.Log.LogInfo((object)("ApplyTextEffects: " + ex.Message));
				}
				catch
				{
				}
			}
		}

		private void RPC_ApplyOptions(long sender, DrawerOptions options)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (_znv.IsOwner())
			{
				CurrentColor = Color32.op_Implicit(options.color);
				PickupRange = Mathf.Min(ItemDrawers.MaxDrawerPickupRange.Value, options.pickupRange);
			}
			((Graphic)_text).color = Color32.op_Implicit(options.color);
		}

		private void RPC_ForceRemove(long sender, int amount)
		{
			if (_znv.IsOwner() && amount > 0)
			{
				int currentAmount = CurrentAmount;
				amount = Mathf.Min(amount, CurrentAmount);
				CurrentAmount -= amount;
				ItemDrawers.DLog($"ForceRemove: {CurrentPrefab} -{amount} ({currentAmount}->{CurrentAmount}) enc={EnchantedCount} sender={sender}");
				if (CurrentAmount <= 0 && EnchantedCount <= 0)
				{
					CurrentPrefab = "";
					CurrentAmount = 0;
					Quality = 1;
				}
				InvokeUpdateIcon();
			}
		}

		private void RPC_WithdrawItem_Request(long sender, int amount)
		{
			if (CurrentAmount <= 0 || !ItemValid)
			{
				if (EnchantedCount <= 0)
				{
					CurrentPrefab = "";
					CurrentAmount = 0;
					Quality = 1;
				}
				InvokeUpdateIcon();
			}
			else if (amount > 0)
			{
				amount = Mathf.Min(amount, CurrentAmount);
				CurrentAmount -= amount;
				_znv.InvokeRPC(sender, "AddItem_Player", new object[3] { CurrentPrefab, amount, Quality });
				InvokeUpdateIcon();
			}
		}

		private void RPC_AddItem_Player(long _, string prefab, int amount, int quality)
		{
			Utils.InstantiateItem(ZNetScene.instance.GetPrefab(prefab), amount, quality);
		}

		private void RPC_UpdateIcon(long _, string prefab, int amount, int quality)
		{
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			int num = amount;
			if (string.IsNullOrEmpty(prefab) || !ItemValidCheck(prefab))
			{
				_image.sprite = _defaultSprite;
				((Component)_stars).gameObject.SetActive(false);
				((Component)_text).gameObject.SetActive(false);
				if ((Object)(object)_text != (Object)null)
				{
					_text.text = "";
				}
				if ((Object)(object)_rarityCircle != (Object)null)
				{
					((Component)_rarityCircle).gameObject.SetActive(false);
				}
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				((Component)_text).gameObject.SetActive(false);
				return;
			}
			_image.sprite = itemPrefab.GetComponent<ItemDrop>().m_itemData.GetIcon();
			_text.text = ((num > 0) ? num.ToString() : "0");
			_text.ForceMeshUpdate(false, false);
			((Component)_text).gameObject.SetActive(true);
			((Component)_stars).gameObject.SetActive(quality > 1);
			if (quality > 1)
			{
				_starsText.text = quality.ToString();
				_starIcon.localPosition = new Vector3((quality >= 10) ? 9f : 0f, 5.25f, 0f);
			}
			if (ItemDrawers.RarityColorEnabled != null && ItemDrawers.RarityColorEnabled.Value && (Object)(object)_rarityCircle != (Object)null)
			{
				ZNetView znv = _znv;
				ZDO val = ((znv != null) ? znv.GetZDO() : null);
				if (val != null)
				{
					Vector3 vec = val.GetVec3("RarityColor", new Vector3(-1f, -1f, -1f));
					if (vec.x >= 0f && vec.y >= 0f && vec.z >= 0f)
					{
						Color32 val2 = Utils.Vec3ToColor(vec);
						((Graphic)_rarityCircle).color = Color32.op_Implicit(val2);
						((Component)_rarityCircle).gameObject.SetActive(true);
						object[] obj = new object[11]
						{
							vec.x,
							vec.y,
							vec.z,
							val2.r,
							val2.g,
							val2.b,
							val2.a,
							((Component)_rarityCircle).gameObject.activeSelf,
							null,
							null,
							null
						};
						Transform parent = ((Component)_rarityCircle).transform.parent;
						obj[8] = ((parent != null) ? ((Object)parent).name : null);
						RectTransform rectTransform = ((Graphic)_rarityCircle).rectTransform;
						float num2;
						Rect rect;
						if (rectTransform == null)
						{
							num2 = 0f;
						}
						else
						{
							rect = rectTransform.rect;
							num2 = ((Rect)(ref rect)).width;
						}
						obj[9] = num2;
						RectTransform rectTransform2 = ((Graphic)_rarityCircle).rectTransform;
						float num3;
						if (rectTransform2 == null)
						{
							num3 = 0f;
						}
						else
						{
							rect = rectTransform2.rect;
							num3 = ((Rect)(ref rect)).height;
						}
						obj[10] = num3;
						ItemDrawers.DLog(string.Format("RPC_UpdateIcon: SHOW circle RarityColor=({0},{1},{2}) color32=({3},{4},{5},{6}) active={7} parent={8} size={9}x{10}", obj));
					}
					else
					{
						((Component)_rarityCircle).gameObject.SetActive(false);
						ItemDrawers.DLog($"RPC_UpdateIcon: HIDE circle RarityColor=({vec.x},{vec.y},{vec.z}) (no rarity)");
					}
				}
			}
			else if ((Object)(object)_rarityCircle != (Object)null)
			{
				((Component)_rarityCircle).gameObject.SetActive(false);
			}
			if ((Object)(object)_text != (Object)null)
			{
				((Graphic)_text).color = CurrentColor;
			}
		}

		private void RPC_AddItem(long sender, string prefab, int amount, int quality)
		{
			if (!_znv.IsOwner())
			{
				ItemDrawers.DLog($"AddItem ignore: not owner prefab={prefab} x{amount}");
				return;
			}
			if (amount <= 0 || string.IsNullOrEmpty(prefab))
			{
				ItemDrawers.DLog($"AddItem REJECT: amount={amount} prefab={prefab}");
				return;
			}
			quality = Math.Max(1, quality);
			if (TotalCount <= 0 && !string.IsNullOrEmpty(CurrentPrefab) && CurrentPrefab != prefab)
			{
				CurrentPrefab = "";
				CurrentAmount = 0;
				Quality = 1;
				SetEnchantedItems(null);
			}
			string currentPrefab = CurrentPrefab;
			if (!string.IsNullOrEmpty(currentPrefab) && TotalCount > 0 && (currentPrefab != prefab || Quality != quality))
			{
				ItemDrawers.DLog($"AddItem REJECT mismatch: have={currentPrefab} q{Quality} got={prefab} q{quality} x{amount} — returning");
				_znv.InvokeRPC(sender, "AddItem_Player", new object[3] { prefab, amount, quality });
			}
			else
			{
				CurrentAmount = ((TotalCount > 0 || CurrentAmount > 0) ? (CurrentAmount + amount) : amount);
				CurrentPrefab = prefab;
				Quality = quality;
				ItemDrawers.DLog($"AddItem OK: {prefab} +{amount} q{quality} => Amount={CurrentAmount} Total={TotalCount}");
				InvokeUpdateIcon();
			}
		}

		private void RPC_AddEnchanted(long sender, string prefab, int quality, string itemDataBase64)
		{
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			ItemDrawers.DLog($"RPC_AddEnchanted ENTRY: sender={sender} prefab={prefab} q{quality} b64len={itemDataBase64?.Length ?? 0}");
			if (!_znv.IsOwner() || string.IsNullOrEmpty(itemDataBase64))
			{
				ItemDrawers instance = ItemDrawers.Instance;
				if (instance != null)
				{
					ManualLogSource log = instance.Log;
					if (log != null)
					{
						log.LogWarning((object)$"RPC_AddEnchanted: rejected (owner={_znv.IsOwner()}, empty={string.IsNullOrEmpty(itemDataBase64)})");
					}
				}
				return;
			}
			quality = Math.Max(1, quality);
			byte[] array = null;
			try
			{
				array = Convert.FromBase64String(itemDataBase64);
			}
			catch (Exception ex)
			{
				ItemDrawers instance2 = ItemDrawers.Instance;
				if (instance2 != null)
				{
					ManualLogSource log2 = instance2.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("RPC_AddEnchanted: base64 decode failed: " + ex.Message));
					}
				}
				return;
			}
			if (array == null || array.Length == 0)
			{
				ItemDrawers instance3 = ItemDrawers.Instance;
				if (instance3 != null)
				{
					ManualLogSource log3 = instance3.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)$"RPC_AddEnchanted: decoded bytes empty (len={((array != null) ? array.Length : 0)})");
					}
				}
				return;
			}
			ItemDrawers.DLog($"RPC_AddEnchanted: decoded {array.Length} bytes");
			string currentPrefab = CurrentPrefab;
			if (ItemValid && !string.IsNullOrEmpty(currentPrefab) && currentPrefab != prefab)
			{
				if (CurrentAmount > 0)
				{
					Utils.InstantiateAtPos(ZNetScene.instance.GetPrefab(currentPrefab), CurrentAmount, Quality, ((Component)this).transform.position + Vector3.up * 1.5f);
					CurrentAmount = 0;
				}
				List<(string, ItemData)> enchantedItems = GetEnchantedItems();
				if (enchantedItems.Count > 0)
				{
					foreach (var item3 in enchantedItems)
					{
						string item = item3.Item1;
						ItemData item2 = item3.Item2;
						GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
						if ((Object)(object)itemPrefab != (Object)null)
						{
							Utils.DropEnchantedItem(itemPrefab, item2, ((Component)this).transform.position + Vector3.up * 1.5f);
						}
					}
					SetEnchantedItems(new List<(string, ItemData)>());
				}
			}
			CurrentPrefab = prefab;
			Quality = quality;
			GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab(prefab);
			if ((Object)(object)itemPrefab2 == (Object)null)
			{
				ItemDrawers instance4 = ItemDrawers.Instance;
				if (instance4 != null)
				{
					ManualLogSource log4 = instance4.Log;
					if (log4 != null)
					{
						log4.LogWarning((object)("RPC_AddEnchanted: prefab '" + prefab + "' not found in ObjectDB!"));
					}
				}
				return;
			}
			ItemData val = Utils.DeserializeItemData(array, itemPrefab2);
			if (val == null)
			{
				ItemDrawers instance5 = ItemDrawers.Instance;
				if (instance5 != null)
				{
					ManualLogSource log5 = instance5.Log;
					if (log5 != null)
					{
						log5.LogWarning((object)("RPC_AddEnchanted: DeserializeItemData returned null for prefab '" + prefab + "'!"));
					}
				}
				return;
			}
			ItemDrawers.DLog($"RPC_AddEnchanted: deserialized OK, customData keys={val.m_customData?.Count ?? 0}");
			List<(string, ItemData)> enchantedItems2 = GetEnchantedItems();
			if (ItemDrawers.StackOnlySameEnchantment != null && ItemDrawers.StackOnlySameEnchantment.Value && enchantedItems2.Count > 0 && !Utils.CustomDataEquals(enchantedItems2[0].Item2?.m_customData, val.m_customData))
			{
				ItemDrawers instance6 = ItemDrawers.Instance;
				if (instance6 != null)
				{
					ManualLogSource log6 = instance6.Log;
					if (log6 != null)
					{
						log6.LogInfo((object)("RPC_AddEnchanted REJECT: enchantment mismatch (drawer has different enchantment for " + prefab + ")"));
					}
				}
				byte[] array2 = Utils.SerializeItemData(val);
				if (array2 != null && array2.Length != 0)
				{
					string text = Convert.ToBase64String(array2);
					_znv.InvokeRPC(sender, "AddEnchanted_Player", new object[1] { text });
				}
			}
			else
			{
				enchantedItems2.Add((prefab, val));
				SetEnchantedItems(enchantedItems2);
				ItemDrawers.DLog($"AddEnchanted OK: {prefab} q{quality} enc={enchantedItems2.Count} EncCount={EnchantedCount} EnchantedB64={EnchantedData.Length} chars customDataKeys={val.m_customData?.Count ?? 0}");
				InvokeUpdateIcon();
			}
		}

		private void RPC_AddEnchanted_Player(long _, string itemDataBase64)
		{
			ItemDrawers.DLog($"RPC_AddEnchanted_Player ENTRY: b64len={itemDataBase64?.Length ?? 0}");
			if (string.IsNullOrEmpty(itemDataBase64))
			{
				return;
			}
			byte[] array = null;
			try
			{
				array = Convert.FromBase64String(itemDataBase64);
			}
			catch (Exception ex)
			{
				ItemDrawers instance = ItemDrawers.Instance;
				if (instance != null)
				{
					ManualLogSource log = instance.Log;
					if (log != null)
					{
						log.LogWarning((object)("RPC_AddEnchanted_Player: base64 decode failed: " + ex.Message));
					}
				}
				return;
			}
			if (array == null || array.Length == 0)
			{
				return;
			}
			string currentPrefab = CurrentPrefab;
			if (string.IsNullOrEmpty(currentPrefab))
			{
				ItemDrawers instance2 = ItemDrawers.Instance;
				if (instance2 != null)
				{
					ManualLogSource log2 = instance2.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)"RPC_AddEnchanted_Player: CurrentPrefab is empty!");
					}
				}
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(currentPrefab);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				ItemDrawers instance3 = ItemDrawers.Instance;
				if (instance3 != null)
				{
					ManualLogSource log3 = instance3.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)("RPC_AddEnchanted_Player: prefab '" + currentPrefab + "' not found!"));
					}
				}
				return;
			}
			ItemData val = Utils.DeserializeItemData(array, itemPrefab);
			if (val == null)
			{
				ItemDrawers instance4 = ItemDrawers.Instance;
				if (instance4 != null)
				{
					ManualLogSource log4 = instance4.Log;
					if (log4 != null)
					{
						log4.LogWarning((object)"RPC_AddEnchanted_Player: DeserializeItemData returned null!");
					}
				}
			}
			else
			{
				ItemDrawers.DLog($"RPC_AddEnchanted_Player: deserialized OK, customData keys={val.m_customData?.Count ?? 0}");
				Utils.InstantiateEnchantedItem(itemPrefab, val);
			}
		}

		private void RPC_WithdrawEnchanted_Request(long sender, int amount)
		{
			List<(string, ItemData)> enchantedItems = GetEnchantedItems();
			ItemDrawers.DLog($"RPC_WithdrawEnchanted_Request: sender={sender} amount={amount} listCount={enchantedItems.Count}");
			int num = Math.Min(amount, enchantedItems.Count);
			if (num <= 0)
			{
				if (CurrentAmount <= 0)
				{
					CurrentPrefab = "";
					CurrentAmount = 0;
					Quality = 1;
				}
				InvokeUpdateIcon();
				return;
			}
			for (int i = 0; i < num; i++)
			{
				var (text, val) = enchantedItems[enchantedItems.Count - 1];
				enchantedItems.RemoveAt(enchantedItems.Count - 1);
				byte[] array = Utils.SerializeItemData(val);
				if (array == null || array.Length == 0)
				{
					ItemDrawers instance = ItemDrawers.Instance;
					if (instance != null)
					{
						ManualLogSource log = instance.Log;
						if (log != null)
						{
							log.LogWarning((object)("RPC_WithdrawEnchanted: SerializeItemData failed for " + text + "!"));
						}
					}
				}
				else
				{
					string text2 = Convert.ToBase64String(array);
					ItemDrawers.DLog($"RPC_WithdrawEnchanted: sending {text} bytes={array.Length} b64={text2.Length} customDataKeys={val.m_customData?.Count ?? 0}");
					_znv.InvokeRPC(sender, "AddEnchanted_Player", new object[1] { text2 });
				}
			}
			SetEnchantedItems(enchantedItems);
			ItemDrawers.DLog($"RPC_WithdrawEnchanted: done, remaining enc={enchantedItems.Count}");
			if (enchantedItems.Count == 0 && CurrentAmount <= 0)
			{
				CurrentPrefab = "";
				Quality = 1;
			}
			InvokeUpdateIcon();
		}

		private void Repeat()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid() || !_znv.IsOwner() || !DoRepeat)
			{
				return;
			}
			string currentPrefab = CurrentPrefab;
			int quality = Quality;
			Vector3 vector = ((Component)this).transform.position + Vector3.up;
			IEnumerable<ItemDrop> enumerable = (IEnumerable<ItemDrop>)F_s_instances.GetValue(null);
			if (enumerable == null)
			{
				return;
			}
			foreach (ItemDrop item in enumerable.Where((ItemDrop drop) => Vector3.Distance(((Component)drop).transform.position, vector) < (float)PickupRange))
			{
				string name = ((Object)item.m_itemData.m_dropPrefab).name;
				if (name != currentPrefab || item.m_itemData.m_quality != quality)
				{
					continue;
				}
				if (!item.CanPickup(false))
				{
					item.RequestOwn();
					continue;
				}
				Object.Instantiate<GameObject>(ItemDrawers.Explosion, ((Component)item).transform.position, Quaternion.identity);
				int stack = item.m_itemData.m_stack;
				ZNetView component = ((Component)item).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					continue;
				}
				if (!component.IsOwner())
				{
					item.RequestOwn();
					continue;
				}
				if (Utils.HasCustomData(item.m_itemData))
				{
					List<(string, ItemData)> enchantedItems = GetEnchantedItems();
					if (ItemDrawers.StackOnlySameEnchantment != null && ItemDrawers.StackOnlySameEnchantment.Value && enchantedItems.Count > 0 && !Utils.CustomDataEquals(enchantedItems[0].Item2?.m_customData, item.m_itemData.m_customData))
					{
						ItemDrawers.DLog("Repeat: SKIP auto-pickup — enchantment mismatch for " + name);
						continue;
					}
					enchantedItems.Add((name, item.m_itemData));
					SetEnchantedItems(enchantedItems);
				}
				else
				{
					CurrentAmount += stack;
				}
				ZNetScene.instance.Destroy(((Component)item).gameObject);
				InvokeUpdateIcon();
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false))
			{
				return true;
			}
			if (((Character)user).IsCrouching())
			{
				CurrentOptions.drawer = this;
				CurrentOptions.color = Color32.op_Implicit(CurrentColor);
				CurrentOptions.pickupRange = PickupRange;
				ShowUI = true;
				return true;
			}
			if (!ItemValid)
			{
				return false;
			}
			if (Input.GetKey((KeyCode)308))
			{
				if (EnchantedCount > 0)
				{
					_znv.InvokeRPC("WithdrawEnchanted_Request", new object[1] { 1 });
				}
				else
				{
					_znv.InvokeRPC("WithdrawItem_Request", new object[1] { 1 });
				}
				return true;
			}
			if (Input.GetKey((KeyCode)304))
			{
				int quality = Quality;
				int num = Utils.CustomCountItems(CurrentPrefab, quality);
				if (num <= 0)
				{
					return true;
				}
				Utils.CustomRemoveItems(CurrentPrefab, num, quality);
				_znv.InvokeRPC("AddItem_Request", new object[3] { CurrentPrefab, num, quality });
				return true;
			}
			if (EnchantedCount > 0)
			{
				_znv.InvokeRPC("WithdrawEnchanted_Request", new object[1] { 1 });
			}
			else
			{
				_znv.InvokeRPC("WithdrawItem_Request", new object[1] { ItemMaxStack });
			}
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			string prefabName = Utils.GetPrefabName(item);
			if (string.IsNullOrEmpty(prefabName))
			{
				ItemDrawers.DLog("UseItem REJECT: cannot resolve prefab (dropPrefab=" + (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "null") + " shared=" + item?.m_shared?.m_name + ")");
				if (user != null)
				{
					((Character)user).Message((MessageType)2, ModLocalization.MsgUnknownItem.Localize(), 0, (Sprite)null);
				}
				return false;
			}
			if (ItemDrawers.ExcludeSet.Contains(prefabName) && !Player.m_debugMode)
			{
				ItemDrawers.DLog("UseItem REJECT: excluded " + prefabName);
				if (user != null)
				{
					((Character)user).Message((MessageType)2, string.Format(ModLocalization.MsgExcluded.Localize(), prefabName), 0, (Sprite)null);
				}
				return false;
			}
			bool flag = TotalCount <= 0;
			if (!string.IsNullOrEmpty(CurrentPrefab) && !flag && (CurrentPrefab != prefabName || Quality != item.m_quality))
			{
				ItemDrawers.DLog($"UseItem REJECT: drawer has {CurrentPrefab} q{Quality}, item is {prefabName} q{item.m_quality}");
				if (user != null)
				{
					((Character)user).Message((MessageType)2, string.Format(ModLocalization.MsgHasPrefab.Localize(), CurrentPrefab), 0, (Sprite)null);
				}
				return false;
			}
			int stack = item.m_stack;
			if (stack <= 0)
			{
				ItemDrawers.DLog("UseItem REJECT: stack<=0");
				return false;
			}
			if (Utils.HasCustomData(item))
			{
				if (ItemDrawers.StackOnlySameEnchantment != null && ItemDrawers.StackOnlySameEnchantment.Value && EnchantedCount > 0)
				{
					List<(string, ItemData)> enchantedItems = GetEnchantedItems();
					if (enchantedItems.Count > 0 && !Utils.CustomDataEquals(enchantedItems[0].Item2?.m_customData, item.m_customData))
					{
						ItemDrawers.DLog("UseItem REJECT: enchantment mismatch (drawer has different enchantment for " + prefabName + ")");
						if (user != null)
						{
							((Character)user).Message((MessageType)2, ModLocalization.MsgDiffEnchant.Localize(), 0, (Sprite)null);
						}
						return false;
					}
				}
				byte[] array = Utils.SerializeItemData(item);
				if (array == null || array.Length == 0)
				{
					ItemDrawers instance = ItemDrawers.Instance;
					if (instance != null)
					{
						ManualLogSource log = instance.Log;
						if (log != null)
						{
							log.LogWarning((object)"UseItem: SerializeItemData failed — item not removed.");
						}
					}
					return false;
				}
				string text = Convert.ToBase64String(array);
				ItemDrawers.DLog($"UseItem ENCHANTED: {prefabName} q{item.m_quality} keys={item.m_customData.Count} bytes={array.Length} b64={text.Length}");
				user.GetInventory().RemoveItem(item);
				_znv.InvokeRPC("AddEnchanted_Request", new object[3] { prefabName, item.m_quality, text });
				return true;
			}
			ItemDrawers.DLog($"UseItem VANILLA: {prefabName} x{stack} q{item.m_quality} → AddItem_Request (drawerAmount={CurrentAmount})");
			user.GetInventory().RemoveItem(item);
			_znv.InvokeRPC("AddItem_Request", new object[3]
			{
				prefabName,
				stack,
				Math.Max(1, item.m_quality)
			});
			return true;
		}

		public string GetHoverText()
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (((Character)Player.m_localPlayer).IsCrouching())
			{
				stringBuilder.AppendLine("[<color=yellow><b>$KEY_Use</b></color>] " + ModLocalization.HoverOpenSettings.Localize());
				return stringBuilder.ToString().Localize();
			}
			if (!ItemValid)
			{
				stringBuilder.AppendLine("<color=yellow><b>" + ModLocalization.HoverUseHotbar.Localize() + "</b></color>");
				return stringBuilder.ToString().Localize();
			}
			int quality = Quality;
			string text = ((quality > 1) ? (" (" + string.Format(ModLocalization.HoverQuality.Localize(), quality) + ")") : "");
			int totalCount = TotalCount;
			stringBuilder.AppendLine($"<color=yellow><b>{LocalizedName}{text}</b></color> ({totalCount})");
			stringBuilder.AppendLine("<color=yellow><b>" + ModLocalization.HoverUseHotbar.Localize() + "</b></color>\n");
			if (totalCount <= 0)
			{
				stringBuilder.AppendLine("[<color=yellow><b>$KEY_Use</b></color>] " + ModLocalization.HoverClear.Localize());
				stringBuilder.AppendLine($"[<color=yellow><b>Left Shift + $KEY_Use</b></color>] {ModLocalization.HoverDepositAll.Localize()} <color=yellow><b>{LocalizedName}</b></color> ({Utils.CustomCountItems(CurrentPrefab, quality)})");
				return stringBuilder.ToString().Localize();
			}
			stringBuilder.AppendLine($"[<color=yellow><b>$KEY_Use</b></color>] {ModLocalization.HoverWithdrawStack.Localize()} ({ItemMaxStack})");
			stringBuilder.AppendLine("[<color=yellow><b>Left Alt + $KEY_Use</b></color>] " + ModLocalization.HoverWithdrawSingle.Localize());
			stringBuilder.AppendLine($"[<color=yellow><b>Left Shift + $KEY_Use</b></color>] {ModLocalization.HoverDepositAll.Localize()} <color=yellow><b>{LocalizedName}{text}</b></color> ({Utils.CustomCountItems(CurrentPrefab, quality)})");
			return stringBuilder.ToString().Localize();
		}

		public string GetHoverName()
		{
			return ModLocalization.HoverName.Localize();
		}

		public static void ProcessInput()
		{
			if (Input.GetKeyDown((KeyCode)27) && ShowUI)
			{
				ShowUI = false;
				Menu.instance.OnClose();
			}
		}

		public static void ProcessGUI()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			if (!ShowUI)
			{
				return;
			}
			GUI.backgroundColor = Color.white;
			Rect val = new Rect((float)Screen.width / 2f - 150f, (float)Screen.height / 2f - 150f, 300f, 300f);
			object obj = DisplayClassO.CachedWindow;
			if (obj == null)
			{
				object obj2 = <>O.<0>__Window;
				if (obj2 == null)
				{
					WindowFunction val2 = Window;
					<>O.<0>__Window = val2;
					obj2 = (object)val2;
				}
				DisplayClassO.CachedWindow = (WindowFunction)obj2;
				obj = obj2;
			}
			GUI.Window(218102318, val, (WindowFunction)obj, ModLocalization.GuiTitle.Localize());
		}

		private static void Window(int id)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)CurrentOptions.drawer == (Object)null || !CurrentOptions.drawer._znv.IsValid())
			{
				ShowUI = false;
				return;
			}
			GUILayout.Label($"{ModLocalization.GuiCurrentDrawer.Localize()} <color=yellow><b>{CurrentOptions.drawer.LocalizedName}</b></color> ({CurrentOptions.drawer.CurrentAmount})", Array.Empty<GUILayoutOption>());
			byte r = CurrentOptions.color.r;
			byte g = CurrentOptions.color.g;
			byte b = CurrentOptions.color.b;
			GUILayout.Label($"{ModLocalization.GuiTextColor.Localize()} <color=#{r:X2}{g:X2}{b:X2}><b>0123456789</b></color>", Array.Empty<GUILayoutOption>());
			GUILayout.Label($"R: {r}", Array.Empty<GUILayoutOption>());
			r = (byte)GUILayout.HorizontalSlider((float)(int)r, 0f, 255f, Array.Empty<GUILayoutOption>());
			GUILayout.Label($"G: {g}", Array.Empty<GUILayoutOption>());
			g = (byte)GUILayout.HorizontalSlider((float)(int)g, 0f, 255f, Array.Empty<GUILayoutOption>());
			GUILayout.Label($"B: {b}", Array.Empty<GUILayoutOption>());
			b = (byte)GUILayout.HorizontalSlider((float)(int)b, 0f, 255f, Array.Empty<GUILayoutOption>());
			CurrentOptions.color = new Color32(r, g, b, byte.MaxValue);
			int pickupRange = CurrentOptions.pickupRange;
			GUILayout.Space(16f);
			GUILayout.Label(string.Format(ModLocalization.GuiPickupRange.Localize() + " <color={0}><b>{1}</b></color>", (pickupRange > 0) ? "lime" : "red", pickupRange), Array.Empty<GUILayoutOption>());
			pickupRange = (int)GUILayout.HorizontalSlider((float)pickupRange, 0f, (float)ItemDrawers.MaxDrawerPickupRange.Value, Array.Empty<GUILayoutOption>());
			CurrentOptions.pickupRange = pickupRange;
			GUILayout.Space(16f);
			if (GUILayout.Button("<color=lime>" + ModLocalization.GuiApply.Localize() + "</color>", Array.Empty<GUILayoutOption>()))
			{
				CurrentOptions.drawer._znv.InvokeRPC(ZNetView.Everybody, "ApplyOptions", new object[1] { CurrentOptions });
				ShowUI = false;
			}
		}
	}
	public static class EpicLootDisplayNamePatch
	{
		private static bool _initialized;

		private static bool _enabled;

		private static MethodInfo _tryGetLegendaryInfo;

		private static MethodInfo _getMagicItemMethod;

		private static FieldInfo _magicItemDisplayNameField;

		private static FieldInfo _magicItemLegendaryIDField;

		public static bool IsEnabled => _enabled;

		public static void Init(Harmony harmonyInstance = null)
		{
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Expected O, but got Unknown
			if (_initialized)
			{
				return;
			}
			_initialized = true;
			try
			{
				Assembly assembly = Array.Find(AppDomain.CurrentDomain.GetAssemblies(), (Assembly a) => a.GetName().Name == "EpicLoot");
				if (assembly == null)
				{
					ItemDrawers.DLog("EpicLootDisplayNamePatch: EpicLoot not found, patch disabled");
					return;
				}
				Type type = assembly.GetType("EpicLoot.LegendarySystem.UniqueLegendaryHelper") ?? assembly.GetType("EpicLoot.UniqueLegendaryHelper");
				Type type2 = assembly.GetType("EpicLoot.ItemDataExtensions");
				Type type3 = assembly.GetType("EpicLoot.MagicItem");
				if (type == null || type2 == null || type3 == null)
				{
					ItemDrawers.DLog("EpicLootDisplayNamePatch: required types not found");
					return;
				}
				_tryGetLegendaryInfo = type.GetMethod("TryGetLegendaryInfo", BindingFlags.Static | BindingFlags.Public);
				_getMagicItemMethod = type2.GetMethod("GetMagicItem", new Type[1] { typeof(ItemData) });
				_magicItemDisplayNameField = type3.GetField("DisplayName", BindingFlags.Instance | BindingFlags.Public);
				_magicItemLegendaryIDField = type3.GetField("LegendaryID", BindingFlags.Instance | BindingFlags.Public);
				if (_tryGetLegendaryInfo == null || _getMagicItemMethod == null || _magicItemDisplayNameField == null || _magicItemLegendaryIDField == null)
				{
					ItemDrawers.DLog("EpicLootDisplayNamePatch: required members not found");
					return;
				}
				MethodInfo method = type2.GetMethod("GetDisplayName", new Type[1] { typeof(ItemData) });
				if (method == null)
				{
					ItemDrawers.DLog("EpicLootDisplayNamePatch: GetDisplayName method not found");
					return;
				}
				MethodInfo method2 = typeof(EpicLootDisplayNamePatch).GetMethod("PostfixDisplayName", BindingFlags.Static | BindingFlags.NonPublic);
				Harmony val = (Harmony)(((object)harmonyInstance) ?? ((object)/*isinst with value type is only supported in some contexts*/));
				if (val == null)
				{
					ItemDrawers.DLog("EpicLootDisplayNamePatch: harmony instance not available");
					return;
				}
				val.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_enabled = true;
				ItemDrawers.DLog("EpicLootDisplayNamePatch: patch applied successfully");
			}
			catch (Exception arg)
			{
				ItemDrawers.DLog($"EpicLootDisplayNamePatch init failed: {arg}");
			}
		}

		private static void PostfixDisplayName(ref string __result, ItemData itemData)
		{
			if (!_enabled || itemData == null)
			{
				return;
			}
			try
			{
				object obj = _getMagicItemMethod.Invoke(null, new object[1] { itemData });
				if (obj == null)
				{
					return;
				}
				string text = (string)_magicItemLegendaryIDField.GetValue(obj);
				if (string.IsNullOrEmpty(text))
				{
					return;
				}
				object[] array = new object[2] { text, null };
				if (!(bool)_tryGetLegendaryInfo.Invoke(null, array))
				{
					return;
				}
				object obj2 = array[1];
				if (obj2 == null)
				{
					return;
				}
				FieldInfo field = obj2.GetType().GetField("Name", BindingFlags.Instance | BindingFlags.Public);
				if (field == null)
				{
					return;
				}
				string text2 = (string)field.GetValue(obj2);
				if (string.IsNullOrEmpty(text2))
				{
					return;
				}
				string text3 = (string)_magicItemDisplayNameField.GetValue(obj);
				if (text2 == text3)
				{
					return;
				}
				string text4 = "";
				if (!string.IsNullOrEmpty(text3) && !string.IsNullOrEmpty(__result))
				{
					int num = __result.IndexOf(text3, StringComparison.Ordinal);
					if (num >= 0)
					{
						text4 = __result.Substring(num + text3.Length);
					}
				}
				ItemDrawers.DLog("EpicLootDisplayNamePatch: replacing '" + text3 + "' with '" + text2 + "' for LegendaryID=" + text);
				__result = text2 + text4;
			}
			catch (Exception ex)
			{
				ItemDrawers.DLog("EpicLootDisplayNamePatch postfix failed: " + ex.Message);
			}
		}
	}
	[BepInPlugin("kg.ItemDrawers", "Cybrp ItemDrawers", "1.2.6")]
	public class ItemDrawers : BaseUnityPlugin
	{
		private const string TiffanyAnsi = "\u001b[38;2;10;186;181m";

		private const string AnsiReset = "\u001b[0m";

		private const int StdOutputHandle = -11;

		private const uint EnableVirtualTerminalProcessing = 4u;

		public static readonly byte[] BuildStampBytes = new byte[16]
		{
			66, 82, 79, 72, 69, 73, 77, 95, 73, 68,
			95, 49, 95, 48, 95, 51
		};

		public static ItemDrawers Instance;

		private static Harmony _harmony;

		public static ConfigEntry<int> DrawerPickupRange;

		public static ConfigEntry<int> MaxDrawerPickupRange;

		public static ConfigEntry<Vector3> DefaultColor;

		public static ConfigEntry<string> ExcludeList;

		public static ConfigEntry<bool> CfgDepositLogs;

		public static HashSet<string> ExcludeSet = new HashSet<string>();

		public static ConfigEntry<bool> TextOutlineEnabled;

		public static ConfigEntry<float> TextOutlineWidth;

		public static ConfigEntry<Color> TextOutlineColor;

		public static ConfigEntry<bool> TextShadowEnabled;

		public static ConfigEntry<Color> TextShadowColor;

		public static ConfigEntry<float> TextShadowOffset;

		public static ConfigEntry<float> TextShadowSoftness;

		public static ConfigEntry<bool> StackOnlySameEnchantment;

		public static ConfigEntry<bool> RarityColorEnabled;

		public static GameObject Explosion;

		public static TMP_FontAsset NorseFont;

		private static AssetBundle _bundle;

		private static readonly string[] DrawerPrefabNames = new string[7] { "kg_ItemDrawer_Wood", "kg_ItemDrawer_Stone", "kg_ItemDrawer_Marble", "kg_ItemDrawerPanel_Wood", "kg_ItemDrawerPanel_Stone", "kg_ItemDrawerPanel_Marble", "kg_ItemDrawer_NoModel" };

		private static readonly (string name, string item, int amount)[] DrawerRecipes = new(string, string, int)[7]
		{
			("$piece_kg_ItemDrawer_Wood", "Wood", 10),
			("$piece_kg_ItemDrawer_Stone", "Stone", 10),
			("$piece_kg_ItemDrawer_Marble", "BlackMarble", 10),
			("$piece_kg_ItemDrawerPanel_Wood", "Wood", 10),
			("$piece_kg_ItemDrawerPanel_Stone", "Stone", 10),
			("$piece_kg_ItemDrawerPanel_Marble", "BlackMarble", 10),
			("$piece_kg_ItemDrawer_NoModel", "GreydwarfEye", 10)
		};

		private static bool _epicLootPatchApplied;

		public static string BuildStamp => Encoding.ASCII.GetString(BuildStampBytes);

		internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger;

		internal static IReadOnlyList<string> AllDrawerPrefabNames => DrawerPrefabNames;

		internal static IReadOnlyList<(string name, string item, int amount)> AllDrawerRecipes => DrawerRecipes;

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern IntPtr GetStdHandle(int nStdHandle);

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

		private static void TryEnableVirtualTerminal()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (((object)Application.platform/*cast due to .constrained prefix*/).ToString().Contains("Windows"))
				{
					IntPtr stdHandle = GetStdHandle(-11);
					if (!(stdHandle == IntPtr.Zero) && !(stdHandle == new IntPtr(-1)) && GetConsoleMode(stdHandle, out var lpMode) && (lpMode & 4) == 0)
					{
						SetConsoleMode(stdHandle, lpMode | 4);
					}
				}
			}
			catch
			{
			}
		}

		private static TextWriter GetBepInExConsoleStream()
		{
			try
			{
				Type type = AccessTools.TypeByName("BepInEx.ConsoleManager");
				if (type == null)
				{
					return null;
				}
				return AccessTools.Property(type, "ConsoleStream")?.GetValue(null) as TextWriter;
			}
			catch
			{
				return null;
			}
		}

		private static void SetBepInExConsoleColor(ConsoleColor color)
		{
			try
			{
				AccessTools.Method(AccessTools.TypeByName("BepInEx.ConsoleManager"), "SetConsoleColor", new Type[1] { typeof(ConsoleColor) }, (Type[])null)?.Invoke(null, new object[1] { color });
			}
			catch
			{
			}
		}

		private static void PrintLoadBanner()
		{
			string[] array = new string[3] { "█▀▀\u2003█▄█\u2003█▄▄\u2003█▀█\u2003█▀█\u2003 \u2003▄▄\u2003 \u2003█\u2003▀█▀\u2003█▀▀\u2003█▀▄▀█\u2003█▀▄\u2003█▀█\u2003▄▀█\u2003█░█░█\u2003█▀▀\u2003█▀█\u2003█▀", "█▄▄\u2003░█░\u2003█▄█\u2003█▀▄\u2003█▀▀\u2003 \u2003░░\u2003 \u2003█\u2003░█░\u2003██▄\u2003█░▀░█\u2003█▄▀\u2003█▀▄\u2003█▀█\u2003▀▄▀▄▀\u2003██▄\u2003█▀▄\u2003▄█", "  Cybrp ItemDrawers v1.2.6" };
			try
			{
				TryEnableVirtualTerminal();
				TextWriter bepInExConsoleStream = GetBepInExConsoleStream();
				string[] array2;
				if (bepInExConsoleStream != null)
				{
					bepInExConsoleStream.WriteLine();
					array2 = array;
					foreach (string text in array2)
					{
						bepInExConsoleStream.WriteLine("\u001b[38;2;10;186;181m" + text + "\u001b[0m");
					}
					bepInExConsoleStream.WriteLine();
					bepInExConsoleStream.Flush();
					return;
				}
				SetBepInExConsoleColor(ConsoleColor.Cyan);
				Console.Out.WriteLine();
				array2 = array;
				foreach (string value in array2)
				{
					Console.Out.WriteLine(value);
				}
				Console.Out.WriteLine();
				SetBepInExConsoleColor(ConsoleColor.Gray);
			}
			catch
			{
			}
		}

		internal static void DLog(string msg)
		{
			if (CfgDepositLogs == null || !CfgDepositLogs.Value)
			{
				return;
			}
			ItemDrawers instance = Instance;
			if (instance != null)
			{
				ManualLogSource log = instance.Log;
				if (log != null)
				{
					log.LogInfo((object)msg);
				}
			}
		}

		private void Awake()
		{
			//IL_0015: 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_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Expected O, but got Unknown
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Expected O, but got Unknown
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Expected O, but got Unknown
			Instance = this;
			PrintLoadBanner();
			PieceManager.Instance.AddPieceCategory("itemdrawers");
			ExcludeList = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ExcludeList", "", "List of items to exclude in the drawer. Leave blank to include all items.");
			ExcludeList.SettingChanged += ResetList;
			ResetList(null, null);
			DrawerPickupRange = ((BaseUnityPlugin)this).Config.Bind<int>("General", "DrawerPickupRange", 4, "Range at which you can pick up items from the drawer.");
			MaxDrawerPickupRange = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxDrawerPickupRange", 100, "Maximum range at which you can pick up items from the drawer.");
			DefaultColor = ((BaseUnityPlugin)this).Config.Bind<Vector3>("General", "DefaultColor", new Vector3(0.039f, 0.729f, 0.71f), "Default color of the drawer text.");
			TextOutlineEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("TextEffects", "OutlineEnabled", true, "Draw a black outline around the item-count digits for readability.");
			TextOutlineWidth = ((BaseUnityPlugin)this).Config.Bind<float>("TextEffects", "OutlineWidth", 0.15f, new ConfigDescription("Outline thickness (0.0–1.0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			TextOutlineColor = ((BaseUnityPlugin)this).Config.Bind<Color>("TextEffects", "OutlineColor", Color.black, "Outline color.");
			TextShadowEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("TextEffects", "ShadowEnabled", true, "Draw a drop shadow under the item-count digits for readability.");
			TextShadowColor = ((BaseUnityPlugin)this).Config.Bind<Color>("TextEffects", "ShadowColor", new Color(0f, 0f, 0f, 0.6f), "Shadow color (alpha controls opacity).");
			TextShadowOffset = ((BaseUnityPlugin)this).Config.Bind<float>("TextEffects", "ShadowOffset", 0.4f, new ConfigDescription("Shadow offset distance (0.0–1.0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			TextShadowSoftness = ((BaseUnityPlugin)this).Config.Bind<float>("TextEffects", "ShadowSoftness", 0.15f, new ConfigDescription("Shadow softness/blur (0.0–1.0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			StackOnlySameEnchantment = ((BaseUnityPlugin)this).Config.Bind<bool>("Enchanted", "StackOnlySameEnchantment", true, "When true, enchanted/modded items only stack in a drawer if their m_customData (enchantments, effects) are identical. When false, all enchanted items of the same prefab+quality stack together.");
			RarityColorEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Enchanted", "RarityColorEnabled", true, "When true, the drawer text color changes based on EpicLoot rarity (Magic=blue, Rare=yellow, Epic=purple, Legendary=teal, Mythic=orange). Overrides the default text color for enchanted drawers.");
			_bundle = LoadAssetBundle("kg_itemdrawers");
			Explosion = _bundle.LoadAsset<GameObject>("kg_ItemDrawer_Explosion");
			NorseFont = NorseFontLoader.Load();
			StationAuto.CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("StationAuto", "Enabled", true, "Master switch for auto-feed/deposit. Off = station integration does nothing.");
			StationAuto.CfgRadius = ((BaseUnityPlugin)this).Config.Bind<float>("StationAuto", "Radius", 8f, new ConfigDescription("Range (m) to search ItemDrawers around a station.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			StationAuto.CfgSmelterRadius = ((BaseUnityPlugin)this).Config.Bind<float>("StationAuto", "SmelterRadius", 15f, new ConfigDescription("Range (m) for smelters/kilns pulling from ItemDrawers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			StationAuto.CfgFeed = ((BaseUnityPlugin)this).Config.Bind<bool>("StationAuto", "FeedFromDrawers", true, "Stations pull fuel/materials directly from nearby ItemDrawers (only from matching non-empty drawers).");
			StationAuto.CfgDeposit = ((BaseUnityPlugin)this).Config.Bind<bool>("StationAuto", "DepositToDrawers", true, "Cooking stations/beehives/sap collectors push finished output into matching nearby drawers.");
			StationAuto.CfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("StationAuto", "DebugLogs", false, "Verbose logging.");
			StationAuto.VReflect.Init();
			QuickStackBridge.CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("QuickStackBridge", "Enabled", true, "Master switch.");
			QuickStackBridge.CfgQuickStackToDrawers = ((BaseUnityPlugin)this).Config.Bind<bool>("QuickStackBridge", "QuickStackToDrawers", true, "Quick Stack (P) also deposits stackable items into matching nearby ItemDrawers (NOT into empty drawers).");
			QuickStackBridge.CfgRestockFromDrawers = ((BaseUnityPlugin)this).Config.Bind<bool>("QuickStackBridge", "RestockFromDrawers", true, "Restock (L) also tops up partially filled stacks from matching nearby ItemDrawers.");
			QuickStackBridge.CfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("QuickStackBridge", "DebugLogs", false, "Verbose logging.");
			CfgDepositLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DepositLogs", true, "Log UseItem / AddItem / ForceRemove / AddEnchanted with reasons.");
			ModLocalization.Init();
			Harmony val = new Harmony("kg.ItemDrawers");
			_harmony = val;
			val.PatchAll(Assembly.GetExecutingAssembly());
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Cybrp ItemDrawers {BuildStamp} (v1.2.6) loaded. stamp[0]={BuildStampBytes[0]} FeedFromDrawers={StationAuto.CfgFeed.Value}");
			AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoaded;
			TryInitQuickStackBridge();
			TryInitEpicLootPatch();
			AppDomain.CurrentDomain.AssemblyLoad += OnEpicLootLoaded;
		}

		private static void OnAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
		{
			if (!(args.LoadedAssembly.GetName().Name != "QuickStackStore"))
			{
				TryInitQuickStackBridge();
				AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoaded;
			}
		}

		private static void TryInitQuickStackBridge()
		{
			if (!QuickStackBridge.QssReflect.Ready)
			{
				QuickStackBridge.QssReflect.Init();
				if (QuickStackBridge.QssReflect.Ready)
				{
					QuickStackBridgePatch.Apply(_harmony);
					RestockBridgePatch.Apply(_harmony);
					Instance.Log.LogInfo((object)"QuickStackBridge patches applied (deferred).");
				}
			}
		}

		private static void TryInitEpicLootPatch()
		{
			if (!_epicLootPatchApplied && !(Array.Find(AppDomain.CurrentDomain.GetAssemblies(), (Assembly a) => a.GetName().Name == "EpicLoot") == null))
			{
				EpicLootDisplayNamePatch.Init(_harmony);
				_epicLootPatchApplied = EpicLootDisplayNamePatch.IsEnabled;
				if (_epicLootPatchApplied)
				{
					Instance.Log.LogInfo((object)"EpicLootDisplayNamePatch applied (deferred).");
				}
			}
		}

		private static void OnEpicLootLoaded(object sender, AssemblyLoadEventArgs args)
		{
			if (!(args.LoadedAssembly.GetName().Name != "EpicLoot"))
			{
				TryInitEpicLootPatch();
				AppDomain.CurrentDomain.AssemblyLoad -= OnEpicLootLoaded;
			}
		}

		private void OnGUI()
		{
			DrawerComponent.ProcessGUI();
		}

		private void Update()
		{
			DrawerComponent.ProcessInput();
			ModLocalization.TryDeferredRegister();
		}

		private void ResetList(object sender, EventArgs e)
		{
			ExcludeSet = new HashSet<string>(ExcludeList.Value.Replace(" ", "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries));
		}

		private static AssetBundle LoadAssetBundle(string filename)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string name = executingAssembly.GetManifestResourceNames().First((string s) => s.EndsWith(filename + ".bundle") || s.EndsWith(filename));
			using Stream stream = executingAssembly.GetManifestResourceStream(name);
			return AssetBundle.LoadFromStream(stream);
		}

		internal static GameObject GetDrawerPrefab(string name)
		{
			return _bundle.LoadAsset<GameObject>(name);
		}
	}
	public static class ModLocalization
	{
		private static readonly Dictionary<string, Dictionary<string, string>> _translations = new Dictionary<string, Dictionary<string, string>>();

		private static string _currentLanguage = "English";

		public static readonly string HoverName = "$broheim_id_hover_name";

		public static readonly string MsgUnknownItem = "$broheim_id_msg_unknown";

		public static readonly string MsgExcluded = "$broheim_id_msg_excluded";

		public static readonly string MsgHasPrefab = "$broheim_id_msg_has_prefab";

		public static readonly string MsgDiffEnchant = "$broheim_id_msg_diff_enchant";

		public static readonly string HoverOpenSettings = "$broheim_id_hover_open_settings";

		public static readonly string HoverUseHotbar = "$broheim_id_hover_use_hotbar";

		public static readonly string HoverQuality = "$broheim_id_hover_quality";

		public static readonly string HoverClear = "$broheim_id_hover_clear";

		public static readonly string HoverDepositAll = "$broheim_id_hover_deposit_all";

		public static readonly string HoverWithdrawStack = "$broheim_id_hover_withdraw_stack";

		public static readonly string HoverWithdrawSingle = "$broheim_id_hover_withdraw_single";

		public static readonly string GuiTitle = "$broheim_id_gui_title";

		public static readonly string GuiCurrentDrawer = "$broheim_id_gui_current_drawer";

		public static readonly string GuiTextColor = "$broheim_id_gui_text_color";

		public static readonly string GuiPickupRange = "$broheim_id_gui_pickup_range";

		public static readonly string GuiApply = "$broheim_id_gui_apply";

		private static int _initAttempts = 0;

		private static string _overrideLanguage = null;

		private static readonly FieldInfo F_m_translations = typeof(Localization).GetField("m_translations", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo M_AddWord = typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
		{
			typeof(string),
			typeof(string)
		}, null);

		private static readonly MethodInfo M_GetSelectedLanguage = typeof(Localization).GetMethod("GetSelectedLanguage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

		private static readonly FieldInfo F_m_language = typeof(Localization).GetField("m_language", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static bool _loggedLanguageSource;

		public static void Init()
		{
			LoadEmbedded();
			RegisterCurrent();
		}

		public static void OnLanguageChanged(string lang = null)
		{
			if (!string.IsNullOrEmpty(lang))
			{
				_overrideLanguage = lang;
			}
			RegisterCurrent();
		}

		public static void TryDeferredRegister()
		{
			if (_initAttempts < 5)
			{
				_initAttempts++;
				RegisterCurrent();
			}
		}

		private static void LoadEmbedded()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				if (!text.StartsWith("kg_ItemDrawers.Translations."))
				{
					continue;
				}
				string text2 = text.Substring("kg_ItemDrawers.Translations.".Length);
				if (text2.EndsWith(".json"))
				{
					text2 = text2.Substring(0, text2.Length - 5);
				}
				try
				{
					using Stream stream = executingAssembly.GetManifestResourceStream(text);
					using StreamReader streamReader = new StreamReader(stream);
					Dictionary<string, string> dictionary = ParseSimpleJson(streamReader.ReadToEnd());
					_translations[text2] = dictionary;
					ItemDrawers instance = ItemDrawers.Instance;
					if (instance != null)
					{
						ManualLogSource log = instance.Log;
						if (log != null)
						{
							log.LogInfo((object)$"ModLocalization: loaded {dictionary.Count} tokens for '{text2}'");
						}
					}
				}
				catch (Exception ex)
				{
					ItemDrawers instance2 = ItemDrawers.Instance;
					if (instance2 != null)
					{
						ManualLogSource log2 = instance2.Log;
						if (log2 != null)
						{
							log2.LogWarning((object)("ModLocalization: failed to load '" + text + "': " + ex.Message));
						}
					}
				}
			}
			if (_translations.ContainsKey("English"))
			{
				return;
			}
			ItemDrawers instance3 = ItemDrawers.Instance;
			if (instance3 != null)
			{
				ManualLogSource log3 = instance3.Log;
				if (log3 != null)
				{
					log3.LogWarning((object)"ModLocalization: English.json not found — using empty fallback");
				}
			}
			_translations["English"] = new Dictionary<string, string>();
		}

		private static void RegisterCurrent()
		{
			_currentLanguage = GetCurrentLanguage();
			Dictionary<string, string> forLanguage = GetForLanguage(_currentLanguage);
			if (Localization.instance == null)
			{
				ItemDrawers instance = ItemDrawers.Instance;
				if (instance != null)
				{
					ManualLogSource log = instance.Log;
					if (log != null)
					{
						log.LogWarning((object)"ModLocalization: Localization.instance is null — deferring registration");
					}
				}
				return;
			}
			int num = 0;
			if (M_AddWord != null)
			{
				foreach (KeyValuePair<string, string> item in forLanguage)
				{
					try
					{
						string text = (item.Key.StartsWith("$") ? item.Key.Substring(1) : item.Key);
						M_AddWord.Invoke(Localization.instance, new object[2] { text, item.Value });
						num++;
					}
					catch
					{
					}
				}
			}
			if (num == 0 && F_m_translations != null)
			{
				Dictionary<string, string> dictionary = (Dictionary<string, string>)F_m_translations.GetValue(Localization.instance);
				if (dictionary != null)
				{
					foreach (KeyValuePair<string, string> item2 in forLanguage)
					{
						string key = (item2.Key.StartsWith("$") ? item2.Key.Substring(1) : item2.Key);
						dictionary[key] = item2.Value;
						num++;
					}
				}
				else
				{
					ItemDrawers instance2 = ItemDrawers.Instance;
					if (instance2 != null)
					{
						ManualLogSource log2 = instance2.Log;
						if (log2 != null)
						{
							log2.LogWarning((object)"ModLocalization: m_translations dictionary is null");
						}
					}
				}
			}
			if (num == 0)
			{
				FieldInfo[] fields = typeof(Localization).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				string arg = string.Join(", ", fields.Select((FieldInfo f) => f.Name + ":" + f.FieldType.Name));
				ItemDrawers instance3 = ItemDrawers.Instance;
				if (instance3 != null)
				{
					ManualLogSource log3 = instance3.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)$"ModLocalization: FAILED to register tokens. AddWord={M_AddWord != null}, m_translations={F_m_translations != null}. Fields: {arg}");
					}
				}
				return;
			}
			ItemDrawers instance4 = ItemDrawers.Instance;
			if (instance4 != null)
			{
				ManualLogSource log4 = instance4.Log;
				if (log4 != null)
				{
					log4.LogInfo((object)string.Format("ModLocalization: registered {0} tokens for language '{1}' (method: {2})", num, _currentLanguage, (M_AddWord != null) ? "AddWord" : "reflection"));
				}
			}
		}

		private static string GetCurrentLanguage()
		{
			if (!string.IsNullOrEmpty(_overrideLanguage))
			{
				return _overrideLanguage;
			}
			try
			{
				Localization instance = Localization.instance;
				if (instance == null)
				{
					return "English";
				}
				if (M_GetSelectedLanguage != null)
				{
					string text = M_GetSelectedLanguage.Invoke(instance, null) as string;
					if (!string.IsNullOrEmpty(text))
					{
						LogLanguageSourceOnce("GetSelectedLanguage", text);
						return text;
					}
				}
				if (F_m_language != null)
				{
					string text2 = F_m_language.GetValue(instance) as string;
					if (!string.IsNullOrEmpty(text2))
					{
						LogLanguageSourceOnce("m_language", text2);
						return text2;
					}
				}
			}
			catch (Exception ex)
			{
				ItemDrawers instance2 = ItemDrawers.Instance;
				if (instance2 != null)
				{
					ManualLogSource log = instance2.Log;
					if (log != null)
					{
						log.LogWarning((object)("ModLocalization: GetCurrentLanguage failed: " + ex.Message));
					}
				}
			}
			return "English";
		}

		private static void LogLanguageSourceOnce(string source, string lang)
		{
			if (_loggedLanguageSource)
			{
				return;
			}
			_loggedLanguageSource = true;
			ItemDrawers instance = ItemDrawers.Instance;
			if (instance != null)
			{
				ManualLogSource log = instance.Log;
				if (log != null)
				{
					log.LogInfo((object)("ModLocalization: language from " + source + " = '" + lang + "'"));
				}
			}
		}

		private static Dictionary<string, string> GetForLanguage(string lang)
		{
			if (_translations.TryGetValue(lang, out var value) && value.Count > 0)
			{
				return value;
			}
			if (_translations.TryGetValue("English", out var value2) && value2.Count > 0)
			{
				return value2;
			}
			return new Dictionary<string, string>();
		}

		private static Dictionary<string, string> ParseSimpleJson(string json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (string.IsNullOrEmpty(json))
			{
				return dictionary;
			}
			json = json.Trim();
			if (json.StartsWith("{"))
			{
				json = json.Substring(1);
			}
			if (json.EndsWith("}"))
			{
				json = json.Substring(0, json.Length - 1);
			}
			int i = 0;
			while (i < json.Length)
			{
				for (; i < json.Length && (json[i] == ' ' || json[i] == ',' || json[i] == '\n' || json[i] == '\r' || json[i] == '\t'); i++)
				{
				}
				if (i >= json.Length || json[i] != '"')
				{
					break;
				}
				string key = ReadString(json, ref i);
				for (; i < json.Length && json[i] != ':'; i++)
				{
				}
				for (i++; i < json.Length && (json[i] == ' ' || json[i] == '\n' || json[i] == '\r' || json[i] == '\t'); i++)
				{
				}
				if (i < json.Length && json[i] == '"')
				{
					string value = ReadString(json, ref i);
					dictionary[key] = value;
				}
			}
			return dictionary;
		}

		private static string ReadString(string json, ref int i)
		{
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < json.Length)
			{
				char c = json[i];
				if (c == '\\' && i + 1 < json.Length)
				{
					char c2 = json[i + 1];
					switch (c2)
					{
					case 'n':
						stringBuilder.Append('\n');
						break;
					case 't':
						stringBuilder.Append('\t');
						break;
					case 'r':
						stringBuilder.Append('\r');
						break;
					case '"':
						stringBuilder.Append('"');
						break;
					case '\\':
						stringBuilder.Append('\\');
						break;
					case '/':
						stringBuilder.Append('/');
						break;
					default:
						stringBuilder.Append(c2);
						break;
					}
					i += 2;
				}
				else
				{
					if (c == '"')
					{
						i++;
						break;
					}
					stringBuilder.Append(c);
					i++;
				}
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	internal static class LocalizationLanguageChangePatch
	{
		[HarmonyPostfix]
		internal static void Postfix(string language)
		{
			try
			{
				ModLocalization.OnLanguageChanged(language);
			}
			catch
			{
			}
		}
	}
	public static class NorseFontLoader
	{
		private static TMP_FontAsset _cached;

		private static bool _tried;

		public static TMP_FontAsset Load()
		{
			if (_tried)
			{
				return _cached;
			}
			_tried = true;
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string s) => s.EndsWith("Norse-Bold.ttf") || s.EndsWith("Norse-Bold"));
				if (text == null)
				{
					ItemDrawers.Instance.Log.LogInfo((object)"NorseFontLoader: Norse-Bold.ttf not found in embedded resources.");
					return null;
				}
				using Stream stream = executingAssembly.GetManifestResourceStream(text);
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				byte[] bytes = memoryStream.ToArray();
				string text2 = Path.Combine(Application.temporaryCachePath, "Cybrp_Norse-Bold.ttf");
				File.WriteAllBytes(text2, bytes);
				try
				{
					MethodInfo methodInfo = (from m in typeof(TMP_FontAsset).GetMethods(BindingFlags.Static | BindingFlags.Public)
						where m.Name == "CreateFontAsset" && m.GetParameters().Length == 7 && m.GetParameters()[0].ParameterType == typeof(string)
						select m).FirstOrDefault();
					if (methodInfo != null)
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						object[] array = new object[parameters.Length];
						array[0] = text2;
						array[1] = 0;
						array[2] = 90;
						array[3] = 9;
						Type parameterType = parameters[4].ParameterType;
						array[4] = Enum.ToObject(parameterType, 4165);
						array[5] = 1024;
						array[6] = 1024;
						object? obj = methodInfo.Invoke(null, array);
						TMP_FontAsset val = (TMP_FontAsset)((obj is TMP_FontAsset) ? obj : null);
						if ((Object)(object)val != (Object)null)
						{
							val.atlasPopulationMode = (AtlasPopulationMode)1;
							Object.DontDestroyOnLoad((Object)(object)val);
							_cached = val;
							ItemDrawers.Instance.Log.LogInfo((object)"NorseFontLoader: loaded Norse font via file path (Strategy 1).");
							return _cached;
						}
					}
				}
				catch (Exception ex)
				{
					ItemDrawers.Instance.Log.LogInfo((object)("NorseFontLoader: Strategy 1 failed (" + ex.Message + ")."));
				}
				try
				{
					Font val2 = Font.CreateDynamicFontFromOSFont(text2, 90);
					if ((Object)(object)val2 != (Object)null)
					{
						val2.RequestCharactersInTexture("0123456789", 90);
						MethodInfo method = typeof(TMP_FontAsset).GetMethod("CreateFontAsset", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Font) }, null);
						if (method != null)
						{
							object? obj2 = method.Invoke(null, new object[1] { val2 });
							TMP_FontAsset val3 = (TMP_FontAsset)((obj2 is TMP_FontAsset) ? obj2 : null);
							if ((Object)(object)val3 != (Object)null)
							{
								val3.atlasPopulationMode = (AtlasPopulationMode)1;
								Object.DontDestroyOnLoad((Object)(object)val3);
								Object.DontDestroyOnLoad((Object)(object)val2);
								_cached = val3;
								ItemDrawers.Instance.Log.LogInfo((object)"NorseFontLoader: loaded Norse font via Unity Font (Strategy 2).");
								return _cached;
							}
						}
					}
				}
				catch (Exception ex2)
				{
					ItemDrawers.Instance.Log.LogInfo((object)("NorseFontLoader: Strategy 2 failed (" + ex2.Message + ")."));
				}
				try
				{
					Font val4 = Font.CreateDynamicFontFromOSFont("Norse-Bold", 90);
					if ((Object)(object)val4 != (Object)null)
					{
						val4.RequestCharactersInTexture("0123456789", 90);
						MethodInfo method2 = typeof(TMP_FontAsset).GetMethod("CreateFontAsset", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Font) }, null);
						if (method2 != null)
						{
							object? obj3 = method2.Invoke(null, new object[1] { val4 });
							TMP_FontAsset val5 = (TMP_FontAsset)((obj3 is TMP_FontAsset) ? obj3 : null);
							if ((Object)(object)val5 != (Object)null)
							{
								val5.atlasPopulationMode = (AtlasPopulationMode)1;
								Object.DontDestroyOnLoad((Object)(object)val5);
								Object.DontDestroyOnLoad((Object)(object)val4);
								_cached = val5;
								ItemDrawers.Instance.Log.LogInfo((object)"NorseFontLoader: loaded Norse font via OS font name (Strategy 3).");
								return _cached;
							}
						}
					}
				}
				catch (Exception ex3)
				{
					ItemDrawers.Instance.Log.LogInfo((object)("NorseFontLoader: Strategy 3 failed (" + ex3.Message + ")."));
				}
				ItemDrawers.Instance.Log.LogInfo((object)"NorseFontLoader: all strategies failed, using default font with size/color changes only.");
				return null;
			}
			catch (Exception ex4)
			{
				ItemDrawers.Instance.Log.LogInfo((object)("NorseFontLoader: could not load Norse font (" + ex4.Message + "), using default font with size/color changes."));
				return null;
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake_Patch
	{
		private static readonly FieldInfo F_namedPrefabs = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs");

		private static readonly FieldInfo F_prefabs = AccessTools.Field(typeof(ZNetScene), "m_prefabs");

		[UsedImplicitly]
		private static void Postfix(ZNetScene __instance)
		{
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)F_namedPrefabs.GetValue(__instance);
			List<GameObject> list = (List<GameObject>)F_prefabs.GetValue(__instance);
			dictionary[StringExtensionMethods.GetStableHashCode(((Object)ItemDrawers.Explosion).name)] = ItemDrawers.Explosion;
			foreach (string allDrawerPrefabName in ItemDrawers.AllDrawerPrefabNames)
			{
				GameObject drawerPrefab = ItemDrawers.GetDrawerPrefab(allDrawerPrefabName);
				if ((Object)(object)drawerPrefab == (Object)null)
				{
					ItemDrawers.Instance.Log.LogWarning((object)("Drawer prefab '" + allDrawerPrefabName + "' not found in AssetBundle!"));
					continue;
				}
				Piece val = drawerPrefab.GetComponent<Piece>();
				if ((Object)(object)val == (Object)null)
				{
					val = drawerPrefab.AddComponent<Piece>();
				}
				if (allDrawerPrefabName.Contains("Wood") || allDrawerPrefabName.Contains("NoModel"))
				{
					GameObject prefab = __instance.GetPrefab("woodwall");
					if ((Object)(object)prefab != (Object)null)
					{
						val.m_placeEffect = prefab.GetComponent<Piece>().m_placeEffect;
					}
				}
				else if (allDrawerPrefabName.Contains("Stone"))
				{
					GameObject prefab2 = __instance.GetPrefab("stone_wall_1x1");
					if ((Object)(object)prefab2 != (Object)null)
					{
						val.m_placeEffect = prefab2.GetComponent<Piece>().m_placeEffect;
					}
				}
				else if (allDrawerPrefabName.Contains("Marble"))
				{
					GameObject prefab3 = __instance.GetPrefab("blackmarble_1x1");
					if ((Object)(object)prefab3 != (Object)null)
					{
						val.m_placeEffect = prefab3.GetComponent<Piece>().m_placeEffect;
					}
				}
				if ((Object)(object)drawerPrefab.GetComponent<DrawerComponent>() == (Object)null)
				{
					drawerPrefab.AddComponent<DrawerComponent>();
				}
				int stableHashCode = StringExtensionMethods.GetStableHashCode(allDrawerPrefabName);
				dictionary[stableHashCode] = drawerPrefab;
				if (!list.Contains(drawerPrefab))
				{
					list.Add(drawerPrefab);
				}
			}
			PieceCategory category = (PieceCategory)(((??)PieceManager.Instance.GetPieceCategory("itemdrawers")) ?? 4);
			foreach (string allDrawerPrefabName2 in ItemDrawers.AllDrawerPrefabNames)
			{
				GameObject drawerPrefab2 = ItemDrawers.GetDrawerPrefab(allDrawerPrefabName2);
				if (!((Object)(object)drawerPrefab2 == (Object)null))
				{
					Piece component = drawerPrefab2.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						component.m_category = category;
					}
				}
			}
			ItemDrawers.Instance.Log.LogInfo((object)$"Cybrp ItemDrawers: registered {ItemDrawers.AllDrawerPrefabNames.Count} drawer prefabs.");
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDB_Awake_Patch
	{
		[UsedImplicitly]
		private static void Postfix(ObjectDB __instance)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			if ((Object)(object)__instance.GetItemPrefab("YmirRemains") == (Object)null)
			{
				return;
			}
			GameObject itemPrefab = __instance.GetItemPrefab("Hammer");
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return;
			}
			PieceTable val = itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			IReadOnlyList<(string, string, int)> allDrawerRecipes = ItemDrawers.AllDrawerRecipes;
			IReadOnlyList<string> allDrawerPrefabNames = ItemDrawers.AllDrawerPrefabNames;
			for (int i = 0; i < allDrawerPrefabNames.Count && i < allDrawerRecipes.Count; i++)
			{
				string text = allDrawerPrefabNames[i];
				(string, string, int) tuple = allDrawerRecipes[i];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				int item3 = tuple.Item3;
				GameObject drawerPrefab = ItemDrawers.GetDrawerPrefab(text);
				if ((Object)(object)drawerPrefab == (Object)null)
				{
					continue;
				}
				Piece component = drawerPrefab.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				component.m_name