Decompiled source of Hutoheim v1.20.509

plugins/Hutoheim.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Hutoheim.Combat;
using Hutoheim.Convenience;
using Hutoheim.Equip;
using Hutoheim.Farm.Mining;
using Hutoheim.Farm.Plant;
using Hutoheim.Farm.Terrain;
using Hutoheim.Portal;
using Hutoheim.Storage;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: AssemblyTitle("Hutoheim")]
[assembly: AssemblyDescription("HutoChaWon 발헤임 모드: 상자, 포탈, 경험치, 전투, 농사·지형, 편의, 생산, 장비칸")]
[assembly: AssemblyCompany("HutoChaWon")]
[assembly: AssemblyProduct("Hutoheim")]
[assembly: AssemblyCopyright("Copyright © 2026 HutoChaWon")]
[assembly: AssemblyFileVersion("1.20.509.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("1.20.509.0")]
namespace Hutoheim.Storage
{
	internal sealed class MaterialPool : CraftChests.IMaterialSource
	{
		private readonly List<Container> _chests;

		private readonly Dictionary<string, List<ItemData>> _inv = new Dictionary<string, List<ItemData>>();

		private readonly Dictionary<string, List<KeyValuePair<Inventory, ItemData>>> _chest = new Dictionary<string, List<KeyValuePair<Inventory, ItemData>>>();

		public static bool Strict;

		private readonly Dictionary<Inventory, Container> _containerOf = new Dictionary<Inventory, Container>();

		public bool Dirty;

		private readonly HashSet<Inventory> _watched = new HashSet<Inventory>();

		private Inventory _playerInv;

		public int ChestCount { get; private set; }

		public MaterialPool(List<Container> chests)
		{
			_chests = chests;
			if (_chests != null)
			{
				foreach (Container chest in _chests)
				{
					Inventory val = ((!((Object)(object)chest != (Object)null)) ? null : chest.GetInventory());
					if (val != null)
					{
						_watched.Add(val);
					}
				}
			}
			Reindex();
		}

		private bool Ok(Inventory inv)
		{
			if (!Strict)
			{
				return true;
			}
			Container value;
			return inv != null && _containerOf.TryGetValue(inv, out value) && ContainerAccess.StillOwned(value);
		}

		private void Fresh()
		{
			if (Dirty)
			{
				Reindex();
			}
		}

		public bool Concerns(Inventory inv)
		{
			if (inv == null)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && inv == ((Humanoid)localPlayer).GetInventory())
			{
				return true;
			}
			if (inv == _playerInv)
			{
				return true;
			}
			return _watched.Contains(inv);
		}

		public static bool UsableInPlayer(ItemData it)
		{
			if (it == null || it.m_equipped)
			{
				return false;
			}
			if (SlotLocks.IsLocked(it))
			{
				return false;
			}
			if (Api.IsSlotItem(it))
			{
				return false;
			}
			return true;
		}

		public void Reindex()
		{
			Dirty = false;
			foreach (List<ItemData> value3 in _inv.Values)
			{
				value3.Clear();
			}
			foreach (List<KeyValuePair<Inventory, ItemData>> value4 in _chest.Values)
			{
				value4.Clear();
			}
			if (_inv.Count > 2000)
			{
				_inv.Clear();
			}
			if (_chest.Count > 2000)
			{
				_chest.Clear();
			}
			ChestCount = 0;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			_playerInv = ((Humanoid)localPlayer).GetInventory();
			foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
			{
				if (UsableInPlayer(allItem))
				{
					if (!_inv.TryGetValue(allItem.m_shared.m_name, out var value))
					{
						value = (_inv[allItem.m_shared.m_name] = new List<ItemData>());
					}
					value.Add(allItem);
				}
			}
			if (_chests == null)
			{
				return;
			}
			foreach (Container chest in _chests)
			{
				if (!ContainerAccess.IsValid(chest))
				{
					continue;
				}
				Inventory inventory = chest.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				_watched.Add(inventory);
				_containerOf[inventory] = chest;
				ChestCount++;
				foreach (ItemData allItem2 in inventory.GetAllItems())
				{
					if (!_chest.TryGetValue(allItem2.m_shared.m_name, out var value2))
					{
						value2 = (_chest[allItem2.m_shared.m_name] = new List<KeyValuePair<Inventory, ItemData>>());
					}
					value2.Add(new KeyValuePair<Inventory, ItemData>(inventory, allItem2));
				}
			}
		}

		private static bool Match(ItemData it, int quality, bool matchWorldLevel)
		{
			if (quality >= 0 && it.m_quality != quality)
			{
				return false;
			}
			if (matchWorldLevel && it.m_worldLevel < Game.m_worldLevel)
			{
				return false;
			}
			return it.m_stack > 0;
		}

		public int InvCount(string name, int quality, bool mwl)
		{
			Fresh();
			int num = 0;
			if (name != null && _inv.TryGetValue(name, out var value))
			{
				foreach (ItemData item in value)
				{
					if (Match(item, quality, mwl))
					{
						num += item.m_stack;
					}
				}
			}
			return num;
		}

		public int BoxCount(string name, int quality, bool mwl)
		{
			Fresh();
			int num = 0;
			if (name != null && _chest.TryGetValue(name, out var value))
			{
				foreach (KeyValuePair<Inventory, ItemData> item in value)
				{
					if (Ok(item.Key) && Match(item.Value, quality, mwl))
					{
						num += item.Value.m_stack;
					}
				}
			}
			return num;
		}

		public int Count(string name, int quality, bool matchWorldLevel)
		{
			return InvCount(name, quality, matchWorldLevel) + BoxCount(name, quality, matchWorldLevel);
		}

		public bool Have(string name, bool matchWorldLevel)
		{
			return Count(name, -1, matchWorldLevel) > 0;
		}

		public ItemData Get(string name, int quality, bool isPrefabName)
		{
			Fresh();
			if (name == null)
			{
				return null;
			}
			if (!isPrefabName)
			{
				if (_inv.TryGetValue(name, out var value))
				{
					foreach (ItemData item in value)
					{
						if (Match(item, quality, matchWorldLevel: true))
						{
							return item;
						}
					}
				}
				if (_chest.TryGetValue(name, out var value2))
				{
					foreach (KeyValuePair<Inventory, ItemData> item2 in value2)
					{
						if (Ok(item2.Key) && Match(item2.Value, quality, matchWorldLevel: true))
						{
							return item2.Value;
						}
					}
				}
				return null;
			}
			foreach (List<ItemData> value3 in _inv.Values)
			{
				foreach (ItemData item3 in value3)
				{
					if ((Object)(object)item3.m_dropPrefab != (Object)null && ((Object)item3.m_dropPrefab).name == name && Match(item3, quality, matchWorldLevel: true))
					{
						return item3;
					}
				}
			}
			foreach (List<KeyValuePair<Inventory, ItemData>> value4 in _chest.Values)
			{
				foreach (KeyValuePair<Inventory, ItemData> item4 in value4)
				{
					if (Ok(item4.Key) && (Object)(object)item4.Value.m_dropPrefab != (Object)null && ((Object)item4.Value.m_dropPrefab).name == name && Match(item4.Value, quality, matchWorldLevel: true))
					{
						return item4.Value;
					}
				}
			}
			return null;
		}

		public List<Container> ChestsToAcquire(Recipe r, int quality, int mult)
		{
			List<Container> list = new List<Container>();
			if ((Object)(object)r == (Object)null || r.m_resources == null)
			{
				return list;
			}
			Fresh();
			bool requireOnlyOneIngredient = r.m_requireOnlyOneIngredient;
			int mult2 = Math.Max(1, mult);
			if (requireOnlyOneIngredient)
			{
				Requirement[] resources = r.m_resources;
				foreach (Requirement val in resources)
				{
					int num = Amount(val, quality, mult2, onlyOne: true);
					if (num > 0 && OwnedCount(val.m_resItem.m_itemData.m_shared.m_name) >= num)
					{
						return list;
					}
				}
				Requirement[] resources2 = r.m_resources;
				foreach (Requirement val2 in resources2)
				{
					int num2 = Amount(val2, quality, mult2, onlyOne: true);
					if (num2 <= 0)
					{
						continue;
					}
					string name = val2.m_resItem.m_itemData.m_shared.m_name;
					int num3 = OwnedCount(name);
					int num4 = 0;
					foreach (Container chest in _chests)
					{
						if (!((Object)(object)chest == (Object)null) && !ContainerAccess.StillOwned(chest))
						{
							Inventory inventory = chest.GetInventory();
							if (inventory != null)
							{
								num4 += inventory.CountItems(name, -1, false);
							}
						}
					}
					if (num3 + num4 >= num2)
					{
						AddChestsFor(name, num2, num3, list);
						return list;
					}
				}
				return list;
			}
			Requirement[] resources3 = r.m_resources;
			foreach (Requirement val3 in resources3)
			{
				int num5 = Amount(val3, quality, mult2, onlyOne: false);
				if (num5 > 0)
				{
					string name2 = val3.m_resItem.m_itemData.m_shared.m_name;
					int num6 = OwnedCount(name2);
					if (num6 < num5)
					{
						AddChestsFor(name2, num5, num6, list);
					}
				}
			}
			return list;
		}

		private static int Amount(Requirement req, int quality, int mult, bool onlyOne)
		{
			if (req == null || (Object)(object)req.m_resItem == (Object)null)
			{
				return 0;
			}
			int num = req.GetAmount(quality);
			if (onlyOne)
			{
				num += Math.Max(0, req.m_extraAmountOnlyOneIngredient);
			}
			return num * mult;
		}

		private int OwnedCount(string name)
		{
			int num = 0;
			for (int i = 1; i <= 10; i++)
			{
				int num2 = InvCount(name, i, mwl: true);
				if (_chest.TryGetValue(name, out var value))
				{
					foreach (KeyValuePair<Inventory, ItemData> item in value)
					{
						if (Match(item.Value, i, matchWorldLevel: true) && _containerOf.TryGetValue(item.Key, out var value2) && ContainerAccess.StillOwned(value2))
						{
							num2 += item.Value.m_stack;
						}
					}
				}
				if (num2 > num)
				{
					num = num2;
				}
			}
			return num;
		}

		private void AddChestsFor(string name, int amount, int have, List<Container> need)
		{
			foreach (Container chest in _chests)
			{
				if (have >= amount)
				{
					break;
				}
				if ((Object)(object)chest == (Object)null || ContainerAccess.StillOwned(chest) || need.Contains(chest))
				{
					continue;
				}
				Inventory inventory = chest.GetInventory();
				if (inventory != null)
				{
					int num = inventory.CountItems(name, -1, false);
					if (num > 0)
					{
						need.Add(chest);
						have += num;
					}
				}
			}
		}

		public void Remove(string name, int amount, int quality, bool worldLevelBased)
		{
			Fresh();
			if (amount <= 0 || name == null)
			{
				return;
			}
			int num = amount;
			Player localPlayer = Player.m_localPlayer;
			Inventory val = ((!((Object)(object)localPlayer != (Object)null)) ? null : ((Humanoid)localPlayer).GetInventory());
			if (val != null && _inv.TryGetValue(name, out var value))
			{
				foreach (ItemData item in new List<ItemData>(value))
				{
					if (num <= 0)
					{
						break;
					}
					if (Match(item, quality, worldLevelBased) && val.ContainsItem(item))
					{
						int num2 = Math.Min(item.m_stack, num);
						if (val.RemoveItem(item, num2))
						{
							num -= num2;
						}
					}
				}
			}
			if (num > 0 && _chest.TryGetValue(name, out var value2))
			{
				value2 = new List<KeyValuePair<Inventory, ItemData>>(value2);
				foreach (Container chest in _chests)
				{
					if (num <= 0)
					{
						break;
					}
					if (!ContainerAccess.StillOwned(chest))
					{
						continue;
					}
					Inventory inventory = chest.GetInventory();
					foreach (KeyValuePair<Inventory, ItemData> item2 in value2)
					{
						if (num <= 0)
						{
							break;
						}
						if (item2.Key != inventory)
						{
							continue;
						}
						ItemData value3 = item2.Value;
						if (Match(value3, quality, worldLevelBased) && inventory.ContainsItem(value3))
						{
							int num3 = Math.Min(value3.m_stack, num);
							if (inventory.RemoveItem(value3, num3))
							{
								num -= num3;
							}
						}
					}
				}
			}
			if (num > 0)
			{
				Plugin.Warn("제작: " + name + " " + num + "개를 찾지 못했습니다 (그사이 내용이 바뀜).");
			}
			Reindex();
		}
	}
	internal static class CraftBridge
	{
		private static readonly FieldInfo F_allStations = AccessTools.Field(typeof(CraftingStation), "m_allStations");

		private static readonly FieldInfo F_stationNview = AccessTools.Field(typeof(CraftingStation), "m_nview");

		private static readonly Func<CraftingStation, ZNetView> G_stationNview = Fast.Getter<CraftingStation, ZNetView>(F_stationNview);

		private static readonly FieldInfo F_haveFire = AccessTools.Field(typeof(CraftingStation), "m_haveFire");

		public static IEnumerable<CraftingStation> AllStations()
		{
			IEnumerable list = ((!(F_allStations != null)) ? null : (F_allStations.GetValue(null) as IEnumerable));
			if (list == null)
			{
				list = Object.FindObjectsByType<CraftingStation>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			}
			IEnumerator enumerator = list.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					object o = enumerator.Current;
					CraftingStation s = (CraftingStation)((o is CraftingStation) ? o : null);
					if ((Object)(object)s != (Object)null)
					{
						yield return s;
					}
				}
			}
			finally
			{
				IDisposable disposable2;
				IDisposable disposable = (disposable2 = enumerator as IDisposable);
				if (disposable2 != null)
				{
					disposable.Dispose();
				}
			}
		}

		public static bool IsValid(CraftingStation s)
		{
			if ((Object)(object)s == (Object)null || !((Behaviour)s).isActiveAndEnabled)
			{
				return false;
			}
			if (F_stationNview == null)
			{
				return true;
			}
			ZNetView val = (ZNetView)((G_stationNview == null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)G_stationNview(s)));
			return (Object)(object)val != (Object)null && val.IsValid();
		}

		public static string WhyUnusable(CraftingStation s)
		{
			bool flag = false;
			try
			{
				flag = F_haveFire != null && (bool)F_haveFire.GetValue(s);
			}
			catch
			{
			}
			if (s.m_craftRequireFire && !flag)
			{
				return "불 필요";
			}
			if (s.m_craftRequireRoof)
			{
				return "지붕 필요";
			}
			return "사용 불가";
		}
	}
	internal static class CraftSort
	{
		private sealed class IKey
		{
			public int Cat;

			public int Sub;

			public int G;

			public int Tab;

			public string Set;

			public float Tier;

			public float SetTier;

			public string Name;
		}

		private sealed class Key
		{
			public Recipe R;

			public ItemData Up;

			public GameObject El;

			public bool Can;

			public int Quality;

			public int Index;

			public int G;

			public int Tab;

			public int Part;

			public string Group;

			public float Tier;

			public string Name;

			public string St;

			public float StRank;

			public float Unit;
		}

		private sealed class RInfo
		{
			public int Cat;

			public int Sub;

			public int G;

			public int Tab;

			public int Part;

			public float Tier;

			public string Name;

			public string Group;
		}

		private static readonly Dictionary<string, float> MatTier = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Wood", 10f },
			{ "Stone", 10f },
			{ "Flint", 10f },
			{ "LeatherScraps", 10f },
			{ "DeerHide", 10f },
			{ "Resin", 10f },
			{ "Feathers", 10f },
			{ "Raspberry", 10f },
			{ "Mushroom", 10f },
			{ "Honey", 10f },
			{ "BoneFragments", 10f },
			{ "NeckTail", 10f },
			{ "Dandelion", 10f },
			{ "RawMeat", 10f },
			{ "DeerMeat", 10f },
			{ "HardAntler", 15f },
			{ "TrophyDeer", 10f },
			{ "TrophyBoar", 10f },
			{ "GreydwarfEye", 20f },
			{ "Blueberries", 20f },
			{ "AncientSeed", 20f },
			{ "TrollHide", 21f },
			{ "Coal", 21f },
			{ "Thistle", 21f },
			{ "CarrotSeeds", 21f },
			{ "Carrot", 21f },
			{ "CopperOre", 21f },
			{ "TinOre", 21f },
			{ "Copper", 22f },
			{ "Tin", 22f },
			{ "Bronze", 23f },
			{ "BronzeNails", 23f },
			{ "FineWood", 24f },
			{ "CryptKey", 25f },
			{ "SurtlingCore", 24f },
			{ "BjornHide", 21f },
			{ "BjornMeat", 21f },
			{ "BjornPaw", 21f },
			{ "MushroomYellow", 21f },
			{ "RoundLog", 25f },
			{ "Guck", 31f },
			{ "Entrails", 31f },
			{ "Bloodbag", 31f },
			{ "Ooze", 31f },
			{ "Root", 31f },
			{ "TurnipSeeds", 31f },
			{ "Turnip", 31f },
			{ "WitheredBone", 31f },
			{ "IronScrap", 31f },
			{ "Iron", 32f },
			{ "IronNails", 32f },
			{ "Chain", 32f },
			{ "ElderBark", 33f },
			{ "Wishbone", 35f },
			{ "SerpentScale", 37f },
			{ "SerpentMeat", 37f },
			{ "Chitin", 37f },
			{ "SilverOre", 41f },
			{ "WolfPelt", 41f },
			{ "WolfFang", 41f },
			{ "Obsidian", 41f },
			{ "FreezeGland", 41f },
			{ "OnionSeeds", 41f },
			{ "Onion", 41f },
			{ "WolfMeat", 41f },
			{ "WolfClaw", 41f },
			{ "Silver", 42f },
			{ "Crystal", 42f },
			{ "JuteRed", 42f },
			{ "DragonEgg", 45f },
			{ "DragonTear", 45f },
			{ "TrophyHatchling", 41f },
			{ "Barley", 51f },
			{ "Flax", 51f },
			{ "BarleyFlour", 51f },
			{ "LoxPelt", 51f },
			{ "LoxMeat", 51f },
			{ "Needle", 51f },
			{ "Tar", 51f },
			{ "GoblinTotem", 51f },
			{ "Cloudberry", 51f },
			{ "BlackMetalScrap", 51f },
			{ "BlackMetal", 52f },
			{ "LinenThread", 52f },
			{ "YagluthDrop", 55f },
			{ "TrophyGoblin", 51f },
			{ "Carapace", 61f },
			{ "Sap", 61f },
			{ "YggdrasilWood", 61f },
			{ "BlackMarble", 61f },
			{ "ScaleHide", 61f },
			{ "BugMeat", 61f },
			{ "RoyalJelly", 61f },
			{ "Wisp", 61f },
			{ "GiantBloodSack", 61f },
			{ "Softtissue", 62f },
			{ "BlackCore", 62f },
			{ "JuteBlue", 62f },
			{ "Mandible", 62f },
			{ "Eitr", 63f },
			{ "QueenDrop", 65f },
			{ "MushroomJotunPuffs", 61f },
			{ "MushroomMagecap", 61f },
			{ "DvergrNeedle", 62f },
			{ "Bilebag", 61f },
			{ "FlametalOre", 71f },
			{ "FlametalOreNew", 71f },
			{ "CharredBone", 71f },
			{ "AskHide", 71f },
			{ "Blackwood", 71f },
			{ "Grausten", 71f },
			{ "Charredskull", 71f },
			{ "AsksvinMeat", 71f },
			{ "Vineberry", 71f },
			{ "VineberrySeeds", 71f },
			{ "Fiddleheadfern", 71f },
			{ "SulfurStone", 71f },
			{ "Flametal", 72f },
			{ "FlametalNew", 72f },
			{ "MoltenCore", 72f },
			{ "CelestialFeather", 72f },
			{ "ProustitePowder", 72f },
			{ "CeramicPlate", 72f },
			{ "MorgenSinew", 72f },
			{ "MorgenHeart", 72f },
			{ "BellFragment", 72f },
			{ "FaderDrop", 75f }
		};

		private static readonly Dictionary<string, float> StationTier = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase)
		{
			{ "piece_workbench", 10f },
			{ "piece_cauldron", 22f },
			{ "forge", 22f },
			{ "piece_stonecutter", 32f },
			{ "piece_artisanstation", 45f },
			{ "blackforge", 61f },
			{ "piece_magetable", 61f },
			{ "piece_preptable", 62f },
			{ "piece_MeadCauldron", 62f }
		};

		private static readonly Dictionary<string, float> _tierCache = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

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

		private static ObjectDB _cacheFor;

		private static readonly Dictionary<SharedData, IKey> _ikeys = new Dictionary<SharedData, IKey>();

		private static readonly Dictionary<string, float> _setTier = new Dictionary<string, float>();

		private static readonly Dictionary<Recipe, RInfo> _rinfo = new Dictionary<Recipe, RInfo>();

		private static readonly FieldInfo F_list = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

		private static readonly List<Key> _keys = new List<Key>();

		private static readonly List<Key> _keyPool = new List<Key>();

		private static readonly Dictionary<string, float> _applySetTier = new Dictionary<string, float>();

		private static readonly Comparison<Key> ByKey = delegate(Key a, Key b)
		{
			int num = Avail(a).CompareTo(Avail(b));
			if (num != 0)
			{
				return num;
			}
			num = b.StRank.CompareTo(a.StRank);
			if (num != 0)
			{
				return num;
			}
			num = string.CompareOrdinal(a.St, b.St);
			if (num != 0)
			{
				return num;
			}
			num = b.Unit.CompareTo(a.Unit);
			if (num != 0)
			{
				return num;
			}
			num = string.CompareOrdinal(a.Group, b.Group);
			if (num != 0)
			{
				return num;
			}
			if (a.Group.Length > 0)
			{
				num = a.Part.CompareTo(b.Part);
				if (num != 0)
				{
					return num;
				}
			}
			num = a.G.CompareTo(b.G);
			if (num != 0)
			{
				return num;
			}
			if (a.G == int.MaxValue)
			{
				num = string.Compare(a.Name, b.Name, StringComparison.CurrentCulture);
				if (num != 0)
				{
					return num;
				}
			}
			num = a.Quality.CompareTo(b.Quality);
			return (num != 0) ? num : a.Index.CompareTo(b.Index);
		};

		private static readonly Comparison<Key> ByCategory = delegate(Key a, Key b)
		{
			int num = Avail(a).CompareTo(Avail(b));
			if (num != 0)
			{
				return num;
			}
			num = a.Tab.CompareTo(b.Tab);
			if (num != 0)
			{
				return num;
			}
			num = a.G.CompareTo(b.G);
			if (num != 0)
			{
				return num;
			}
			if (a.G == int.MaxValue)
			{
				num = b.Unit.CompareTo(a.Unit);
				if (num != 0)
				{
					return num;
				}
				num = string.CompareOrdinal(a.Group, b.Group);
				if (num != 0)
				{
					return num;
				}
				if (a.Group.Length > 0)
				{
					num = a.Part.CompareTo(b.Part);
					if (num != 0)
					{
						return num;
					}
				}
				num = string.Compare(a.Name, b.Name, StringComparison.CurrentCulture);
				if (num != 0)
				{
					return num;
				}
			}
			num = a.Quality.CompareTo(b.Quality);
			return (num != 0) ? num : a.Index.CompareTo(b.Index);
		};

		private static float Tier(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return 0f;
			}
			if (MatTier.TryGetValue(prefab, out var value))
			{
				return value;
			}
			if (_tierCache.TryGetValue(prefab, out value))
			{
				return value;
			}
			if (!_visiting.Add(prefab))
			{
				return 0f;
			}
			value = 0f;
			try
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
				ItemDrop val = ((!((Object)(object)itemPrefab != (Object)null)) ? null : itemPrefab.GetComponent<ItemDrop>());
				Recipe val2 = ((!((Object)(object)val != (Object)null)) ? null : ObjectDB.instance.GetRecipe(val.m_itemData));
				if ((Object)(object)val2 != (Object)null)
				{
					value = RecipeTier(val2, 1);
				}
			}
			catch
			{
			}
			_visiting.Remove(prefab);
			_tierCache[prefab] = value;
			return value;
		}

		private static float RecipeTier(Recipe r, int quality)
		{
			float num = 0f;
			CraftingStation requiredStation = r.GetRequiredStation(quality);
			if ((Object)(object)requiredStation != (Object)null)
			{
				if (StationTier.TryGetValue(Utils.GetPrefabName(((Component)requiredStation).gameObject), out var value))
				{
					num = value;
				}
				num += (float)Mathf.Max(0, r.GetRequiredStationLevel(quality) - 1) * 0.3f;
			}
			if (r.m_resources != null)
			{
				Requirement[] resources = r.m_resources;
				foreach (Requirement val in resources)
				{
					if (val == null || (Object)(object)val.m_resItem == (Object)null)
					{
						continue;
					}
					bool num2;
					if (quality > 1)
					{
						if (val.m_amountPerLevel > 0)
						{
							goto IL_00cb;
						}
						num2 = val.m_amount <= 0;
					}
					else
					{
						num2 = val.m_amount <= 0;
					}
					if (num2)
					{
						continue;
					}
					goto IL_00cb;
					IL_00cb:
					num = Mathf.Max(num, Tier(Utils.GetPrefabName(((Component)val.m_resItem).gameObject)));
				}
			}
			return num;
		}

		internal static int Category(SharedData sh, out int sub)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected I4, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected I4, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Invalid comparison between Unknown and I4
			sub = 0;
			ItemType itemType = sh.m_itemType;
			switch (itemType - 1)
			{
			case 2:
			case 3:
			case 13:
			case 19:
			case 21:
			{
				SkillType skillType = sh.m_skillType;
				switch (skillType - 1)
				{
				default:
					if ((int)skillType == 104)
					{
						sub = 3;
						return 5;
					}
					sub = 30;
					return 0;
				case 0:
					sub = 1;
					return 0;
				case 1:
					sub = 2;
					return 0;
				case 6:
					sub = 3;
					return 0;
				case 2:
					sub = 4;
					return 0;
				case 4:
					sub = 5;
					return 0;
				case 3:
					sub = 6;
					return 0;
				case 10:
					sub = 7;
					return 0;
				case 7:
					sub = 10;
					return 0;
				case 13:
					sub = 11;
					return 0;
				case 8:
					sub = 20;
					return 0;
				case 9:
					sub = 21;
					return 0;
				case 11:
					sub = 1;
					return 5;
				case 12:
					sub = 2;
					return 5;
				}
			}
			case 4:
				return 1;
			case 5:
				sub = 1;
				return 2;
			case 6:
				sub = 2;
				return 2;
			case 10:
				sub = 3;
				return 2;
			case 11:
				sub = 4;
				return 2;
			case 16:
				sub = 5;
				return 2;
			case 17:
				sub = 1;
				return 3;
			case 23:
				sub = 2;
				return 3;
			case 8:
			case 22:
				return 4;
			case 14:
			case 18:
				return 5;
			case 1:
				return (!(sh.m_food > 0f) && !(sh.m_foodStamina > 0f) && !(sh.m_foodEitr > 0f)) ? 8 : 6;
			case 0:
				return 9;
			case 20:
				return 6;
			case 12:
				return 11;
			default:
				return 10;
			}
		}

		private static float ItemTier(ItemData it)
		{
			string text = ((!((Object)(object)it.m_dropPrefab != (Object)null)) ? null : ((Object)it.m_dropPrefab).name);
			if (!string.IsNullOrEmpty(text))
			{
				return Tier(text);
			}
			try
			{
				Recipe recipe = ObjectDB.instance.GetRecipe(it);
				return (!((Object)(object)recipe != (Object)null)) ? 0f : RecipeTier(recipe, 1);
			}
			catch
			{
				return 0f;
			}
		}

		private static float SetTier(string set, float fallback)
		{
			if (_setTier.TryGetValue(set, out var value))
			{
				return value;
			}
			value = fallback;
			try
			{
				foreach (GameObject item in ObjectDB.instance.m_items)
				{
					ItemDrop val = ((!((Object)(object)item != (Object)null)) ? null : item.GetComponent<ItemDrop>());
					if (!((Object)(object)val == (Object)null) && !(val.m_itemData.m_shared.m_setName != set))
					{
						float num = Tier(((Object)item).name);
						if (num > 0f && num < value)
						{
							value = num;
						}
					}
				}
			}
			catch
			{
			}
			_setTier[set] = value;
			return value;
		}

		private static IKey KeyOf(ItemData it)
		{
			EnsureCache();
			if (_ikeys.TryGetValue(it.m_shared, out var value))
			{
				return value;
			}
			value = new IKey();
			value.Cat = Category(it.m_shared, out value.Sub);
			value.G = GuideOrder.Of((!((Object)(object)it.m_dropPrefab != (Object)null)) ? null : ((Object)it.m_dropPrefab).name);
			value.Tab = ((value.G == int.MaxValue) ? GuideOrder.TabOfCategory(value.Cat) : (value.G / 1000000));
			value.Name = ContainerAccess.Localize(it.m_shared.m_name);
			value.Set = string.Empty;
			if (value.G == int.MaxValue)
			{
				value.Tier = ((!((Object)(object)ObjectDB.instance != (Object)null)) ? 0f : ItemTier(it));
				value.Set = ((value.Cat != 2 || string.IsNullOrEmpty(it.m_shared.m_setName)) ? string.Empty : it.m_shared.m_setName);
				value.SetTier = ((value.Set.Length <= 0) ? value.Tier : SetTier(value.Set, value.Tier));
			}
			_ikeys[it.m_shared] = value;
			return value;
		}

		public static int CompareItems(ItemData a, ItemData b)
		{
			IKey key = KeyOf(a);
			IKey key2 = KeyOf(b);
			int num = key.Tab.CompareTo(key2.Tab);
			if (num != 0)
			{
				return num;
			}
			num = key.G.CompareTo(key2.G);
			if (num != 0)
			{
				return num;
			}
			if (key.G != int.MaxValue)
			{
				return a.m_quality.CompareTo(b.m_quality);
			}
			num = key.Cat.CompareTo(key2.Cat);
			if (num != 0)
			{
				return num;
			}
			if (key.Cat == 2)
			{
				num = key2.SetTier.CompareTo(key.SetTier);
				if (num != 0)
				{
					return num;
				}
				num = string.CompareOrdinal(key.Set, key2.Set);
				if (num != 0)
				{
					return num;
				}
				num = key.Sub.CompareTo(key2.Sub);
				if (num != 0)
				{
					return num;
				}
			}
			else
			{
				num = key.Sub.CompareTo(key2.Sub);
				if (num != 0)
				{
					return num;
				}
				num = key2.Tier.CompareTo(key.Tier);
				if (num != 0)
				{
					return num;
				}
			}
			num = string.Compare(key.Name, key2.Name, StringComparison.CurrentCulture);
			if (num != 0)
			{
				return num;
			}
			return a.m_quality.CompareTo(b.m_quality);
		}

		private static void EnsureCache()
		{
			if (!((Object)(object)ObjectDB.instance == (Object)(object)_cacheFor))
			{
				_cacheFor = ObjectDB.instance;
				_tierCache.Clear();
				_ikeys.Clear();
				_setTier.Clear();
				_rinfo.Clear();
			}
		}

		private static RInfo InfoOf(Recipe r)
		{
			if (_rinfo.TryGetValue(r, out var value))
			{
				return value;
			}
			RInfo rInfo = new RInfo();
			rInfo.Group = string.Empty;
			rInfo.Name = string.Empty;
			value = rInfo;
			SharedData shared = r.m_item.m_itemData.m_shared;
			value.Cat = Category(shared, out value.Sub);
			value.G = GuideOrder.Of(Utils.GetPrefabName(((Component)r.m_item).gameObject));
			value.Tab = ((value.G == int.MaxValue) ? GuideOrder.TabOfCategory(value.Cat) : (value.G / 1000000));
			value.Name = ContainerAccess.Localize(shared.m_name);
			string prefabName = Utils.GetPrefabName(((Component)r.m_item).gameObject);
			float num = GuideOrder.RankOf(prefabName);
			value.Tier = ((!(num >= 0f)) ? RecipeTier(r, 1) : num);
			if (GuideOrder.Set.TryGetValue(prefabName, out var value2))
			{
				value.Group = value2.Key;
				value.Part = value2.Value;
			}
			else if (value.Cat == 2 && !string.IsNullOrEmpty(shared.m_setName))
			{
				value.Group = shared.m_setName;
				value.Part = value.Sub;
			}
			_rinfo[r] = value;
			return value;
		}

		private static int Avail(Key k)
		{
			return CraftSearch.IsUnknown(k.R) ? 2 : ((!k.Can) ? 1 : 0);
		}

		private static float StationRank(string st)
		{
			if (GuideOrder.Station.TryGetValue(st, out var value))
			{
				return value;
			}
			if (StationTier.TryGetValue(st, out value))
			{
				return value;
			}
			return 0f;
		}

		public static void Apply(InventoryGui gui, bool byCategory)
		{
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			EnsureCache();
			IList list = ((!(F_list != null)) ? null : (F_list.GetValue(gui) as IList));
			if (list == null || list.Count < 2 || !RecipePairs.Init(list))
			{
				return;
			}
			List<Key> keys = _keys;
			keys.Clear();
			for (int i = 0; i < list.Count; i++)
			{
				if (_keyPool.Count <= i)
				{
					_keyPool.Add(new Key());
				}
				Key key = _keyPool[i];
				RecipePairs.Read(list, i, out key.R, out key.Up, out key.El, out key.Can);
				key.Index = i;
				key.Group = string.Empty;
				key.Name = string.Empty;
				key.Quality = 0;
				key.Tier = 0f;
				key.Part = 0;
				key.St = string.Empty;
				key.StRank = -1f;
				Recipe r = key.R;
				if ((Object)(object)r != (Object)null && (Object)(object)r.m_item != (Object)null)
				{
					RInfo rInfo = InfoOf(r);
					key.Tier = rInfo.Tier;
					key.Name = rInfo.Name;
					key.Group = rInfo.Group;
					key.G = rInfo.G;
					key.Tab = rInfo.Tab;
					key.Part = rInfo.Part;
					key.Quality = ((key.Up == null) ? 1 : (key.Up.m_quality + 1));
					CraftingStation val = null;
					try
					{
						val = r.GetRequiredStation(key.Quality);
					}
					catch
					{
					}
					if ((Object)(object)val != (Object)null)
					{
						key.St = Utils.GetPrefabName(((Component)val).gameObject);
						key.StRank = StationRank(key.St);
					}
				}
				else
				{
					key.G = int.MaxValue;
					key.Tab = 99;
				}
				keys.Add(key);
			}
			Dictionary<string, float> applySetTier = _applySetTier;
			applySetTier.Clear();
			for (int j = 0; j < keys.Count; j++)
			{
				Key key2 = keys[j];
				if (key2.Group.Length != 0)
				{
					string key3 = key2.St + "\u0001" + key2.Group;
					applySetTier[key3] = ((!applySetTier.TryGetValue(key3, out var value)) ? key2.Tier : Mathf.Max(value, key2.Tier));
				}
			}
			for (int k = 0; k < keys.Count; k++)
			{
				Key key4 = keys[k];
				key4.Unit = ((key4.Group.Length <= 0) ? key4.Tier : applySetTier[key4.St + "\u0001" + key4.Group]);
			}
			keys.Sort((!byCategory) ? ByKey : ByCategory);
			float recipeListSpace = gui.m_recipeListSpace;
			for (int l = 0; l < keys.Count; l++)
			{
				Key key5 = keys[l];
				if (key5.Index != l)
				{
					RecipePairs.Write(list, l, key5.R, key5.Up, key5.El, key5.Can);
				}
				RectTransform val2 = (RectTransform)((!((Object)(object)key5.El != (Object)null)) ? null : /*isinst with value type is only supported in some contexts*/);
				if ((Object)(object)val2 != (Object)null)
				{
					val2.anchoredPosition = new Vector2(0f, (float)l * (0f - recipeListSpace));
				}
				key5.R = null;
				key5.Up = null;
				key5.El = null;
			}
			keys.Clear();
		}
	}
	internal static class RecipePairs
	{
		public delegate void ReadFn(object list, int i, out Recipe r, out ItemData it, out GameObject el, out bool can);

		public delegate void WriteFn(object list, int i, Recipe r, ItemData it, GameObject el, bool can);

		public static ReadFn Read;

		public static WriteFn Write;

		private static Type _for;

		public static bool Init(IList list)
		{
			if (list == null)
			{
				return false;
			}
			Type type = list.GetType();
			if (type == _for)
			{
				return Read != null && Write != null;
			}
			_for = type;
			Read = null;
			Write = null;
			Type type2 = (type.IsGenericType ? type.GetGenericArguments()[0] : ((list.Count <= 0 || list[0] == null) ? null : list[0].GetType()));
			if (type2 == null)
			{
				_for = null;
				return false;
			}
			PropertyInfo property = type2.GetProperty("Recipe");
			PropertyInfo property2 = type2.GetProperty("ItemData");
			PropertyInfo property3 = type2.GetProperty("InterfaceElement");
			PropertyInfo property4 = type2.GetProperty("CanCraft");
			ConstructorInfo constructor = type2.GetConstructor(new Type[4]
			{
				typeof(Recipe),
				typeof(ItemData),
				typeof(GameObject),
				typeof(bool)
			});
			if (property == null || property3 == null || property4 == null || constructor == null)
			{
				return false;
			}
			try
			{
				Emit(type, type2, property, property2, property3, property4, constructor);
			}
			catch
			{
				Read = null;
				Write = null;
			}
			if (Read == null || Write == null)
			{
				Fallback(property, property2, property3, property4, constructor);
			}
			return Read != null && Write != null;
		}

		private static void Emit(Type lt, Type pt, PropertyInfo pR, PropertyInfo pI, PropertyInfo pE, PropertyInfo pC, ConstructorInfo ctor)
		{
			if (lt.IsGenericType && pt.IsValueType && !(pI == null))
			{
				MethodInfo method = lt.GetMethod("get_Item", new Type[1] { typeof(int) });
				MethodInfo method2 = lt.GetMethod("set_Item", new Type[2]
				{
					typeof(int),
					pt
				});
				MethodInfo getMethod = pR.GetGetMethod(nonPublic: true);
				MethodInfo getMethod2 = pI.GetGetMethod(nonPublic: true);
				MethodInfo getMethod3 = pE.GetGetMethod(nonPublic: true);
				MethodInfo getMethod4 = pC.GetGetMethod(nonPublic: true);
				if (!(method == null) && !(method2 == null) && !(getMethod == null) && !(getMethod2 == null) && !(getMethod3 == null) && !(getMethod4 == null) && !(getMethod.ReturnType != typeof(Recipe)) && !(getMethod2.ReturnType != typeof(ItemData)) && !(getMethod3.ReturnType != typeof(GameObject)) && !(getMethod4.ReturnType != typeof(bool)))
				{
					DynamicMethod dynamicMethod = new DynamicMethod("HutoPairRead", null, new Type[6]
					{
						typeof(object),
						typeof(int),
						typeof(Recipe).MakeByRefType(),
						typeof(ItemData).MakeByRefType(),
						typeof(GameObject).MakeByRefType(),
						typeof(bool).MakeByRefType()
					}, typeof(RecipePairs).Module, skipVisibility: true);
					ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
					iLGenerator.DeclareLocal(pt);
					iLGenerator.Emit(OpCodes.Ldarg_0);
					iLGenerator.Emit(OpCodes.Castclass, lt);
					iLGenerator.Emit(OpCodes.Ldarg_1);
					iLGenerator.Emit(OpCodes.Callvirt, method);
					iLGenerator.Emit(OpCodes.Stloc_0);
					iLGenerator.Emit(OpCodes.Ldarg_2);
					iLGenerator.Emit(OpCodes.Ldloca_S, (byte)0);
					iLGenerator.Emit(OpCodes.Call, getMethod);
					iLGenerator.Emit(OpCodes.Stind_Ref);
					iLGenerator.Emit(OpCodes.Ldarg_3);
					iLGenerator.Emit(OpCodes.Ldloca_S, (byte)0);
					iLGenerator.Emit(OpCodes.Call, getMethod2);
					iLGenerator.Emit(OpCodes.Stind_Ref);
					iLGenerator.Emit(OpCodes.Ldarg_S, (byte)4);
					iLGenerator.Emit(OpCodes.Ldloca_S, (byte)0);
					iLGenerator.Emit(OpCodes.Call, getMethod3);
					iLGenerator.Emit(OpCodes.Stind_Ref);
					iLGenerator.Emit(OpCodes.Ldarg_S, (byte)5);
					iLGenerator.Emit(OpCodes.Ldloca_S, (byte)0);
					iLGenerator.Emit(OpCodes.Call, getMethod4);
					iLGenerator.Emit(OpCodes.Stind_I1);
					iLGenerator.Emit(OpCodes.Ret);
					ReadFn read = (ReadFn)dynamicMethod.CreateDelegate(typeof(ReadFn));
					DynamicMethod dynamicMethod2 = new DynamicMethod("HutoPairWrite", null, new Type[6]
					{
						typeof(object),
						typeof(int),
						typeof(Recipe),
						typeof(ItemData),
						typeof(GameObject),
						typeof(bool)
					}, typeof(RecipePairs).Module, skipVisibility: true);
					iLGenerator = dynamicMethod2.GetILGenerator();
					iLGenerator.Emit(OpCodes.Ldarg_0);
					iLGenerator.Emit(OpCodes.Castclass, lt);
					iLGenerator.Emit(OpCodes.Ldarg_1);
					iLGenerator.Emit(OpCodes.Ldarg_2);
					iLGenerator.Emit(OpCodes.Ldarg_3);
					iLGenerator.Emit(OpCodes.Ldarg_S, (byte)4);
					iLGenerator.Emit(OpCodes.Ldarg_S, (byte)5);
					iLGenerator.Emit(OpCodes.Newobj, ctor);
					iLGenerator.Emit(OpCodes.Callvirt, method2);
					iLGenerator.Emit(OpCodes.Ret);
					WriteFn write = (WriteFn)dynamicMethod2.CreateDelegate(typeof(WriteFn));
					Read = read;
					Write = write;
				}
			}
		}

		private static void Fallback(PropertyInfo pR, PropertyInfo pI, PropertyInfo pE, PropertyInfo pC, ConstructorInfo ctor)
		{
			Read = delegate(object l, int i, out Recipe r, out ItemData it, out GameObject el, out bool can)
			{
				object obj = ((IList)l)[i];
				object? value = pR.GetValue(obj, null);
				r = (Recipe)((value is Recipe) ? value : null);
				it = (ItemData)((!(pI != null)) ? null : /*isinst with value type is only supported in some contexts*/);
				object? value2 = pE.GetValue(obj, null);
				el = (GameObject)((value2 is GameObject) ? value2 : null);
				can = (bool)pC.GetValue(obj, null);
			};
			Write = delegate(object l, int i, Recipe r, ItemData it, GameObject el, bool can)
			{
				((IList)l)[i] = ctor.Invoke(new object[4] { r, it, el, can });
			};
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
	internal static class P_CraftSort_UpdateRecipeList
	{
		private static void Postfix(InventoryGui __instance)
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !RecipeReuse.Skipped)
				{
					StorageWindow window = Plugin.Window;
					if (window != null && window.CraftActive && NearbyCraft.Virtual(localPlayer))
					{
						CraftSort.Apply(__instance, byCategory: false);
					}
				}
			}
			catch (Exception e)
			{
				StorageWindow.WarnOnce("제작 목록 정렬", e);
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "StackAll")]
	internal static class Patch_Inventory_StackAll
	{
		private static readonly FieldInfo F_items = AccessTools.Field(typeof(Inventory), "m_inventory");

		private static void Prefix(Inventory fromInventory, out List<ItemData> __state)
		{
			__state = null;
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || fromInventory == null || fromInventory != ((Humanoid)localPlayer).GetInventory() || SlotLocks.Count() == 0 || !(F_items.GetValue(fromInventory) is List<ItemData> list))
				{
					return;
				}
				__state = list.FindAll(SlotLocks.IsLocked);
				if (__state.Count == 0)
				{
					__state = null;
					return;
				}
				foreach (ItemData item in __state)
				{
					list.Remove(item);
				}
			}
			catch
			{
				__state = null;
			}
		}

		private static void Finalizer(Inventory fromInventory, List<ItemData> __state)
		{
			if (__state == null)
			{
				return;
			}
			try
			{
				if (!(F_items.GetValue(fromInventory) is List<ItemData> list))
				{
					return;
				}
				foreach (ItemData item in __state)
				{
					if (!list.Contains(item))
					{
						list.Add(item);
					}
				}
				MethodInfo m_changed = InvBatch.M_changed;
				if (m_changed != null)
				{
					m_changed.Invoke(fromInventory, (m_changed.GetParameters().Length != 2) ? new object[0] : new object[2] { true, false });
				}
			}
			catch
			{
			}
		}
	}
	internal static class CraftSearch
	{
		public static bool Focused;

		private static int _rectFrame = -1;

		private static bool _rectOk;

		private static Rect _cr;

		private static Rect _tr;

		private static string _q = string.Empty;

		private static string _applied = string.Empty;

		private static GUIStyle _field;

		private static GUIStyle _ph;

		private static readonly MethodInfo M_updatePanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null);

		private static int _tipFrame = -1;

		private static bool _tipCovers;

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

		private static readonly HashSet<Recipe> _unknown = new HashSet<Recipe>();

		private static readonly FieldInfo F_avail = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

		private static readonly Color FrameColor = Color32.op_Implicit(new Color32((byte)110, (byte)82, (byte)50, byte.MaxValue));

		private static bool Active => Plugin.Window?.IsOpen ?? false;

		public static string Query => (!Active) ? string.Empty : (_q ?? string.Empty).Trim();

		private static string L(string t)
		{
			if (t == null)
			{
				return string.Empty;
			}
			if (_names.TryGetValue(t, out var value))
			{
				return value;
			}
			value = ContainerAccess.Localize(t) ?? t;
			if (_names.Count > 4096)
			{
				_names.Clear();
			}
			_names[t] = value;
			return value;
		}

		public static void Filter(List<Recipe> recipes)
		{
			string q = Query;
			_applied = q;
			_unknown.Clear();
			if (q.Length == 0 || recipes == null)
			{
				return;
			}
			recipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || (Object)(object)r.m_item == (Object)null || L(r.m_item.m_itemData.m_shared.m_name).IndexOf(q, StringComparison.OrdinalIgnoreCase) < 0);
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || !instance.InCraftTab())
			{
				return;
			}
			HashSet<Recipe> hashSet = new HashSet<Recipe>(recipes);
			foreach (Recipe recipe in ObjectDB.instance.m_recipes)
			{
				if ((Object)(object)recipe == (Object)null || !recipe.m_enabled || (Object)(object)recipe.m_item == (Object)null || hashSet.Contains(recipe))
				{
					continue;
				}
				SharedData shared = recipe.m_item.m_itemData.m_shared;
				if (string.IsNullOrEmpty(shared.m_dlc) && !localPlayer.IsRecipeKnown(shared.m_name) && L(shared.m_name).IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					bool flag;
					try
					{
						flag = localPlayer.RequiredCraftingStation(recipe, 1, false);
					}
					catch
					{
						flag = false;
					}
					if (flag)
					{
						recipes.Add(recipe);
						_unknown.Add(recipe);
					}
				}
			}
		}

		public static bool IsUnknown(Recipe r)
		{
			return (Object)(object)r != (Object)null && _unknown.Count > 0 && _unknown.Contains(r);
		}

		public static void MarkUnknown(InventoryGui gui)
		{
			if (_unknown.Count == 0 || (Object)(object)gui == (Object)null || F_avail == null || !(F_avail.GetValue(gui) is IList list) || !RecipePairs.Init(list))
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				RecipePairs.Read(list, i, out var r, out var _, out var el, out var _);
				if (!((Object)(object)r == (Object)null) && !((Object)(object)el == (Object)null) && _unknown.Contains(r))
				{
					Transform val = el.transform.Find("name");
					TMP_Text val2 = ((!((Object)(object)val != (Object)null)) ? null : ((Component)val).GetComponent<TMP_Text>());
					if ((Object)(object)val2 != (Object)null && val2.text.IndexOf("(미습득)", StringComparison.Ordinal) < 0)
					{
						val2.text += " <color=#a08060>(미습득)</color>";
					}
				}
			}
		}

		private static void DrawFrame(Rect r, float t)
		{
			//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)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			Color color = GUI.color;
			GUI.color = FrameColor;
			Texture2D whiteTexture = Texture2D.whiteTexture;
			GUI.DrawTexture(new Rect(((Rect)(ref r)).x - t, ((Rect)(ref r)).y - t, ((Rect)(ref r)).width + 2f * t, t), (Texture)(object)whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref r)).x - t, ((Rect)(ref r)).yMax, ((Rect)(ref r)).width + 2f * t, t), (Texture)(object)whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref r)).x - t, ((Rect)(ref r)).y, t, ((Rect)(ref r)).height), (Texture)(object)whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax, ((Rect)(ref r)).y, t, ((Rect)(ref r)).height), (Texture)(object)whiteTexture);
			GUI.color = color;
		}

		public static void OnGUI()
		{
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Invalid comparison between Unknown and I4
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Invalid comparison between Unknown and I4
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Expected O, but got Unknown
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Invalid comparison between Unknown and I4
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Invalid comparison between Unknown and I4
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Invalid comparison between Unknown and I4
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Invalid comparison between Unknown and I4
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Invalid comparison between Unknown and I4
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null || !Active || !InventoryGui.IsVisible() || (Object)(object)instance.m_crafting == (Object)null || !((Component)instance.m_crafting).gameObject.activeInHierarchy)
			{
				if (Focused)
				{
					Focused = false;
					try
					{
						Input.imeCompositionMode = (IMECompositionMode)0;
					}
					catch
					{
					}
				}
				if ((Object)(object)instance == (Object)null || !Active || !InventoryGui.IsVisible())
				{
					_q = string.Empty;
					_applied = string.Empty;
				}
				return;
			}
			int frameCount = Time.frameCount;
			if (frameCount != _rectFrame)
			{
				_rectFrame = frameCount;
				RectTransform val = (RectTransform)((!((Object)(object)instance.m_tabUpgrade != (Object)null)) ? null : /*isinst with value type is only supported in some contexts*/);
				_rectOk = StorageWindow.ScreenRect(instance.m_crafting, out _cr) && (Object)(object)val != (Object)null && StorageWindow.ScreenRect(val, out _tr);
			}
			if (!_rectOk)
			{
				return;
			}
			Rect cr = _cr;
			Rect tr = _tr;
			float width = ((Rect)(ref cr)).width;
			Rect rect = instance.m_crafting.rect;
			float num = width / Mathf.Max(1f, ((Rect)(ref rect)).width);
			float num2 = 8f * num;
			float num3 = ((Rect)(ref tr)).xMax + num2;
			float num4 = ((Rect)(ref cr)).xMax - 44f * num;
			if (num4 - num3 < 60f * num)
			{
				return;
			}
			float num5 = Mathf.Round(((Rect)(ref tr)).height * 0.7f);
			float num6 = ((Rect)(ref tr)).height * 0.47f;
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(num3, Mathf.Round((float)Screen.height - ((Rect)(ref tr)).yMax + num6 - num5 * 0.5f), num4 - num3, num5);
			int frameCount2 = Time.frameCount;
			if (frameCount2 != _tipFrame)
			{
				_tipFrame = frameCount2;
				_tipCovers = StorageWindow.TooltipCoversCore(val2);
			}
			if (!Focused && _tipCovers)
			{
				return;
			}
			UiSkin.Ensure();
			if (_field == null)
			{
				_field = new GUIStyle(UiSkin.FieldStyle);
				_ph = new GUIStyle(UiSkin.Placeholder);
				_ph.fontStyle = (FontStyle)0;
			}
			GUIStyle field = _field;
			int fontSize = Mathf.Clamp(Mathf.RoundToInt(num5 * 0.55f), 11, 22);
			_ph.fontSize = fontSize;
			field.fontSize = fontSize;
			Event current = Event.current;
			if ((int)current.type == 7)
			{
				DrawFrame(val2, 1f);
			}
			GUI.SetNextControlName("hutoheim_craftsearch");
			_q = GUI.TextField(val2, _q ?? string.Empty, 40, _field);
			bool flag = GUI.GetNameOfFocusedControl() == "hutoheim_craftsearch";
			if (string.IsNullOrEmpty(_q) && !flag)
			{
				GUI.Label(val2, "레시피 검색…", _ph);
			}
			if (flag && (int)current.type == 4 && ((int)current.keyCode == 27 || (int)current.keyCode == 13 || (int)current.keyCode == 271 || (int)current.keyCode == 9))
			{
				GUI.FocusControl((string)null);
				current.Use();
				flag = false;
			}
			if (flag && (int)current.type == 0 && !((Rect)(ref val2)).Contains(current.mousePosition))
			{
				GUI.FocusControl((string)null);
				flag = false;
			}
			if (flag != Focused)
			{
				try
				{
					Input.imeCompositionMode = (IMECompositionMode)(flag ? 1 : 0);
				}
				catch
				{
				}
			}
			Focused = flag;
			if ((int)current.type != 7 || !(Query != _applied) || !(M_updatePanel != null))
			{
				return;
			}
			_applied = Query;
			try
			{
				M_updatePanel.Invoke(instance, new object[1] { false });
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
	internal static class P_CraftSearch_UpdateRecipeList
	{
		[HarmonyPriority(200)]
		private static void Prefix(List<Recipe> recipes)
		{
			try
			{
				CraftSearch.Filter(recipes);
			}
			catch
			{
			}
		}

		[HarmonyPriority(0)]
		private static void Postfix(InventoryGui __instance)
		{
			try
			{
				CraftSearch.MarkUnknown(__instance);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	internal static class P_Requirement_Unknown
	{
		private const string Child = "Hutoheim_unknown";

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

		private static readonly Func<Player, HashSet<string>> G_known = Fast.Getter<Player, HashSet<string>>(F_known);

		private static void Postfix(Transform elementRoot, Requirement req, Player player)
		{
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)elementRoot == (Object)null)
				{
					return;
				}
				Transform val = elementRoot.Find("Hutoheim_unknown");
				bool flag = false;
				if (req != null && (Object)(object)req.m_resItem != (Object)null && (Object)(object)player != (Object)null && ((Component)elementRoot).gameObject.activeSelf && G_known != null)
				{
					HashSet<string> hashSet = G_known(player);
					flag = hashSet != null && !hashSet.Contains(req.m_resItem.m_itemData.m_shared.m_name);
				}
				if (!flag)
				{
					if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(false);
					}
					return;
				}
				if ((Object)(object)val == (Object)null)
				{
					Transform val2 = elementRoot.Find("res_amount");
					if ((Object)(object)val2 == (Object)null)
					{
						return;
					}
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, elementRoot);
					((Object)val3).name = "Hutoheim_unknown";
					val = val3.transform;
					RectTransform val4 = (RectTransform)(object)((val2 is RectTransform) ? val2 : null);
					RectTransform val5 = (RectTransform)(object)((val is RectTransform) ? val : null);
					if ((Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null)
					{
						Rect rect = val4.rect;
						float num = Mathf.Max(10f, ((Rect)(ref rect)).height);
						val5.anchoredPosition = val4.anchoredPosition + new Vector2(0f, num * 0.8f);
					}
					TMP_Text component = val3.GetComponent<TMP_Text>();
					if ((Object)(object)component != (Object)null)
					{
						component.enableAutoSizing = false;
						component.fontSize = Mathf.Max(9f, component.fontSize * 0.7f);
						((Graphic)component).color = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)170, (byte)90, byte.MaxValue));
						((Graphic)component).raycastTarget = false;
					}
				}
				TMP_Text component2 = ((Component)val).GetComponent<TMP_Text>();
				if ((Object)(object)component2 != (Object)null && component2.text != "미습득")
				{
					component2.text = "미습득";
				}
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "HideRequirement")]
	internal static class P_Requirement_Unknown_Hide
	{
		private static void Postfix(Transform elementRoot)
		{
			try
			{
				Transform val = ((!((Object)(object)elementRoot != (Object)null)) ? null : elementRoot.Find("Hutoheim_unknown"));
				if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
			catch
			{
			}
		}
	}
	internal static class SlotLocks
	{
		private const string StoreKey = "slotlocks";

		private static HashSet<int> _set;

		private static string _setFor;

		public static int Version;

		private static int Pack(int x, int y)
		{
			return y * 1000 + x;
		}

		private static HashSet<int> Parse(string v)
		{
			HashSet<int> hashSet = new HashSet<int>();
			if (string.IsNullOrEmpty(v))
			{
				return hashSet;
			}
			string[] array = v.Split(new char[1] { ';' });
			foreach (string text in array)
			{
				string[] array2 = text.Split(new char[1] { ',' });
				if (array2.Length == 2 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2))
				{
					hashSet.Add(Pack(result, result2));
				}
			}
			return hashSet;
		}

		private static void Save()
		{
			if (_set == null || _setFor == null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (int item in _set)
			{
				list.Add(item % 1000 + "," + item / 1000);
			}
			CharStore.Set("slotlocks", string.Join(";", list.ToArray()));
		}

		private static HashSet<int> Current(bool create)
		{
			string text = CharStore.CharId();
			if (text == null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return null;
			}
			if (!CharStore.Readable)
			{
				return null;
			}
			if (_set == null || text != _setFor)
			{
				_set = Parse(CharStore.Get("slotlocks"));
				_setFor = text;
				Version++;
			}
			return _set;
		}

		public static bool IsLocked(int x, int y)
		{
			return Current(create: false)?.Contains(Pack(x, y)) ?? false;
		}

		public static bool IsLocked(ItemData it)
		{
			return it != null && IsLocked(it.m_gridPos.x, it.m_gridPos.y);
		}

		public static bool Toggle(int x, int y)
		{
			HashSet<int> hashSet = Current(create: true);
			if (hashSet == null)
			{
				return false;
			}
			int item = Pack(x, y);
			bool flag = !hashSet.Remove(item);
			if (flag)
			{
				hashSet.Add(item);
			}
			Version++;
			Save();
			if (CraftChests.Override is MaterialPool materialPool)
			{
				materialPool.Dirty = true;
			}
			return flag;
		}

		public static int Count()
		{
			return Current(create: false)?.Count ?? 0;
		}
	}
	public class StorageWindow
	{
		private sealed class Deposited
		{
			public Container C;

			public string Key;

			public int Count;

			public Vector2i Pos;
		}

		private class PendingOp
		{
			public List<Container> Chests;

			public Action Act;

			public float Start;

			public float Deadline;

			public int Session;
		}

		private class CStation
		{
			public string Key;

			public string Name;

			public CraftingStation Best;

			public int Level;

			public int MaxLevel;

			public int Count;

			public string Why;

			public int WhyOrder = -1;
		}

		private struct Cand
		{
			public CStation Info;

			public CraftingStation S;

			public int Level;

			public float D2;

			public int Order;
		}

		private enum Mode
		{
			One,
			Stack,
			All
		}

		private class Entry
		{
			public string Key;

			public string Name;

			public ItemData Sample;

			public int Total;

			public int Chests;
		}

		private struct KeyCache
		{
			public string Name;

			public string Key;

			public int Q;

			public int V;

			public int W;
		}

		private class HeldItem
		{
			public string Key;

			public ItemData Sample;

			public int Amount;
		}

		private List<Deposited> _undo;

		private int _undoSig;

		private float _nextUndoCheck;

		internal static readonly FieldInfo F_containerGrid = AccessTools.Field(typeof(InventoryGui), "m_containerGrid");

		internal static readonly FieldInfo F_dragGo = AccessTools.Field(typeof(InventoryGui), "m_dragGo");

		internal static readonly FieldInfo F_dragItem = AccessTools.Field(typeof(InventoryGui), "m_dragItem");

		internal static readonly FieldInfo F_dragInv = AccessTools.Field(typeof(InventoryGui), "m_dragInventory");

		internal static readonly FieldInfo F_dragAmount = AccessTools.Field(typeof(InventoryGui), "m_dragAmount");

		internal static readonly MethodInfo M_setupDrag = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3]
		{
			typeof(ItemData),
			typeof(Inventory),
			typeof(int)
		}, (Type[])null);

		private static readonly FieldInfo F_firstContainerUpdate = AccessTools.Field(typeof(InventoryGui), "m_firstContainerUpdate");

		private static readonly FieldInfo F_invList = AccessTools.Field(typeof(Inventory), "m_inventory");

		private static readonly FieldInfo F_elements = AccessTools.Field(typeof(InventoryGrid), "m_elements");

		private static readonly Func<InventoryGrid, IList> G_elements = Fast.Getter<InventoryGrid, IList>(F_elements);

		private static readonly Func<InventoryGui, InventoryGrid> G_containerGrid = Fast.Getter<InventoryGui, InventoryGrid>(F_containerGrid);

		private static readonly Func<Inventory, List<ItemData>> G_invList = Fast.Getter<Inventory, List<ItemData>>(F_invList);

		private static readonly Func<InventoryGui, Inventory> G_dragInv = Fast.Getter<InventoryGui, Inventory>(F_dragInv);

		public const int VCols = 8;

		public const int VRows = 6;

		private static readonly FieldInfo F_invHeight = AccessTools.Field(typeof(Inventory), "m_height");

		private Inventory _vinv;

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

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

		private string _dragKey;

		private bool _showingSelf;

		public static bool SearchFocused;

		private static bool _warnedPanel;

		private int _scrollRow;

		private int _vinvVersion;

		private int _drawnVersion = -1;

		private bool _allowShrink;

		private ItemData _drawnDrag;

		private float _openedAt;

		private int _fitOk;

		private Vector2i _drawnSel;

		private bool _drawnSelValid;

		private InventoryElement _drawnHover;

		private static readonly MethodInfo M_hovered = AccessTools.Method(typeof(InventoryGrid), "GetHoveredElement", (Type[])null, (Type[])null);

		private static Func<InventoryGrid, InventoryElement> _hovered;

		private Vector3 _hovMouse;

		private Vector3 _hovRoot;

		private int _hovVersion = -1;

		private InventoryGrid _hovGrid;

		private InventoryElement _hovLast;

		private static readonly Func<InventoryGrid, Inventory> G_gridInv = Fast.Getter<InventoryGrid, Inventory>(AccessTools.Field(typeof(InventoryGrid), "m_inventory"));

		private static readonly Action<InventoryGrid> _gamepad = MakeGamepad();

		private static readonly MethodInfo M_createTooltip = AccessTools.Method(typeof(InventoryGrid), "CreateItemTooltip", (Type[])null, (Type[])null);

		private static readonly FieldInfo F_elTooltip = AccessTools.Field(typeof(InventoryElement), "m_tooltip");

		private readonly object[] _tipArgs = new object[2];

		private static readonly Func<InventoryGui, ItemData> G_dragItem = Fast.Getter<InventoryGui, ItemData>(F_dragItem);

		private static readonly Func<InventoryGui, bool> G_firstContainerUpdate = Fast.Getter<InventoryGui, bool>(F_firstContainerUpdate);

		private static readonly Func<InventoryGrid, Vector2i> G_gridSelected = Fast.Getter<InventoryGrid, Vector2i>(AccessTools.Field(typeof(InventoryGrid), "m_selected"));

		private readonly Dictionary<ItemData, KeyValuePair<int, string>> _countText = new Dictionary<ItemData, KeyValuePair<int, string>>();

		private static readonly Vector3[] _screenCorners = (Vector3[])(object)new Vector3[4];

		private static readonly Dictionary<RectTransform, Canvas> _rootCanvas = new Dictionary<RectTransform, Canvas>();

		private TMP_Text _stationLine;

		private readonly Button[] _barBtn = (Button[])(object)new Button[3];

		private readonly TMP_Text[] _barTxt = (TMP_Text[])(object)new TMP_Text[3];

		private InventoryGui _extrasFor;

		private bool _vanillaBtnHidden;

		private const float BarGap = 8f;

		private const float BarTop = 10f;

		private static readonly bool StationLineEnabled = false;

		private readonly List<KeyValuePair<RectTransform, Vector2>> _grown = new List<KeyValuePair<RectTransform, Vector2>>();

		private static readonly FieldInfo F_gridWidth = AccessTools.Field(typeof(InventoryGrid), "m_width");

		private InventoryGrid _swappedGrid;

		private GameObject _origPrefab;

		private float _origSpace;

		private bool _hasOrigBottom;

		private Vector2 _origBottom;

		private float _extra;

		private float _shrink;

		private Scrollbar _sbFor;

		private Vector2 _sbAMin;

		private Vector2 _sbAMax;

		private Vector2 _sbPivot;

		private Vector2 _sbPos;

		private Vector2 _sbSize;

		private ScrollRect _srFor;

		private Scrollbar _srBar;

		private bool _srVertical;

		private bool _sbSetting;

		private Scrollbar _sbHooked;

		private int _sbRow = -1;

		private int _sbMax = -1;

		private static GUIStyle _field;

		private static GUIStyle _ph;

		private static FieldInfo[] _tipFields;

		private static int _tipFrame = -1;

		private static Rect _tipRect;

		private static bool _tipResult;

		private static readonly List<CanvasGroup> _cgTmp = new List<CanvasGroup>();

		private static int _alphaFrame = -1;

		private static float _alpha = 1f;

		private readonly List<ItemData> _wornTmp = new List<ItemData>();

		private static readonly Dictionary<string, Recipe> _recipeOf = new Dictionary<string, Recipe>();

		private static ObjectDB _recipeDb;

		private static int _recipeCount = -1;

		private const float SlideTime = 0.2f;

		private const float CloseTime = 0.15f;

		private bool _slideOn;

		private bool _hasRest;

		private Vector3 _restTL;

		private Vector3 _appliedLocal;

		private RectTransform _slideRt;

		private readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4];

		private readonly Vector3[] _bc = (Vector3[])(object)new Vector3[4];

		private Vector3 _lastTL;

		private int _stable;

		private float _openT = -1f;

		private float _closeT = -1f;

		private bool _wasOpen;

		private const string PrefKey = "Hutoheim.ChestPanelRest";

		private int _idleStable;

		private Vector3 _idleLast;

		private static readonly Vector3[] _canvasCorners = (Vector3[])(object)new Vector3[4];

		private const float AcquireTimeout = 1.5f;

		private readonly List<PendingOp> _ops = new List<PendingOp>();

		private static readonly FieldInfo F_gRecipe = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");

		private static readonly FieldInfo F_gUpgrade = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem");

		private static readonly FieldInfo F_gMulti = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting");

		private static readonly MethodInfo M_gDoCrafting = AccessTools.Method(typeof(InventoryGui), "DoCrafting", new Type[1] { typeof(Player) }, (Type[])null);

		private bool _craftWaiting;

		private bool _craftDeferred;

		private int _craftWaitSession;

		private int _craftToken;

		private readonly List<Cand> _cands = new List<Cand>();

		private float _stationNext;

		private bool _craftPanelDirty;

		private bool _craftFullDirty = true;

		private float _nextCraftRefresh;

		private string _stationSig = string.Empty;

		private MaterialPool _pool;

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

		private readonly List<CStation> _stationList = new List<CStation>();

		private readonly List<string> _missingStations = new List<string>();

		private static readonly MethodInfo M_updateCraftingPanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null);

		private static readonly FieldInfo F_craftTimer = AccessTools.Field(typeof(InventoryGui), "m_craftTimer");

		private static readonly Func<InventoryGui, float> G_craftTimer = Fast.Getter<InventoryGui, float>(F_craftTimer);

		private static readonly FieldInfo F_knownRecipes = AccessTools.Field(typeof(Player), "m_knownRecipes");

		private static readonly Func<Player, HashSet<string>> G_knownRecipes = Fast.Getter<Player, HashSet<string>>(F_knownRecipes);

		private int _knownCount = -1;

		private const float UsableTtl = 5f;

		private static readonly Dictionary<int, KeyValuePair<float, bool>> _usable = new Dictionary<int, KeyValuePair<float, bool>>();

		private long _poolSig;

		private readonly List<Container> _opened = new List<Container>();

		private readonly List<Entry> _entries = new List<Entry>();

		private readonly Queue<Action> _actions = new Queue<Action>();

		private Vector3 _origin;

		private List<Vector3> _area = new List<Vector3>();

		private int _session;

		private bool _dirty;

		private float _nextRebuild;

		private string _search = string.Empty;

		private string _lastSearch = string.Empty;

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

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

		private readonly List<Entry> _nextEntries = new List<Entry>();

		private long _contentSig = long.MinValue;

		private Vector3 _sortedAt = new Vector3(float.MaxValue, 0f, 0f);

		private static readonly Func<Container, uint> GetLastRevision = Fast.Getter<Container, uint>(AccessTools.Field(typeof(Container), "m_lastRevision"));

		private long _lastSig;

		private long _lastChestSig;

		private static readonly Comparison<Entry> ByEntry = delegate(Entry a, Entry b)
		{
			int num;
			try
			{
				num = CraftSort.CompareItems(a.Sample, b.Sample);
			}
			catch
			{
				num = string.Compare(a.Name, b.Name, StringComparison.CurrentCulture);
			}
			return (num == 0) ? string.CompareOrdinal(a.Key, b.Key) : num;
		};

		private static readonly Dictionary<ItemData, KeyCache> _keyCache = new Dictionary<ItemData, KeyCache>();

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

		private HeldItem _held;

		internal bool UndoReady => _undo != null;

		internal bool ShowingSelf => _showingSelf;

		internal Inventory Virtual => _vinv;

		private int TotalRows => Math.Max(6, (_entries.Count + 8 - 1) / 8);

		private int MaxScrollRow => Math.Max(0, TotalRows - 6);

		private bool SlideOpen => IsOpen || SpawnPicker.Active;

		internal bool Closing => _slideOn && !IsOpen && !SpawnPicker.Active;

		internal bool CraftActive => IsOpen && Plugin.CraftEnabled.Value;

		public bool IsOpen { get; private set; }

		public void DepositAllClicked()
		{
			_nextUndoCheck = 0f;
			CheckUndo();
			if (_undo != null)
			{
				TakeBackCore();
			}
			else
			{
				DepositAllCore();
			}
		}

		private static bool AllDepositable(ItemData it)
		{
			if (it == null || it.m_equipped)
			{
				return false;
			}
			if (Api.IsSlotItem(it))
			{
				return false;
			}
			if (Plugin.ExcludeHotbar.Value && it.m_gridPos.y == 0)
			{
				return false;
			}
			if (SlotLocks.IsLocked(it))
			{
				return false;
			}
			return true;
		}

		private static int InvSig(Inventory inv)
		{
			int num = 17;
			if (inv == null)
			{
				return num;
			}
			foreach (ItemData allItem in inv.GetAllItems())
			{
				num = num * 31 + ((allItem.m_shared.m_name != null) ? allItem.m_shared.m_name.GetHashCode() : 0);
				num = num * 31 + allItem.m_stack;
				num = num * 31 + allItem.m_gridPos.x * 97 + allItem.m_gridPos.y;
				num = num * 31 + allItem.m_quality;
			}
			return num;
		}

		private void CheckUndo()
		{
			if (_undo != null && !(Time.unscaledTime < _nextUndoCheck))
			{
				_nextUndoCheck = Time.unscaledTime + 0.25f;
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || InvSig(((Humanoid)localPlayer).GetInventory()) != _undoSig)
				{
					_undo = null;
				}
			}
		}

		private void DepositAllCore()
		{
			_actions.Enqueue(delegate
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					bool flag = false;
					foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
					{
						if (AllDepositable(allItem))
						{
							flag = true;
							break;
						}
					}
					if (flag)
					{
						HashSet<Container> hashSet = new HashSet<Container>();
						foreach (ItemData allItem2 in ((Humanoid)localPlayer).GetInventory().GetAllItems())
						{
							if (AllDepositable(allItem2))
							{
								foreach (Container item in DepositTargets(allItem2))
								{
									hashSet.Add(item);
								}
							}
						}
						WithChests(new List<Container>(hashSet), delegate
						{
							//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
							//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
							//IL_0191: Unknown result type (might be due to invalid IL or missing references)
							//IL_0193: Unknown result type (might be due to invalid IL or missing references)
							Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
							List<Container> list = Owned(_opened);
							List<Deposited> list2 = new List<Deposited>();
							HashSet<Container> hashSet2 = new HashSet<Container>();
							int num = 0;
							int num2 = 0;
							List<ItemData> list3 = new List<ItemData>(inventory.GetAllItems());
							list3.Sort(delegate(ItemData a, ItemData b)
							{
								int num5 = a.m_gridPos.y.CompareTo(b.m_gridPos.y);
								return (num5 == 0) ? a.m_gridPos.x.CompareTo(b.m_gridPos.x) : num5;
							});
							using (ContainerAccess.Batch())
							{
								foreach (ItemData item2 in list3)
								{
									if (AllDepositable(item2))
									{
										string key = ContainerAccess.KeyOf(item2);
										string name = item2.m_shared.m_name;
										Vector2i gridPos = item2.m_gridPos;
										for (int num3 = 0; num3 < 3; num3++)
										{
											if (!inventory.ContainsItem(item2))
											{
												break;
											}
											if (item2.m_stack <= 0)
											{
												break;
											}
											foreach (Container item3 in list)
											{
												if (!inventory.ContainsItem(item2) || item2.m_stack <= 0)
												{
													break;
												}
												if (ContainerAccess.StillOwned(item3))
												{
													Inventory inventory2 = item3.GetInventory();
													if (inventory2 != null)
													{
														bool flag2 = ChestIndex.Has(inventory2, name);
														if ((num3 >= 2 || flag2) && (flag2 || !ContainerAccess.IsFull(inventory2)))
														{
															int num4 = ContainerAccess.Move(inventory, item2, inventory2, item2.m_stack, preferNonHotbar: false, num3 >= 1);
															if (num4 > 0)
															{
																list2.Add(new Deposited
																{
																	C = item3,
																	Key = key,
																	Count = num4,
																	Pos = gridPos
																});
																num += num4;
																hashSet2.Add(item3);
															}
														}
													}
												}
											}
										}
										if (inventory.ContainsItem(item2) && item2.m_stack > 0)
										{
											num2++;
										}
									}
								}
							}
							if (num > 0)
							{
								_undo = list2;
								_undoSig = InvSig(inventory);
							}
						});
					}
				}
			});
		}

		private void TakeBackCore()
		{
			List<Deposited> log = _undo;
			_undo = null;
			if (log == null || log.Count == 0)
			{
				return;
			}
			_actions.Enqueue(delegate
			{
				List<Container> list = new List<Container>();
				foreach (Deposited item in log)
				{
					if ((Object)(object)item.C != (Object)null && !list.Contains(item.C))
					{
						list.Add(item.C);
					}
				}
				WithChests(list, delegate
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return;
					}
					Inventory inventory = ((Humanoid)localPlayer).GetInventory();
					int num = 0;
					int num2 = 0;
					using (ContainerAccess.Batch())
					{
						for (int num3 = log.Count - 1; num3 >= 0; num3--)
						{
							Deposited deposited = log[num3];
							num2 += deposited.Count;
							if (ContainerAccess.StillOwned(deposited.C))
							{
								Inventory inventory2 = deposited.C.GetInventory();
								if (inventory2 != null)
								{
									int num4 = deposited.Count;
									List<ItemData> list2 = new List<ItemData>(inventory2.GetAllItems());
									list2.Sort((ItemData a, ItemData b) => a.m_stack.CompareTo(b.m_stack));
									foreach (ItemData item2 in list2)
									{
										if (num4 <= 0)
										{
											break;
										}
										if (ContainerAccess.HasKey(item2, deposited.Key) && inventory2.ContainsItem(item2))
										{
											int num5 = Mathf.Min(num4, item2.m_stack);
											int num6 = 0;
											ItemData itemAt = inventory.GetItemAt(deposited.Pos.x, deposited.Pos.y);
											if (itemAt == null || (itemAt.IsSameType(item2) && itemAt.m_stack < itemAt.m_shared.m_maxStackSize))
											{
												int num7 = ((itemAt != null) ? (itemAt.m_shared.m_maxStackSize - itemAt.m_stack) : item2.m_shared.m_maxStackSize);
												int num8 = Mathf.Min(num5, num7);
												int stack = item2.m_stack;
												bool flag = num8 >= item2.m_stack;
												if (num8 > 0 && inventory.MoveItemToThis(inventory2, item2, num8, deposited.Pos.x, deposited.Pos.y))
												{
													num6 = ((!flag) ? (stack - item2.m_stack) : num8);
												}
											}
											if (num6 < num5 && inventory2.ContainsItem(item2))
											{
												num6 += ContainerAccess.Move(inventory2, item2, inventory, num5 - num6, preferNonHotbar: true, allowEmpty: true);
											}
											num4 -= num6;
											num += num6;
										}
									}
								}
							}
						}
					}
				});
			});
		}

		internal static InventoryGrid ContainerGrid(InventoryGui gui)
		{
			return (InventoryGrid)(((Object)(object)gui == (Object)null) ? null : ((G_containerGrid == null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)G_containerGrid(gui))));
		}

		private static List<ItemData> InvList(Inventory inv)
		{
			return (inv == null) ? null : ((G_invList == null) ? (F_invList.GetValue(inv) as List<ItemData>) : G_invList(inv));
		}

		internal static Inventory DragInv(InventoryGui gui)
		{
			return (Inventory)(((Object)(object)gui == (Object)null) ? null : ((G_dragInv == null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)G_dragInv(gui))));
		}

		internal void MarkCraftDirty()
		{
			_craftPanelDirty = true;
		}

		internal static void WarnOnce(string what, Exception e)
		{
			if (!_warnedPanel)
			{
				_warnedPanel = true;
				Plugin.Warn("통합 창(" + what + "): " + ((e == null) ? string.Empty : e.Message));
			}
		}

		private bool ShowVanilla()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null || F_containerGrid == null || F_invList == null || M_setupDrag == null)
			{
				return false;
			}
			_showingSelf = true;
			try
			{
				instance.Show((Container)null, 1);
			}
			catch (Exception e)
			{
				WarnOnce("열기", e);
				return false;
			}
			finally
			{
				_showingSelf = false;
			}
			return true;
		}

		private void RebuildVirtual()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			_vinvVersion++;
			if (_vinv == null)
			{
				_vinv = new Inventory("주변 보관함", (Sprite)null, 8, 6);
			}
			List<ItemData> list = InvList(_vinv);
			if (list == null)
			{
				return;
			}
			list.Clear();
			if (_vinv.GetHeight() != 6 && F_invHeight != null)
			{
				F_invHeight.SetValue(_vinv, 6);
			}
			if (_allowShrink)
			{
				_scrollRow = 0;
			}
			_allowShrink = false;
			_scrollRow = Mathf.Clamp(_scrollRow, 0, MaxScrollRow);
			int num = 48;
			int num2 = _scrollRow * 8;
			for (int i = 0; i < _entries.Count; i++)
			{
				ChestKnowledge.LearnSample(_entries[i].Sample);
			}
			for (int j = 0; j < num && num2 + j < _entries.Count; j++)
			{
				Entry entry = _entries[num2 + j];
				if (!_clones.TryGetValue(entry.Key, out var value))
				{
					value = entry.Sample.Clone();
					_clones[entry.Key] = value;
					_cloneKey[value] = entry.Key;
				}
				value.m_stack = Math.Max(1, entry.Total);
				value.m_equipped = false;
				value.m_durability = entry.Sample.m_durability;
				value.m_gridPos = new Vector2i(j % 8, j / 8);
				list.Add(value);
			}
		}

		private void ScrollTo(int row)
		{
			row = Mathf.Clamp(row, 0, MaxScrollRow);
			if (row != _scrollRow)
			{
				_scrollRow = row;
				RebuildVirtual();
			}
		}

		private void HandleWheel(InventoryGui gui, InventoryGrid g)
		{
			//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)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			float y = Input.mouseScrollDelta.y;
			if (!(Mathf.Abs(y) < 0.01f) && MaxScrollRow != 0 && ScreenRect(gui.m_container, out var r) && ((Rect)(ref r)).Contains(Input.mousePosition))
			{
				ScrollTo(_scrollRow + ((!(y > 0f)) ? 1 : (-1)));
			}
		}

		private string KeyOfVirtual(ItemData it)
		{
			string value;
			return (it == null || !_cloneKey.TryGetValue(it, out value)) ? null : value;
		}

		private string PanelTitle()
		{
			return "기지 상자 " + _opened.Count + "개";
		}

		internal void UpdatePanel(InventoryGui gui)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			UndoSlide();
			InventoryGrid val = ContainerGrid(gui);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (_vinv == null)
			{
				RebuildVirtual();
			}
			if (!((Component)gui.m_container).gameObject.activeSelf)
			{
				((Component)gui.m_container).gameObject.SetActive(true);
			}
			try
			{
				if (_gamepad != null && G_gridInv != null && object.ReferenceEquals(G_gridInv(val), _vinv))
				{
					_gamepad(val);
				}
			}
			catch
			{
			}
			ItemData val2 = ((G_dragItem == null) ? null : G_dragItem(gui));
			bool flag = G_firstContainerUpdate != null && G_firstContainerUpdate(gui);
			float unscaledTime = Time.unscaledTime;
			Vector2i drawnSel = (Vector2i)((G_gridSelected == null) ? new Vector2i(-1, -1) : G_gridSelected(val));
			bool flag2 = unscaledTime - _openedAt < 1.5f && _fitOk < 5;
			try
			{
				HandleWheel(gui, val);
			}
			catch
			{
			}
			try
			{
				SyncScrollbar(val);
			}
			catch (Exception e)
			{
				WarnOnce("스크롤", e);
			}
			InventoryElement val3 = HoveredCached(val);
			bool flag3 = flag || _drawnVersion != _vinvVersion || val2 != _drawnDrag || !_drawnSelValid || drawnSel.x != _drawnSel.x || drawnSel.y != _drawnSel.y;
			if (!flag3 && (Object)(object)val3 != (Object)(object)_drawnHover)
			{
				_drawnHover = val3;
				if (!HoverTooltip(val, val3))
				{
					flag3 = true;
				}
			}
			if ((Object)(object)_barTxt[1] != (Object)null)
			{
				SetText(_barTxt[1], (!UndoReady) ? "전부 넣기" : "다시 꺼내기");
			}
			if (!flag3)
			{
				if (flag2)
				{
					try
					{
						EnsureExtras(gui);
						return;
					}
					catch (Exception e2)
					{
						WarnOnce("버튼", e2);
						return;
					}
				}
				return;
			}
			_drawnHover = val3;
			_drawnVersion = _vinvVersion;
			_drawnDrag = val2;
			_drawnSel = drawnSel;
			_drawnSelValid = true;
			val.UpdateInventory(_vinv, (Player)null, val2);
			FixAmounts(val);
			if (flag)
			{
				val.ResetView();
				F_firstContainerUpdate.SetValue(gui, false);
			}
			if ((Object)(object)gui.m_containerName != (Object)null)
			{
				string text = PanelTitle();
				if (gui.m_containerName.text != text)
				{
					gui.m_containerName.text = text;
				}
			}
			if ((Object)(object)gui.m_containerWeight != (Object)null && gui.m_containerWeight.text != string.Empty)
			{
				gui.m_containerWeight.text = string.Empty;
			}
			try
			{
				EnsureExtras(gui);
			}
			catch (Exception e3)
			{
				WarnOnce("버튼", e3);
			}
		}

		private InventoryElement HoveredCached(InventoryGrid g)
		{
			//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)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0094: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Vector3 mousePosition = Input.mousePosition;
			Vector3 val = ((!((Object)(object)g.m_gridRoot != (Object)null)) ? Vector3.zero : ((Transform)g.m_gridRoot).position);
			if (object.ReferenceEquals(g, _hovGrid) && _hovVersion == _vinvVersion && mousePosition == _hovMouse && val == _hovRoot)
			{
				return _hovLast;
			}
			_hovGrid = g;
			_hovVersion = _vinvVersion;
			_hovMouse = mousePosition;
			_hovRoot = val;
			_hovLast = Hovered(g);
			return _hovLast;
		}

		private static Action<InventoryGrid> MakeGamepad()
		{
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGrid), "UpdateGamepad", (Type[])null, (Type[])null);
				return (!(methodInfo != null)) ? null : ((Action<InventoryGrid>)Delegate.CreateDelegate(typeof(Action<InventoryGrid>), methodInfo));
			}
			catch
			{
				return null;
			}
		}

		private bool HoverTooltip(InventoryGrid g, InventoryElement el)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)el == (Object)null)
			{
				return true;
			}
			if (M_createTooltip == null || F_elTooltip == null || _vinv == null)
			{
				return false;
			}
			try
			{
				if (ZInput.IsTouchActive())
				{
					return false;
				}
				Vector2i position = el.Position;
				ItemData itemAt = _vinv.GetItemAt(position.x, position.y);
				if (itemAt == null)
				{
					return true;
				}
				object value = F_elTooltip.GetValue(el);
				if (value == null)
				{
					return false;
				}
				_tipArgs[0] = itemAt;
				_tipArgs[1] = value;
				M_createTooltip.Invoke(g, _tipArgs);
				_tipArgs[0] = null;
				_tipArgs[1] = null;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static InventoryElement Hovered(InventoryGrid g)
		{
			try
			{
				if (_hovered == null && M_hovered != null)
				{
					_hovered = (Func<InventoryGrid, InventoryElement>)Delegate.CreateDelegate(typeof(Func<InventoryGrid, InventoryElement>), M_hovered);
				}
				return (_hovered == null) ? null : _hovered(g);
			}
			catch
			{
				return null;
			}
		}

		private void FixAmounts(InventoryGrid g)
		{
			IList list = ((G_elements == null) ? null : G_elements(g));
			if (list == null)
			{
				return;
			}
			List<ItemData> list2 = InvList(_vinv);
			for (int i = 0; i < list.Count; i++)
			{
				object? obj = list[i];
				InventoryElement val = (InventoryElement)((obj is InventoryElement) ? obj : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val.m_amount == (Object)null)
				{
					continue;
				}
				ItemData val2 = null;
				if (list2 != null && i < list2.Count && list2[i] != null && list2[i].m_gridPos.x == i % 8 && list2[i].m_gridPos.y == i / 8)
				{
					val2 = list2[i];
				}
				else if (list2 == null || i < list2.Count)
				{
					val2 = _vinv.GetItemAt(i % 8, i / 8);
				}
				if (val2 == null || (val2.m_shared.m_maxStackSize <= 1 && val2.m_stack <= 1))
				{
					continue;
				}
				if (!_countText.TryGetValue(val2, out var value) || value.Key != val2.m_stack)
				{
					value = new KeyValuePair<int, string>(val2.m_stack, FormatCount(val2.m_stack));
					if (_countText.Count > 4000)
					{
						_countText.Clear();
					}
					_countText[val2] = value;
				}
				if (val.m_amount.text != value.Value)
				{
					val.m_amount.text = value.Value;
				}
				if (!((Component)val.m_amount).gameObject.activeSelf)
				{
					((Component)val.m_amount).gameObject.SetActive(true);
				}
			}
		}

		internal static bool ScreenRect(RectTransform rt, out Rect r)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			r = default(Rect);
			if ((Object)(object)rt == (Object)null)
			{
				return false;
			}
			if (!_rootCanvas.TryGetValue(rt, out var value) || (Object)(object)value == (Object)null)
			{
				value = ((Component)rt).GetComponentInParent<Canvas>();
				if ((Object)(object)value != (Object)null)
				{
					value = value.rootCanvas;
				}
				if (_rootCanvas.Count > 256)
				{
					_rootCanvas.Clear();
				}
				_rootCanvas[rt] = value;
			}
			Camera val = null;
			if ((Object)(object)value != (Object)null && (int)value.renderMode != 0)
			{
				val = value.worldCamera;
			}
			Vector3[] screenCorners = _screenCorners;
			rt.GetWorldCorners(screenCorners);
			Vector2 val2 = RectTransformUtility.WorldToScreenPoint(val, screenCorners[0]);
			Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val, screenCorners[2]);
			r = Rect.MinMaxRect(Mathf.Min(val2.x, val3.x), Mathf.Min(val2.y, val3.y), Mathf.Max(val2.x, val3.x), Mathf.Max(val2.y, val3.y));
			return ((Rect)(ref r)).width > 1f && ((Rect)(ref r)).height > 1f;
		}

		private Button MakeBarButton(InventoryGui gui, Button src, string name, UnityAction act, out TMP_Text txt)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)src).gameObject, (Transform)(object)gui.m_container);
			((Object)val).name = name;
			Component[] componentsInChildren = val.GetComponentsInChildren<Component>(true);
			foreach (Component val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					string name2 = ((object)val2).GetType().Name;
					if (name2 == "UIGamePad" || name2 == "Localize")
					{
						Object.Destroy((Object)(object)val2);
					}
				}
			}
			Button component = val.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				for (int j = 0; j < ((UnityEventBase)component.onClick).GetPersistentEventCount(); j++)
				{
					((UnityEventBase)component.onClick).SetPersistentListenerState(j, (UnityEventCallState)0);
				}
				((UnityEventBase)component.onClick).RemoveAllListeners();
				((UnityEvent)component.onClick).AddListener(act);
			}
			txt = val.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)txt != (Object)null)
			{
				float num = ((!(txt.fontSize > 0f)) ? 18f : txt.fontSize);
				txt.enableAutoSizing = true;
				txt.fontSizeMax = num;
				txt.fontSizeMin = Mathf.Min(10f, num);
				txt.textWrappingMode = (TextWrappingModes)0;
				txt.overflowMode = (TextOverflowModes)1;
				txt.fontStyle = (FontStyles)0;
			}
			val.SetActive(true);
			return component;
		}

		private static void SetRt(RectTransform rt, Vector2 anchor, Vector2 pivot, Vector2 size, Vector2 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (rt.anchorMin != anchor)
			{
				rt.anchorMin = anchor;
			}
			if (rt.anchorMax != anchor)
			{
				rt.anchorMax = anchor;
			}
			if (rt.pivot != pivot)
			{
				rt.pivot = pivot;
			}
			if (rt.sizeDelta != size)
			{
				rt.sizeDelta = size;
			}
			if (rt.anchoredPosition != pos)
			{
				rt.anchoredPosition = pos;
			}
		}

		private void LayoutBar(InventoryGui gui)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)((!((Object)(object)gui.m_stackAllButton != (Object)null)) ? null : /*isinst with value type is only supported in some contexts*/);
			float num;
			if ((Object)(object)val != (Object)null)
			{
				Rect rect = val.rect;
				if (((Rect)(ref rect)).height > 10f)
				{
					Rect rect2 = val.rect;
					num = ((Rect)(ref rect2)).height;
					goto IL_0064;
				}
			}
			num = 34f;
			goto IL_0064;
			IL_0064:
			float num2 = num;
			float num3;
			if ((Object)(object)val != (Object)null)
			{
				Rect rect3 = val.rect;
				num3 = ((Rect)(ref rect3)).width;
			}
			else
			{
				num3 = 0f;
			}
			float num4 = Mathf.Max(num3, 150f);
			for (int i = 0; i < 3; i++)
			{
				if (!((Object)(object)_barBtn[i] == (Object)null))
				{
					Transform transform = ((Component)_barBtn[i]).transform;
					RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					SetRt(val2, new Vector2(1f, 1f), new Vector2(0f, 1f), new Vector2(num4, num2), new Vector2(8f, 0f - (10f + (float)(i + 1) * (num2 + 8f))));
					if (((Transform)val2).localScale != Vector3.one)
					{
						((Transform)val2).localScale = Vector3.one;
					}
				}
			}
			if ((Object)(object)_stationLine != (Object)null)
			{
				RectTransform rectTransform = _stationLine.rectTransform;
				Vector2 anchorMin = (rectTransform.anchorMax = new Vector2(1f, 1f));
				rectTransform.anchorMin = anchorMin;
				rectTransform.pivot = new Vector2(0f, 1f);
				rectTransform.sizeDelta = new Vector2(num4 + 40f, 400f);
				rectTransform.anchoredPosition = new Vector2(8f, 0f - (10f + 4f * (num2 + 8f) + 6f));
			}
		}

		private void GrowPanel(InventoryGui gui)
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			InventoryGrid val = ContainerGrid(gui);
			if ((Object)(object)val == (Object)null || (Object)(object)val.m_gridRoot == (Object)null)
			{
				return;
			}
			InventoryGrid playerGrid = gui.m_playerGrid;
			if ((Object)(object)_swappedGrid != (Object)(object)val && (Object)(object)playerGrid != (Object)null && (Object)(object)playerGrid.m_elementPrefab != (Object)null)
			{
				_swappedGrid = val;
				_origPrefab = val.m_elementPrefab;
				_origSpace = val.m_elementSpace;
				val.m_elementPrefab = playerGrid.m_elementPrefab;
				val.m_elementSpace = playerGrid.m_elementSpace;
				if (F_gridWidth != null)
				{
					F_gridWidth.SetValue(val, -1);
				}
				_drawnVersion = -1;
			}
			RectTransform container = gui.m_container;
			if (!_hasOrigBottom)
			{
				_hasOrigBottom = true;
				try
				{
					val.ResetView();
				}
				catch
				{
				}
				_origBottom = container.offsetMin;
				float num = (_extra = 2f * val.m_elementSpace);
				_shrink = 0f;
				container.offsetMin = new Vector2(container.offsetMin.x, container.offsetMin.y - num);
				Transform parent = ((Transform)val.m_gridRoot).parent;
				while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)((Component)container).transform)
				{
					RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
					if ((Object)(object)val2 != (Object)null && Mathf.Approximately(val2.anchorMin.y, val2.anchorMax.y))
					{
						_grown.Add(new KeyValuePair<RectTransform, Vector2>(val2, val2.offsetMin));
						val2.offsetMin = new Vector2(val2.offsetMin.x, val2.offsetMin.y - num);
					}
					parent = parent.parent;
				}
			}
			FitBottom(val, container);
			try
			{
				FixScrollbar(gui, val);
			}
			catch (Exception e)
			{
				WarnOnce("스크롤바", e);
			}
		}

		private void FitBottom(InventoryGrid g, RectTransform c)
		{
			//IL_0168: 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_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL