Decompiled source of SmarterContainers v1.10.0

SmartContainers.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SmartContainers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SmartContainers")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6b695573-f20c-49d7-99c3-26f3bd0c12c1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SmartContainers
{
	internal static class ConfigMigration
	{
		private const int CurrentModVersion = 20;

		public const string Prefixes = "trophy,mead,arrow,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,axe,crossbow,bolt,turretbolt,feast,fishingbait,spice,asksvincarrion";

		public const string Postfixes = "seeds";

		public const string Valuables = "ruby,coins,coin,amber,amberpearl,ancientcoin,ancientgemstone_black,ancientgemstone_green,ancientgemstone_orange,ancientgemstone_purple,gemstone_blue,gemstone_green,gemstone_red,dragontear,thunderstone,silvernecklace";

		public const string Ore = "copperore,tinore,ironore,silverore,flametalore,flametalore_old,ironscrap,blackmetalscrap,copperscrap,bronzescrap";

		public const string Rock = "stone,flint,obsidian,grausten,sulfurstone,blackmarble";

		public const string Ingots = "copper,tin,bronze,iron,silver,blackmetal,flametal,flametal_old";

		public const string Wood = "wood,finewood,roundlog,elderbark,yggdrasilwood,blackwood,frostwood,barkabranch";

		public const string Mushrooms = "mushroomcommon,mushroomblue,mushroomyellow,mushroom_bzerker,magecap,jotunpuffs";

		public const string Berries = "blueberries,raspberries,cloudberries,lingonberries,pukeberries,vineberry,honey";

		public const string Vegetables = "carrot,turnip,onion,fiddleheadfern,kale";

		public const string CookedMeat = "meat_cooked,boar_meat_cooked,deer_meat_cooked,wolf_meat_cooked,necktailgrilled,fish_cooked,loxmeat_cooked,serpentmeatcooked,hare_meat_cooked,chicken_meat_cooked,asksvin_meat_cooked,volture_meat_cooked,bonemawmeat_cooked,bjorn_meat_cooked,bug_meat_cooked,moose_meat_cooked,blubber_cooked,egg_cooked,smokedfish,smokedmoosemeat";

		public const string Crops = "barley,flax,oat,barleyflour,oatflour";

		public const string Cones = "pinecone,fircone,fircone_big";

		public const string Eggs = "chicken_egg,voltureegg,asksvin_egg";

		public const string Fuel = "coal,resin,tar";

		public const string Uncooked = "bakedpoteitr_uncooked,breaddough,fishandbreaduncooked,honeyglazedchickenuncooked,kalechips_uncooked,loxpie_uncooked,magicallystuffedmushroomuncooked,meatplatteruncooked,mistharesupremeuncooked,ovenpancake_uncooked,piquantpie_uncooked,roastedcrustpie_uncooked,vikingcupcake_uncooked";

		public const string Soups = "blacksoup,carrotsoup,deerstew,fierysvinstew,fishsoup,onionsoup,sealsoup,serpentstew,sizzlingberrybroth,turnipstew";

		public const string Food = "Sausages,QueensJam,BloodPudding";

		private const string OldPrefixes = "trophy,mead,arrow,armor,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,club,mushroom,arrow";

		private const string OldPostfixes = "cone,seeds,pelt,hide,berries";

		private const string OldValuables = "ruby,coins,amber,amberpearl";

		private const string OldOre = "copperore,flametalore,ironore,silverore,tinore,ironscrap,blackmetalscrap";

		private const string OldRock = "stone,flint,obsidian";

		private const string OldIngots = "copper,bronze,flametal,iron,silver,tin,blackmetal";

		private const string OldWood = "wood,finewood,corewood,elderbark,roundlog";

		private const string OldMushrooms = "Mushroom,MushroomBlue,MushroomYellow,mushroomcommon";

		private const string OldBerries = "Blueberries,raspberries,cloudberries,honey";

		private const string OldVegetables = "Carrot,Turnip";

		private const string OldCookedMeat = "CookedLoxMeat,NeckTailGrilled,MeatCooked,FishCooked,SerpentMeatCooked";

		private const string OldFood = "CarrotSoup,Sausages,QueensJam,SerpentStew,TurnipStew,BloodPudding";

		private static readonly HashSet<string> DrinkExtraSc = new HashSet<string> { "barleywine", "barleywinebase", "lingondricka", "oatmilk", "shocklatesmoothie", "sparklingshroomshake" };

		public static ConfigEntry<int> MigrateConcurrency(ConfigFile config, ConfigEntry<ConcurrentChestModificationWorkaround> concurrency)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			ConfigEntry<int> val = config.Bind<int>("General", "modVersion", 18, new ConfigDescription("Stored config version.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			if (val.Value >= 20)
			{
				return val;
			}
			if (val.Value < 19 && concurrency.Value == ConcurrentChestModificationWorkaround.ExcludeContainersOpenedByOthers)
			{
				concurrency.Value = ConcurrentChestModificationWorkaround.RequestOwnership;
			}
			return val;
		}

		public static void MigrateGroups(ConfigFile config, ConfigEntry<int> storedModVersion)
		{
			Dictionary<string, string> defaultGroupByItem;
			if (storedModVersion.Value < 20)
			{
				defaultGroupByItem = new Dictionary<string, string>();
				AddDefaultGroup("ruby,coins,coin,amber,amberpearl,ancientcoin,ancientgemstone_black,ancientgemstone_green,ancientgemstone_orange,ancientgemstone_purple,gemstone_blue,gemstone_green,gemstone_red,dragontear,thunderstone,silvernecklace", "valuables");
				AddDefaultGroup("copperore,tinore,ironore,silverore,flametalore,flametalore_old,ironscrap,blackmetalscrap,copperscrap,bronzescrap", "ore");
				AddDefaultGroup("stone,flint,obsidian,grausten,sulfurstone,blackmarble", "rock");
				AddDefaultGroup("copper,tin,bronze,iron,silver,blackmetal,flametal,flametal_old", "ingots");
				AddDefaultGroup("wood,finewood,roundlog,elderbark,yggdrasilwood,blackwood,frostwood,barkabranch", "wood");
				AddDefaultGroup("mushroomcommon,mushroomblue,mushroomyellow,mushroom_bzerker,magecap,jotunpuffs", "mushrooms");
				AddDefaultGroup("blueberries,raspberries,cloudberries,lingonberries,pukeberries,vineberry,honey", "berries");
				AddDefaultGroup("carrot,turnip,onion,fiddleheadfern,kale", "vegetables");
				AddDefaultGroup("meat_cooked,boar_meat_cooked,deer_meat_cooked,wolf_meat_cooked,necktailgrilled,fish_cooked,loxmeat_cooked,serpentmeatcooked,hare_meat_cooked,chicken_meat_cooked,asksvin_meat_cooked,volture_meat_cooked,bonemawmeat_cooked,bjorn_meat_cooked,bug_meat_cooked,moose_meat_cooked,blubber_cooked,egg_cooked,smokedfish,smokedmoosemeat", "cookedMeat");
				AddDefaultGroup("bakedpoteitr_uncooked,breaddough,fishandbreaduncooked,honeyglazedchickenuncooked,kalechips_uncooked,loxpie_uncooked,magicallystuffedmushroomuncooked,meatplatteruncooked,mistharesupremeuncooked,ovenpancake_uncooked,piquantpie_uncooked,roastedcrustpie_uncooked,vikingcupcake_uncooked", "uncooked");
				AddDefaultGroup("blacksoup,carrotsoup,deerstew,fierysvinstew,fishsoup,onionsoup,sealsoup,serpentstew,sizzlingberrybroth,turnipstew", "soups");
				AddDefaultGroup("Sausages,QueensJam,BloodPudding", "food");
				AddDefaultGroup("barley,flax,oat,barleyflour,oatflour", "crops");
				AddDefaultGroup("pinecone,fircone,fircone_big", "cones");
				AddDefaultGroup("chicken_egg,voltureegg,asksvin_egg", "eggs");
				AddDefaultGroup("coal,resin,tar", "fuel");
				HashSet<string> newPrefixSet = ParseIdSet("trophy,mead,arrow,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,axe,crossbow,bolt,turretbolt,feast,fishingbait,spice,asksvincarrion");
				MigrateIdList(config, "PrefixedItemGroups", "prefixes", "trophy,mead,arrow,armor,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,club,mushroom,arrow", "trophy,mead,arrow,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,axe,crossbow,bolt,turretbolt,feast,fishingbait,spice,asksvincarrion", null);
				MigrateIdList(config, "PostfixedItemGroups", "posfixes", "cone,seeds,pelt,hide,berries", "seeds", null);
				MigrateIdList(config, "ItemGroup", "valuables", "ruby,coins,amber,amberpearl", "ruby,coins,coin,amber,amberpearl,ancientcoin,ancientgemstone_black,ancientgemstone_green,ancientgemstone_orange,ancientgemstone_purple,gemstone_blue,gemstone_green,gemstone_red,dragontear,thunderstone,silvernecklace", (string id) => BelongsToAnotherGroup(id, "valuables", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "ore", "copperore,flametalore,ironore,silverore,tinore,ironscrap,blackmetalscrap", "copperore,tinore,ironore,silverore,flametalore,flametalore_old,ironscrap,blackmetalscrap,copperscrap,bronzescrap", (string id) => BelongsToAnotherGroup(id, "ore", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "rock", "stone,flint,obsidian", "stone,flint,obsidian,grausten,sulfurstone,blackmarble", (string id) => BelongsToAnotherGroup(id, "rock", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "ingots", "copper,bronze,flametal,iron,silver,tin,blackmetal", "copper,tin,bronze,iron,silver,blackmetal,flametal,flametal_old", (string id) => BelongsToAnotherGroup(id, "ingots", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "wood", "wood,finewood,corewood,elderbark,roundlog", "wood,finewood,roundlog,elderbark,yggdrasilwood,blackwood,frostwood,barkabranch", (string id) => BelongsToAnotherGroup(id, "wood", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "mushrooms", "Mushroom,MushroomBlue,MushroomYellow,mushroomcommon", "mushroomcommon,mushroomblue,mushroomyellow,mushroom_bzerker,magecap,jotunpuffs", (string id) => BelongsToAnotherGroup(id, "mushrooms", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "berries", "Blueberries,raspberries,cloudberries,honey", "blueberries,raspberries,cloudberries,lingonberries,pukeberries,vineberry,honey", (string id) => BelongsToAnotherGroup(id, "berries", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "vegetables", "Carrot,Turnip", "carrot,turnip,onion,fiddleheadfern,kale", (string id) => BelongsToAnotherGroup(id, "vegetables", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "cookedMeat", "CookedLoxMeat,NeckTailGrilled,MeatCooked,FishCooked,SerpentMeatCooked", "meat_cooked,boar_meat_cooked,deer_meat_cooked,wolf_meat_cooked,necktailgrilled,fish_cooked,loxmeat_cooked,serpentmeatcooked,hare_meat_cooked,chicken_meat_cooked,asksvin_meat_cooked,volture_meat_cooked,bonemawmeat_cooked,bjorn_meat_cooked,bug_meat_cooked,moose_meat_cooked,blubber_cooked,egg_cooked,smokedfish,smokedmoosemeat", (string id) => BelongsToAnotherGroup(id, "cookedMeat", defaultGroupByItem, newPrefixSet));
				MigrateIdList(config, "ItemGroup", "food", "CarrotSoup,Sausages,QueensJam,SerpentStew,TurnipStew,BloodPudding", "Sausages,QueensJam,BloodPudding", (string id) => BelongsToAnotherGroup(id, "food", defaultGroupByItem, newPrefixSet));
				storedModVersion.Value = 20;
			}
			void AddDefaultGroup(string itemCsv, string group)
			{
				foreach (string item in ParseIdSet(itemCsv))
				{
					defaultGroupByItem[item] = group;
				}
			}
		}

		private static HashSet<string> ParseIdSet(string csv)
		{
			HashSet<string> hashSet = new HashSet<string>();
			if (string.IsNullOrEmpty(csv))
			{
				return hashSet;
			}
			string[] array = csv.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].SCName().Replace(" ", "");
				if (text.Length > 0)
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		private static void MigrateIdList(ConfigFile config, string section, string key, string oldDefault, string newDefault, Func<string, bool> dropAdded)
		{
			ConfigEntry<string> val = default(ConfigEntry<string>);
			if (!config.TryGetEntry<string>(section, key, ref val))
			{
				return;
			}
			HashSet<string> hashSet = ParseIdSet(val.Value);
			HashSet<string> hashSet2 = ParseIdSet(oldDefault);
			HashSet<string> collection = ParseIdSet(newDefault);
			HashSet<string> hashSet3 = new HashSet<string>(hashSet2);
			hashSet3.ExceptWith(hashSet);
			HashSet<string> hashSet4 = new HashSet<string>(hashSet);
			hashSet4.ExceptWith(hashSet2);
			if (dropAdded != null)
			{
				hashSet4.RemoveWhere((string id) => dropAdded(id));
			}
			HashSet<string> hashSet5 = new HashSet<string>(collection);
			hashSet5.ExceptWith(hashSet3);
			hashSet5.UnionWith(hashSet4);
			if (!hashSet5.SetEquals(hashSet))
			{
				string text = string.Join(",", hashSet5.OrderBy((string id) => id));
				Mod.log.LogInfo((object)("migrate " + section + "." + key + " -> " + text));
				val.Value = text;
			}
		}

		private static bool BelongsToAnotherGroup(string itemId, string group, Dictionary<string, string> defaultGroupByItem, ISet<string> prefixes)
		{
			string text = GroupOfItem(itemId, defaultGroupByItem, prefixes);
			if (text != null)
			{
				return text != group;
			}
			return false;
		}

		private static string GroupOfItem(string itemId, Dictionary<string, string> defaultGroupByItem, ISet<string> prefixes)
		{
			if (defaultGroupByItem.TryGetValue(itemId, out var value))
			{
				return value;
			}
			if (itemId.EndsWith("berries") || itemId == "vineberry")
			{
				return "berries";
			}
			if (ScIsCooked(itemId))
			{
				return "cookedMeat";
			}
			if (ScIsRaw(itemId))
			{
				return "rawMeat";
			}
			if (ScIsSkin(itemId))
			{
				return "skins";
			}
			if (DrinkExtraSc.Contains(itemId))
			{
				return "drinks";
			}
			string text = LongestPrefixSc(itemId, prefixes);
			if (text == "mead")
			{
				return "drinks";
			}
			if (text != null)
			{
				return "prefix:" + text;
			}
			if (itemId.EndsWith("seeds"))
			{
				return "seeds";
			}
			return null;
		}

		private static bool ScIsRaw(string sc)
		{
			if (sc == "meatrotten" || sc == "mashedmeat" || sc.StartsWith("smoked"))
			{
				return false;
			}
			switch (sc)
			{
			case "meatraw":
			case "fishraw":
			case "loxmeat":
			case "serpentmeat":
			case "bonemawmeat":
			case "necktail":
			case "blubber":
				return true;
			default:
				if (sc.EndsWith("meat"))
				{
					return !sc.Contains("cooked");
				}
				return false;
			}
		}

		private static bool ScIsCooked(string sc)
		{
			if (sc.Contains("uncooked"))
			{
				return false;
			}
			switch (sc)
			{
			case "necktailgrilled":
			case "smokedfish":
			case "smokedmoosemeat":
				return true;
			default:
				if (!sc.Contains("meatcooked"))
				{
					return sc.EndsWith("cooked");
				}
				return true;
			}
		}

		private static bool ScIsSkin(string sc)
		{
			if (!sc.EndsWith("hide") && !sc.EndsWith("pelt") && !sc.EndsWith("scale"))
			{
				return false;
			}
			if (!sc.StartsWith("cape") && !sc.StartsWith("shield") && !sc.StartsWith("helmet") && !sc.StartsWith("chest") && !sc.StartsWith("legs") && !sc.StartsWith("trophy"))
			{
				return !sc.StartsWith("spear");
			}
			return false;
		}

		private static string LongestPrefixSc(string sc, ISet<string> prefixes)
		{
			string text = null;
			foreach (string prefix in prefixes)
			{
				bool flag = ((prefix == "shield") ? (sc.StartsWith("shield") && sc != "shieldcore") : ((!(prefix == "axe")) ? sc.StartsWith(prefix) : (sc.StartsWith("axe") && !sc.StartsWith("axehead"))));
				if (flag && (text == null || prefix.Length > text.Length))
				{
					text = prefix;
				}
			}
			return text;
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? ShowRangeAsPercent;

		public Action<ConfigEntryBase> CustomDrawer;

		public bool? Browsable;

		public string Category;

		public object DefaultValue;

		public bool? HideDefaultButton;

		public bool? HideSettingName;

		public string Description;

		public string DispName;

		public int? Order;

		public bool? ReadOnly;

		public bool? IsAdvanced;

		public Func<object, string> ObjToStr;

		public Func<string, object> StrToObj;
	}
	public static class ContainersTracker
	{
		public static ICollection<Container> containerList = new List<Container>();

		public static bool isRearrangingItem = false;

		public static bool teleportingInProgress = false;

		public static List<Container> GetNearbyContainers(Vector3 center, bool all = false)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			foreach (Container container in containerList)
			{
				int num = (all ? (Mod.range.Value * 2) : Mod.range.Value);
				if ((Object)(object)container != (Object)null && (Object)(object)((Component)container).transform != (Object)null && container.GetInventory() != null && (Object)(object)((Component)container).GetComponentInParent<Piece>() != (Object)null)
				{
					float num2 = Vector3.Distance(center, ((Component)container).transform.position);
					if ((num <= 0 || num2 < (float)num) && container.CheckAccess(Player.m_localPlayer.GetPlayerID()))
					{
						list.Add(container);
					}
				}
			}
			return list;
		}

		public static bool IsReliableRoutingTarget(Container container)
		{
			return GetRoutingExclusionReason(container) == null;
		}

		internal static bool ShouldTrackRoutingTarget(Container container)
		{
			if (Mod.unsafeTargetEnabled || IsReliableRoutingTarget(container))
			{
				return true;
			}
			LogExcludedTarget(container);
			return false;
		}

		public static void RemoveUnsafeRoutingTargets()
		{
			if (Mod.unsafeTargetEnabled)
			{
				return;
			}
			foreach (Container item in containerList.ToList())
			{
				if ((Object)(object)item != (Object)null && !IsReliableRoutingTarget(item))
				{
					LogExcludedTarget(item);
					containerList.Remove(item);
				}
			}
		}

		private static void LogExcludedTarget(Container container)
		{
			Mod.log.LogWarning((object)("[SmartContainers excluded target] reason=" + GetRoutingExclusionReason(container) + " name=" + ((Object)container).name + " componentTypes=" + DescribeComponentHierarchy(container)));
		}

		private static string GetRoutingExclusionReason(Container container)
		{
			if ((Object)(object)container.m_rootObjectOverride != (Object)null)
			{
				return "uses m_rootObjectOverride";
			}
			if ((Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null)
			{
				return "has Ship host";
			}
			if ((Object)(object)container.m_wagon != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null)
			{
				return "has Vagon host";
			}
			if ((Object)(object)((Component)container).GetComponentInParent<Incinerator>() != (Object)null)
			{
				return "has Incinerator host";
			}
			if ((Object)(object)((Component)container).GetComponentInParent<TombStone>() != (Object)null)
			{
				return "has TombStone host";
			}
			if ((Object)(object)((Component)container).GetComponentInParent<Corpse>() != (Object)null)
			{
				return "has Corpse host";
			}
			return null;
		}

		private static string DescribeComponentHierarchy(Container container)
		{
			List<string> list = new List<string>();
			Transform val = ((Component)container).transform;
			while ((Object)(object)val != (Object)null)
			{
				string[] value = (from component in ((Component)val).GetComponents<Component>()
					where (Object)(object)component != (Object)null && !(component is Transform)
					select ((object)component).GetType().FullName).Distinct().ToArray();
				list.Add(((Object)val).name + ":[" + string.Join(",", value) + "]");
				val = val.parent;
			}
			return string.Join(" <- ", list);
		}

		public static void Init()
		{
			Container[] array = Object.FindObjectsOfType<Container>();
			Mod.log.LogDebug((object)$"tracking {array.Length} discovered containers.");
			Container[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				TryTrack(array2[i]);
			}
		}

		internal static bool TryTrack(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			if (((Object)container).name.StartsWith("Treasure"))
			{
				return false;
			}
			if (container.GetInventory() == null)
			{
				return false;
			}
			if (!HasNetworkIdentityForTracking(container))
			{
				return false;
			}
			if (!ShouldTrackRoutingTarget(container))
			{
				return false;
			}
			if (!containerList.Contains(container))
			{
				containerList.Add(container);
			}
			OwnerPut.Register(container);
			return true;
		}

		public static void CleanupContainersList()
		{
			Mod.log.LogDebug((object)$"cleanup containerList. size before: {containerList.Count}");
			foreach (Container item in containerList.ToList())
			{
				if (!((Object)(object)item != (Object)null) || !((Object)(object)((Component)item).transform != (Object)null) || item.GetInventory() == null)
				{
					containerList.Remove(item);
				}
			}
			Mod.log.LogDebug((object)$"cleanup containerList. size after: {containerList.Count}");
		}

		internal static bool HasNetworkIdentityForTracking(Container container)
		{
			if ((Object)(object)container?.m_nview == (Object)null || !container.m_nview.IsValid())
			{
				return false;
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (zDO != null)
			{
				if (zDO.GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) == 0L)
				{
					return zDO.GetOwner() != 0;
				}
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class Container_Awake_Patch
	{
		private static void Postfix(Container __instance)
		{
			if (Mod.modEnabled.Value)
			{
				ContainersTracker.TryTrack(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Container), "OnDestroyed")]
	internal static class Container_OnDestroyed_Patch
	{
		private static void Prefix(Container __instance)
		{
			if (Mod.modEnabled.Value)
			{
				ContainersTracker.containerList.Remove(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OpenServer")]
	internal static class ZNet_OpenServer_Patch
	{
		private static void Postfix()
		{
			if (Mod.modEnabled.Value)
			{
				ContainersTracker.RemoveUnsafeRoutingTargets();
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "StackAll")]
	internal static class Container_OnStackAll_Patch
	{
		private static void Postfix(Inventory __instance, Inventory fromInventory, bool message)
		{
			if (Mod.unloadAllEnabled.Value && Mod.unloadAllInsteadStackBtn.Value)
			{
				InventoryGui instance = InventoryGui.instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_playerGrid == (Object)null) && !((Object)(object)instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting())
				{
					UnloadItems.UnloadAllItems(((Humanoid)Player.m_localPlayer).GetInventory());
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateTeleport")]
	public static class PlayerUpdateTeleport_Patch_Cleanup_Containers
	{
		public static void Prefix(float dt)
		{
			if (Mod.modEnabled.Value)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && localPlayer.m_teleporting && !ContainersTracker.teleportingInProgress)
				{
					OwnerPut.RestoreAllPending();
					OwnershipHandoff.Clear();
					ContainersTracker.teleportingInProgress = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateTeleport")]
	public static class PlayerUpdateTeleport_Postfix
	{
		public static void Postfix(float dt)
		{
			if (Mod.modEnabled.Value)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && ContainersTracker.teleportingInProgress && !localPlayer.m_teleporting)
				{
					ContainersTracker.CleanupContainersList();
					ContainersTracker.teleportingInProgress = false;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData)
	})]
	public static class Inventory_Patch
	{
		internal enum DepositResult
		{
			Done,
			Pending,
			Failed
		}

		internal static bool LastMissInUse;

		public static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item)
		{
			if (BagStackBlocked(item))
			{
				return false;
			}
			if (!ShouldHandle(__instance, fromInventory, item))
			{
				return true;
			}
			if (__instance.HaveItem(item.m_shared.m_name, true))
			{
				return true;
			}
			return !TryRouteFromPlayer(fromInventory, __instance, item);
		}

		public static void Postfix(Inventory __instance, Inventory fromInventory, ItemData item)
		{
			if (!BagStackBlocked(item) && ShouldHandle(__instance, fromInventory, item) && fromInventory.ContainsItem(item))
			{
				TryRouteFromPlayer(fromInventory, __instance, item);
			}
		}

		private static bool ShouldHandle(Inventory dest, Inventory from, ItemData item)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if (!Mod.modEnabled.Value)
			{
				return false;
			}
			if (dest == null || from == null || item == null)
			{
				return false;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsTeleporting())
			{
				return false;
			}
			if (((object)dest).Equals((object?)((Humanoid)Player.m_localPlayer).GetInventory()))
			{
				return false;
			}
			if (from != ((Humanoid)Player.m_localPlayer).GetInventory())
			{
				return false;
			}
			if (Mod.onlyStackableItems.Value && item.m_shared.m_maxStackSize == 1)
			{
				return false;
			}
			if (ContainersTracker.isRearrangingItem)
			{
				return false;
			}
			if (Input.GetKey((KeyCode)108))
			{
				Console.instance.Print("SmartContainers tracked item [" + item.m_shared.m_name + "]");
			}
			KeyboardShortcut value = Mod.keyModifier.Value;
			if (!((KeyboardShortcut)(ref value)).IsPressed())
			{
				value = Mod.groupingKeyModifier.Value;
				if (!((KeyboardShortcut)(ref value)).IsPressed() && (!ZInput.GetButton(Mod.gamepadKey1.Value) || !ZInput.GetButton(Mod.gamepadKey2.Value.ToString())))
				{
					return false;
				}
			}
			if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.instance.IsContainerOpen())
			{
				return false;
			}
			if (InventoryGui.instance.m_currentContainer.GetInventory() != dest)
			{
				return false;
			}
			if (!Mod.unsafeTargetEnabled && !Mod.unsafeSourceEnabled.Value && !ContainersTracker.IsReliableRoutingTarget(InventoryGui.instance.m_currentContainer))
			{
				return false;
			}
			return true;
		}

		private static bool TryRouteFromPlayer(Inventory fromInventory, Inventory dest, ItemData item)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			ContainersTracker.isRearrangingItem = true;
			try
			{
				if (TryHandleDrawers(item))
				{
					fromInventory.RemoveItem(item);
					dest.Changed(false, false);
					fromInventory.Changed(false, false);
					Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint());
					return true;
				}
				Container val = FindRouteTarget(item);
				if ((Object)(object)val == (Object)null)
				{
					OwnerPut.DebugCenter("SC route failed: no chest");
					return false;
				}
				if (Mod.concurrencyWorkaround.Value.UsesRpc())
				{
					int num = RouteNotice.Open();
					DepositResult num2 = Deposit(val, item, fromInventory, allowCurrent: false, playAudio: true, num);
					if (num2 == DepositResult.Done)
					{
						RouteNotice.Moved(num);
					}
					RouteNotice.Close(num);
					if (num2 == DepositResult.Failed)
					{
						OwnerPut.DebugCenter("SC route failed: put");
						return false;
					}
					dest.Changed(false, false);
					return true;
				}
				if (!AddItemToContainer(item, val))
				{
					OwnerPut.DebugCenter("SC route failed: add");
					return false;
				}
				fromInventory.RemoveItem(item);
				dest.Changed(false, false);
				fromInventory.Changed(false, false);
				PlayRoutedFeedback(item, val, playAudio: true);
				return true;
			}
			finally
			{
				ContainersTracker.isRearrangingItem = false;
			}
		}

		internal static bool TryHandleDrawers(ItemData item)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			if (!Mod.drawersIntegrationEnabled.Value)
			{
				return false;
			}
			if ((Object)(object)item?.m_dropPrefab == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			foreach (ItemDrawers_API.Drawer item2 in ItemDrawers_API.AllDrawersInRange(((Component)Player.m_localPlayer).transform.position, Mod.range.Value))
			{
				if (((Object)item.m_dropPrefab).name.Equals(item2.Prefab))
				{
					Console.instance.Print($"{item.m_stack}-of-{Localization.instance.Localize(item.m_shared.m_name)} routed because Drawer has same item stack");
					item2.Add(item.m_stack);
					if (Mod.hudMessageEnabled.Value && (Object)(object)MessageHud.instance != (Object)null)
					{
						MessageHud.instance.QueueUnlockMsg(item.GetIcon(), item.m_shared.m_name, Mod.hudMessageText.Value);
					}
					Mod.PlayEffect(Mod.effectFeedbackEnabled.Value, "vfx_Potion_health_medium", item2.Position);
					return true;
				}
			}
			return false;
		}

		public static Container FindRouteTarget(ItemData item, bool allowCurrent = false, bool forceGrouping = false)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			LastMissInUse = false;
			try
			{
				List<Container> nearbyRoutingCandidates = GetNearbyRoutingCandidates();
				if (nearbyRoutingCandidates == null)
				{
					return null;
				}
				Container openedContainer = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_currentContainer : null);
				foreach (Container item2 in nearbyRoutingCandidates)
				{
					Inventory inventory = item2.GetInventory();
					if (Accept(item2, inventory != null && (allowCurrent || (Object)(object)openedContainer == (Object)null || ((object)openedContainer).GetHashCode() != ((object)item2).GetHashCode()) && inventory.HaveItem(item.m_shared.m_name, true)))
					{
						Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has same item stack");
						return item2;
					}
				}
				KeyboardShortcut value;
				if (Mod.groupingEnabled.Value)
				{
					if (!forceGrouping)
					{
						value = Mod.groupingKeyModifier.Value;
						if (!((KeyboardShortcut)(ref value)).IsPressed() && !ZInput.IsGamepadActive())
						{
							goto IL_0420;
						}
					}
					List<Tuple<string, Container>> list = new List<Tuple<string, Container>>();
					foreach (Container item3 in nearbyRoutingCandidates)
					{
						string text = ItemGroups.FindMatchingUserGroup(item3, item);
						if (text == null)
						{
							continue;
						}
						if (!CanRouteTo(item3, item, openedContainer, allowCurrent))
						{
							if (InUseWithoutMod(item3))
							{
								LastMissInUse = true;
							}
						}
						else
						{
							list.Add(Tuple.Create<string, Container>(text, item3));
						}
					}
					if (list.Any())
					{
						Tuple<string, Container> tuple = list.OrderByDescending((Tuple<string, Container> t) => t.Item1).First();
						if (list.Count > 1)
						{
							Mod.log.LogWarning((object)("Ambiguous item-groups [" + string.Join(",", list) + "] found for " + ((Object)item.m_dropPrefab).name + " item. Using " + tuple.Item1));
						}
						Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item from group " + tuple.Item1 + " : [" + string.Join(",", ItemGroups.Groups[tuple.Item1]) + "]");
						return tuple.Item2;
					}
					foreach (Container item4 in nearbyRoutingCandidates)
					{
						if (Accept(item4, ItemGroups.ContainerHasSame_SystemGroupItems(item4, item)))
						{
							return item4;
						}
					}
					foreach (Container item5 in nearbyRoutingCandidates)
					{
						if (Accept(item5, ItemGroups.ContainerHasSame_PatternItems(item5, item)))
						{
							return item5;
						}
					}
					foreach (Container item6 in nearbyRoutingCandidates)
					{
						if (Accept(item6, ItemGroups.ContainerHasSame_PostfixItems(item6, item)))
						{
							return item6;
						}
					}
					if (Mod.itemTypeGroupsEnabled.Value)
					{
						foreach (Container item7 in nearbyRoutingCandidates)
						{
							if (Accept(item7, ItemGroups.ContainerHasSameItemType(item7, item)))
							{
								return item7;
							}
						}
					}
					goto IL_0420;
				}
				goto IL_0496;
				IL_0496:
				return null;
				IL_0420:
				if (Mod.fuzzyGroupingEnabled.Value)
				{
					if (!forceGrouping)
					{
						value = Mod.groupingKeyModifier.Value;
						if (!((KeyboardShortcut)(ref value)).IsPressed() && !ZInput.IsGamepadActive())
						{
							goto IL_0496;
						}
					}
					foreach (Container item8 in nearbyRoutingCandidates)
					{
						if (Accept(item8, ItemGroups.ContainerHasSimilarGroupItems(item8, item)))
						{
							return item8;
						}
					}
				}
				goto IL_0496;
				bool Accept(Container candidate, bool matched)
				{
					if (!matched)
					{
						return false;
					}
					if (CanRouteTo(candidate, item, openedContainer, allowCurrent))
					{
						return true;
					}
					if (InUseWithoutMod(candidate))
					{
						LastMissInUse = true;
					}
					return false;
				}
			}
			catch (Exception ex)
			{
				Mod.log.LogError((object)("Failed to rearrange container items: " + ex));
			}
			return null;
		}

		internal static List<Container> GetNearbyRoutingCandidates()
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)InventoryGui.instance == (Object)null)
			{
				return null;
			}
			Container openedContainer = InventoryGui.instance.m_currentContainer;
			if ((Object)(object)openedContainer == (Object)null)
			{
				return null;
			}
			if (Mod.concurrencyWorkaround.Value.BlockIfAnyOtherOpened() && ContainersTracker.GetNearbyContainers(((Component)Player.m_localPlayer).transform.position, all: true).Any((Container c) => ((object)openedContainer).GetHashCode() != ((object)c).GetHashCode() && c.m_nview.GetZDO().GetInt("InUse", 0) == 1))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "Cant distribute items: other Player is using containers nearby.", 0, (Sprite)null, false);
				return null;
			}
			return ContainersTracker.GetNearbyContainers(((Component)Player.m_localPlayer).transform.position).Where(delegate(Container c)
			{
				if (((object)openedContainer).GetHashCode() == ((object)c).GetHashCode())
				{
					return true;
				}
				if (Mod.concurrencyWorkaround.Value.Ignore())
				{
					return true;
				}
				ZDO zDO = c.m_nview.GetZDO();
				if (zDO == null)
				{
					return false;
				}
				bool flag = zDO.GetInt("InUse", 0) == 1;
				if (Mod.concurrencyWorkaround.Value.UsesRpc())
				{
					if (zDO.GetOwner() == 0L)
					{
						return false;
					}
					if (flag)
					{
						return OwnerPut.PeerHasFlag(c);
					}
					return true;
				}
				return (Mod.concurrencyWorkaround.Value.SkipOpenedOthers() || Mod.concurrencyWorkaround.Value.BlockIfAnyOtherOpened()) && !flag;
			}).ToList();
		}

		private static bool CanRouteTo(Container target, ItemData item, Container opened, bool allowCurrent)
		{
			if ((Object)(object)target == (Object)null || target.GetInventory() == null)
			{
				return false;
			}
			if (Mod.concurrencyWorkaround.Value.UsesRpc() && !target.IsOwner())
			{
				ZDO val = (((Object)(object)target.m_nview != (Object)null) ? target.m_nview.GetZDO() : null);
				if (val == null || val.GetOwner() == 0L)
				{
					return false;
				}
				if (val.GetInt("InUse", 0) == 1 && !OwnerPut.PeerHasFlag(target))
				{
					return false;
				}
			}
			if (!target.GetInventory().CanAddItem(item, -1))
			{
				return false;
			}
			if (!allowCurrent && (Object)(object)opened != (Object)null && ((object)opened).GetHashCode() == ((object)target).GetHashCode())
			{
				return false;
			}
			return true;
		}

		private static bool InUseWithoutMod(Container target)
		{
			if (!Mod.concurrencyWorkaround.Value.UsesRpc() || (Object)(object)target == (Object)null || target.IsOwner())
			{
				return false;
			}
			ZDO val = (((Object)(object)target.m_nview != (Object)null) ? target.m_nview.GetZDO() : null);
			if (val == null || val.GetOwner() == 0L)
			{
				return false;
			}
			if (val.GetInt("InUse", 0) == 1)
			{
				return !OwnerPut.PeerHasFlag(target);
			}
			return false;
		}

		internal static DepositResult Deposit(Container target, ItemData item, Inventory from, bool allowCurrent, bool playAudio, int batch)
		{
			if (BagStackBlocked(item))
			{
				return DepositResult.Pending;
			}
			if (target.IsOwner())
			{
				if (!AddItemToContainer(item, target, allowCurrent))
				{
					return DepositResult.Failed;
				}
				from.RemoveItem(item);
				PlayRoutedFeedback(item, target, playAudio);
				return DepositResult.Done;
			}
			ZDO val = (((Object)(object)target.m_nview != (Object)null) ? target.m_nview.GetZDO() : null);
			if (val == null || val.GetOwner() == 0L)
			{
				return DepositResult.Failed;
			}
			if (val.GetInt("InUse", 0) == 1)
			{
				if (!OwnerPut.PeerHasFlag(target))
				{
					return DepositResult.Failed;
				}
				if (!OwnerPut.BeginRemotePut(target, item, from))
				{
					return DepositResult.Failed;
				}
				return DepositResult.Pending;
			}
			if (!OwnershipHandoff.Begin(target, item, from, playAudio, batch))
			{
				return DepositResult.Failed;
			}
			return DepositResult.Pending;
		}

		internal static bool BagStackBlocked(ItemData item)
		{
			if (item != null)
			{
				if (!OwnerPut.IsAwaitingLateOk(item))
				{
					return OwnershipHandoff.Holds(item);
				}
				return true;
			}
			return false;
		}

		internal static bool AddItemToContainer(ItemData item, Container targetContainer, bool allowCurrent = false)
		{
			if ((Object)(object)targetContainer == (Object)null || item == null)
			{
				return false;
			}
			if (Mod.concurrencyWorkaround.Value.UsesRpc() && !targetContainer.IsOwner())
			{
				return false;
			}
			Container val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_currentContainer : null);
			if (allowCurrent || (Object)(object)val == (Object)null || ((object)val).GetHashCode() != ((object)targetContainer).GetHashCode())
			{
				bool num = targetContainer.GetInventory().AddItem(item);
				if (num && (!Mod.concurrencyWorkaround.Value.UsesRpc() || !targetContainer.IsOwner()))
				{
					targetContainer.Save();
				}
				return num;
			}
			return false;
		}

		internal static void PlayRoutedFeedback(ItemData item, Container targetContainer, bool playAudio)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (item != null)
			{
				if (playAudio && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint());
				}
				Container val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_currentContainer : null);
				if (Mod.hudMessageEnabled.Value && (Object)(object)MessageHud.instance != (Object)null && ((Object)(object)val == (Object)null || !((object)val).Equals((object?)targetContainer)))
				{
					MessageHud.instance.QueueUnlockMsg(item.GetIcon(), item.m_shared.m_name, Mod.hudMessageText.Value);
				}
				if ((Object)(object)targetContainer != (Object)null)
				{
					Mod.PlayEffect(Mod.effectFeedbackEnabled.Value, "vfx_Potion_health_medium", ((Component)targetContainer).transform.position);
				}
			}
		}
	}
	internal static class RouteNotice
	{
		private sealed class Batch
		{
			public int Moved;

			public int Busy;

			public int Pending;
		}

		private static int next;

		private static readonly Dictionary<int, Batch> OpenBatches = new Dictionary<int, Batch>();

		public static int Open()
		{
			int num = ++next;
			OpenBatches[num] = new Batch();
			return num;
		}

		public static void Moved(int id)
		{
			if (OpenBatches.TryGetValue(id, out var value))
			{
				value.Moved++;
			}
		}

		public static void Busy(int id)
		{
			if (OpenBatches.TryGetValue(id, out var value))
			{
				value.Busy++;
			}
		}

		public static void Pending(int id)
		{
			if (id != 0 && OpenBatches.TryGetValue(id, out var value))
			{
				value.Pending++;
			}
		}

		public static void Settle(int id, bool moved)
		{
			if (OpenBatches.TryGetValue(id, out var value))
			{
				if (value.Pending > 0)
				{
					value.Pending--;
				}
				if (moved)
				{
					value.Moved++;
				}
				else
				{
					value.Busy++;
				}
				Announce(id, value);
			}
		}

		public static void Drop(int id)
		{
			if (OpenBatches.TryGetValue(id, out var value))
			{
				if (value.Pending > 0)
				{
					value.Pending--;
				}
				Announce(id, value);
			}
		}

		public static void Close(int id)
		{
			if (OpenBatches.TryGetValue(id, out var value))
			{
				Announce(id, value);
			}
		}

		public static void Clear()
		{
			OpenBatches.Clear();
		}

		private static void Announce(int id, Batch batch)
		{
			if (batch.Pending <= 0)
			{
				OpenBatches.Remove(id);
				if (batch.Busy != 0 && !((Object)(object)Player.m_localPlayer == (Object)null))
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, (batch.Moved == 0) ? "$msg_inuse" : "Some items were not moved", 0, (Sprite)null, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData),
		typeof(int),
		typeof(int),
		typeof(int)
	})]
	internal static class Inventory_MoveItemToSlot_Patch
	{
		private static bool Prefix(ItemData item)
		{
			return !Inventory_Patch.BagStackBlocked(item);
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "DropItem")]
	internal static class InventoryGrid_DropItem_Patch
	{
		private static bool Prefix(ItemData item)
		{
			return !Inventory_Patch.BagStackBlocked(item);
		}
	}
	[HarmonyPatch(typeof(Humanoid), "DropItem", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData),
		typeof(int)
	})]
	internal static class Humanoid_DropItem_Patch
	{
		private static bool Prefix(ItemData item)
		{
			return !Inventory_Patch.BagStackBlocked(item);
		}
	}
	public static class ItemDrawers_API
	{
		public class Drawer
		{
			private readonly ZNetView znv;

			public readonly string Prefab;

			public readonly Vector3 Position;

			public readonly int Amount;

			public Drawer(ZNetView znv)
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				this.znv = znv;
				Amount = znv.m_zdo.GetInt("Amount", 0);
				Position = znv.m_zdo.GetPosition();
				Prefab = znv.m_zdo.GetString("Prefab", "");
			}

			public void Remove(int amount)
			{
				znv.ClaimOwnership();
				znv.InvokeRPC("ForceRemove", new object[1] { amount });
			}

			public void Withdraw(int amount)
			{
				znv.InvokeRPC("WithdrawItem_Request", new object[1] { amount });
			}

			public void Add(int amount)
			{
				znv.InvokeRPC("AddItem_Request", new object[2] { Prefab, amount });
			}
		}

		private static readonly bool _IsInstalled;

		private static readonly MethodInfo MI_GetAllDrawers;

		public static List<Drawer> AllDrawers
		{
			get
			{
				if (!_IsInstalled)
				{
					return new List<Drawer>();
				}
				return ((List<ZNetView>)MI_GetAllDrawers.Invoke(null, null)).Select((ZNetView znv) => new Drawer(znv)).ToList();
			}
		}

		public static List<Drawer> AllDrawersInRange(Vector3 pos, float range)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!_IsInstalled)
			{
				return new List<Drawer>();
			}
			return (from znv in (List<ZNetView>)MI_GetAllDrawers.Invoke(null, null)
				where Vector3.Distance(((Component)znv).transform.position, pos) <= range
				select new Drawer(znv)).ToList();
		}

		static ItemDrawers_API()
		{
			Type type = Type.GetType("API.ClientSide, kg_ItemDrawers");
			if ((object)type == null)
			{
				_IsInstalled = false;
				return;
			}
			_IsInstalled = true;
			MI_GetAllDrawers = type.GetMethod("AllDrawers", BindingFlags.Static | BindingFlags.Public);
		}
	}
	public static class GuiFactory
	{
		public static Transform AddContainerGuiButton(string btnObjName, string text, Vector2 size, Vector2 pos)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return CreateButton(btnObjName, text, ((Component)InventoryGui.instance.m_takeAllButton).transform.parent, size, pos);
		}

		public static Transform CreateButton(string btnObjName, string text, Transform parent, Vector2 size, Vector2 pos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			_ = (RectTransform)parent.Find(btnObjName);
			Transform obj = Object.Instantiate<Transform>(((Component)InventoryGui.instance.m_takeAllButton).transform, parent);
			((Object)obj).name = btnObjName;
			RectTransform val = (RectTransform)((Component)obj).transform;
			val.SetSizeWithCurrentAnchors((Axis)0, size.x);
			val.SetSizeWithCurrentAnchors((Axis)1, size.y);
			RectTransform val2 = (RectTransform)((Component)val).transform.Find("Text");
			val2.SetSizeWithCurrentAnchors((Axis)0, size.x);
			val2.SetSizeWithCurrentAnchors((Axis)1, size.y);
			((TMP_Text)((Component)val2).GetComponent<TextMeshProUGUI>()).text = text;
			val.pivot = pos;
			return (Transform)val;
		}

		public static void InitJoyKey(Transform btnComponent, string joyKeyCode, string tooltip)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			UIGamePad component = ((Component)btnComponent).GetComponent<UIGamePad>();
			Transform val = Object.Instantiate<Transform>(((Component)btnComponent).transform.Find("Text"), ((Component)component).transform);
			TextMeshProUGUI component2 = ((Component)val).GetComponent<TextMeshProUGUI>();
			((TMP_Text)component2).text = tooltip;
			((Graphic)component2).color = new Color(0.8f, 0.8f, 0.8f, 1f);
			Transform transform = ((Component)val).transform;
			transform.position += new Vector3(0f, 13f, 0f);
			if ((Object)(object)component.m_hint != (Object)null)
			{
				Object.Destroy((Object)(object)component.m_hint);
			}
			((Component)val).gameObject.SetActive(false);
			component.m_hint = ((Component)val).gameObject;
			component.m_zinputKey = joyKeyCode;
			component.m_availableForConsoleMouse = false;
		}

		public static void RefreshJoyHint(Transform btn)
		{
			if (!Object.op_Implicit((Object)(object)btn) || ZInput.instance == null)
			{
				return;
			}
			UIGamePad component = ((Component)btn).GetComponent<UIGamePad>();
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_hint) && !string.IsNullOrEmpty(component.m_zinputKey))
			{
				TextMeshProUGUI component2 = component.m_hint.GetComponent<TextMeshProUGUI>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					((Behaviour)component2).enabled = true;
					((TMP_Text)component2).text = ZInput.instance.GetBoundKeyString(component.m_zinputKey, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Show")]
	public static class Gui_Patch
	{
		public static bool initialized;

		private static Transform createGroupButton;

		private static Transform storeAllButton;

		private static TMP_Text routingDisabledLabel;

		private static void Postfix(InventoryGui __instance)
		{
			if (Mod.modEnabled.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && __instance.IsContainerOpen())
			{
				if (!initialized)
				{
					InitButtons(__instance);
				}
				RefreshJoyHints();
				UpdateRoutingDisabledLabel(__instance);
			}
		}

		private static void InitButtons(InventoryGui __instance)
		{
			if (!Mod.modEnabled.Value)
			{
				return;
			}
			try
			{
				AddRoutingDisabledLabel(__instance);
				if ((Mod.groupingEnabled.Value || Mod.unloadAllEnabled.Value) && Mod.createGroupBtnEnabled.Value)
				{
					AddCreateGroupBtn(__instance);
				}
				if (Mod.unloadAllEnabled.Value && !Mod.unloadAllInsteadStackBtn.Value)
				{
					AddStoreAllBtn(__instance);
				}
				initialized = true;
			}
			catch (Exception ex)
			{
				Mod.log.LogError((object)("Failed to properly patch GUI with additional buttons: " + ex));
				Clean();
			}
			finally
			{
				Mod.log.LogInfo((object)"Initialized UI extensions.");
			}
		}

		private static void AddRoutingDisabledLabel(InventoryGui inventoryGui)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)routingDisabledLabel != (Object)null) && !((Object)(object)inventoryGui.m_containerName == (Object)null))
			{
				routingDisabledLabel = Object.Instantiate<TMP_Text>(inventoryGui.m_containerName, (Transform)(object)inventoryGui.m_container);
				((Object)routingDisabledLabel).name = "smartRoutingDisabledLabel";
				routingDisabledLabel.text = "Smart Routing disabled";
				((Graphic)routingDisabledLabel).color = new Color(1f, 0.55f, 0.2f, 1f);
				routingDisabledLabel.fontSize = Mathf.Max(12f, inventoryGui.m_containerName.fontSize * 0.5f);
				((Graphic)routingDisabledLabel).raycastTarget = false;
				RectTransform val = (RectTransform)routingDisabledLabel.transform;
				val.anchorMin = new Vector2(0f, 0f);
				val.anchorMax = new Vector2(0f, 0f);
				val.pivot = new Vector2(0f, 0f);
				val.anchoredPosition = new Vector2(-16f, -16f);
				((Component)routingDisabledLabel).gameObject.SetActive(false);
			}
		}

		private static void UpdateRoutingDisabledLabel(InventoryGui inventoryGui)
		{
			if (!((Object)(object)routingDisabledLabel == (Object)null))
			{
				Container currentContainer = inventoryGui.m_currentContainer;
				bool flag = (Object)(object)currentContainer != (Object)null && (Mod.unsafeTargetEnabled || Mod.unsafeSourceEnabled.Value || ContainersTracker.IsReliableRoutingTarget(currentContainer));
				((Component)routingDisabledLabel).gameObject.SetActive(!flag && Mod.unsafeSourceLabelDisplayed.Value);
				if ((Object)(object)createGroupButton != (Object)null)
				{
					((Component)createGroupButton).gameObject.SetActive(flag);
				}
				if ((Object)(object)storeAllButton != (Object)null)
				{
					((Component)storeAllButton).gameObject.SetActive(flag);
				}
			}
		}

		private static void RefreshJoyHints()
		{
			GuiFactory.RefreshJoyHint(createGroupButton);
			GuiFactory.RefreshJoyHint(storeAllButton);
		}

		public static void HideRoutingDisabledLabel()
		{
			if ((Object)(object)routingDisabledLabel != (Object)null)
			{
				((Component)routingDisabledLabel).gameObject.SetActive(false);
			}
		}

		private static void AddCreateGroupBtn(InventoryGui __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			createGroupButton = GuiFactory.AddContainerGuiButton("createGroupBtn", "☀", new Vector2(45f, 30f), Mod.createGroupBtnPos.Value);
			GuiFactory.InitJoyKey(createGroupButton, "JoyMap", ZInput.instance.GetBoundKeyString("JoyMap", false));
			Button component = ((Component)createGroupButton).GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)__instance.m_playerGrid == (Object)null) && !((Object)(object)__instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting())
				{
					Inventory inventory = __instance.m_containerGrid.GetInventory();
					KeyboardShortcut value;
					if (Mod.unloadAllEnabled.Value)
					{
						value = Mod.unloadAllItemsGroupKeyModifier.Value;
						if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("JoyRTrigger"))
						{
							UnloadItems.AddToUnloadAllItemsFilter(inventory);
							return;
						}
					}
					if (Mod.unloadAllEnabled.Value)
					{
						value = Mod.unloadAllSkipItemsGroupKeyModifier.Value;
						if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("JoyLTrigger"))
						{
							UnloadItems.AddToUnloadAllItemsSkipList(inventory);
							return;
						}
					}
					if (Mod.groupingEnabled.Value)
					{
						GroupEditor.Open(inventory, __instance.m_currentContainer);
					}
				}
			});
		}

		private static void AddStoreAllBtn(InventoryGui __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			storeAllButton = GuiFactory.AddContainerGuiButton("storeAllButton", "↓↓↓", new Vector2(45f, 36f), Mod.unloadAllBtnPos.Value);
			GuiFactory.InitJoyKey(storeAllButton, "JoyMenu", ZInput.instance.GetBoundKeyString("JoyMenu", false));
			((UnityEvent)((Component)storeAllButton).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				if (!((Object)(object)__instance.m_playerGrid == (Object)null) && !((Object)(object)__instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting())
				{
					UnloadItems.UnloadAllItems(((Humanoid)Player.m_localPlayer).GetInventory());
				}
			});
		}

		public static void Init()
		{
			if ((Object)(object)InventoryGui.instance != (Object)null)
			{
				InitButtons(InventoryGui.instance);
				if (InventoryGui.instance.IsContainerOpen())
				{
					UpdateRoutingDisabledLabel(InventoryGui.instance);
				}
			}
		}

		public static void Clean()
		{
			if ((Object)(object)createGroupButton != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)createGroupButton).gameObject);
			}
			if ((Object)(object)storeAllButton != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)storeAllButton).gameObject);
			}
			if ((Object)(object)routingDisabledLabel != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)routingDisabledLabel).gameObject);
			}
			GroupEditor.Close();
			initialized = false;
			routingDisabledLabel = null;
			Mod.log.LogInfo((object)"Cleaned up UI extensions.");
		}
	}
	[HarmonyPatch(typeof(UIGamePad), "Update")]
	internal static class ChestHintPatch
	{
		private static void Postfix(UIGamePad __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance.m_hint))
			{
				string name = ((Object)((Component)__instance).gameObject).name;
				if ((!(name != "createGroupBtn") || !(name != "storeAllButton")) && (!ZInput.IsGamepadActive() || ZInput.IsMouseActive()))
				{
					__instance.m_hint.SetActive(false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	public static class Game_Start_Patch
	{
		private static void Postfix(Game __instance)
		{
			Gui_Patch.Clean();
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	public static class Gui_Hide_Patch
	{
		private static void Postfix(InventoryGui __instance)
		{
			if (Gui_Patch.initialized)
			{
				GroupEditor.Close();
				Gui_Patch.HideRoutingDisabledLabel();
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class InventoryGrid_UpdateGui_Patch
	{
		private static readonly Color Dim = new Color(0.35f, 0.5f, 0.75f, 1f);

		private static readonly Color Lit = new Color(0.75f, 0.9f, 1f, 1f);

		private static void Postfix(InventoryGrid __instance)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)__instance != (Object)(object)instance.m_playerGrid)
			{
				return;
			}
			Inventory inventory = __instance.m_inventory;
			if (inventory == null)
			{
				return;
			}
			int width = inventory.GetWidth();
			Color color = Color.Lerp(Dim, Lit, 0.5f + 0.5f * Mathf.Sin(Time.time * 6f));
			List<ItemData> inventory2 = inventory.m_inventory;
			for (int i = 0; i < inventory2.Count; i++)
			{
				ItemData val = inventory2[i];
				if (Inventory_Patch.BagStackBlocked(val))
				{
					InventoryElement element = __instance.GetElement(val.m_gridPos.x, val.m_gridPos.y, width);
					if (!((Object)(object)element?.m_icon == (Object)null))
					{
						((Graphic)element.m_icon).color = color;
					}
				}
			}
		}
	}
	public static class GroupEditor
	{
		private sealed class ItemInfo
		{
			internal string ScName;

			internal string Label;

			internal string Topic;

			internal string Description;

			internal Sprite Icon;

			internal ItemType ItemType;

			internal bool HasType;
		}

		private enum CellRole
		{
			Group,
			Chest,
			Search,
			Rule
		}

		private sealed class Cell
		{
			internal ItemInfo Info;

			internal CellRole Role;

			internal GameObject Root;

			internal Image Background;

			internal Image Icon;

			internal Image Dot;

			internal Image[] Marks;

			internal TextMeshProUGUI Name;

			internal TextMeshProUGUI More;

			internal GameObject Frame;
		}

		private sealed class Row
		{
			internal string Id;

			internal Image Background;

			internal Image Mark;

			internal TextMeshProUGUI Label;

			internal GameObject Frame;

			internal GameObject DeleteHint;
		}

		private enum RuleKind
		{
			Pattern,
			Postfix,
			Type,
			Fuzzy
		}

		private sealed class RuleSet
		{
			internal RuleKind Kind;

			internal string Id;

			internal string Label;

			internal readonly List<ItemInfo> Items = new List<ItemInfo>();
		}

		private sealed class RuleRowUi
		{
			internal RuleSet Set;

			internal Image Background;

			internal Image Mark;

			internal TextMeshProUGUI Label;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__CreateGroup;

			public static UnityAction <1>__AddAllSearch;

			public static UnityAction <2>__CloseSearch;

			public static UnityAction <3>__Close;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Comparison<ItemInfo> <>9__75_0;

			public static UnityAction <>9__80_0;

			public static UnityAction <>9__80_1;

			public static UnityAction<string> <>9__80_2;

			public static UnityAction<string> <>9__80_3;

			public static UnityAction <>9__80_4;

			public static UnityAction <>9__80_5;

			public static Func<string, ItemInfo> <>9__86_0;

			public static Func<ItemInfo, bool> <>9__86_1;

			public static Func<ItemInfo, string> <>9__86_2;

			public static Func<string, ItemInfo> <>9__87_0;

			public static Func<ItemInfo, bool> <>9__87_1;

			public static Func<ItemInfo, string> <>9__87_2;

			public static Func<string, int> <>9__88_0;

			public static Func<string, int> <>9__88_1;

			public static Func<string, int> <>9__88_2;

			public static Func<string, string> <>9__88_3;

			public static Func<Row, bool> <>9__120_0;

			public static Func<Row, int> <>9__120_1;

			public static Func<Row, int> <>9__120_2;

			public static Func<Row, int> <>9__120_3;

			public static Func<Row, string> <>9__120_4;

			public static Func<Cell, bool> <>9__122_0;

			public static Func<Cell, bool> <>9__122_1;

			public static Func<string, bool> <>9__129_0;

			public static Func<string, int> <>9__129_1;

			public static Func<string, string> <>9__129_2;

			public static Comparison<ItemInfo> <>9__175_0;

			public static Func<RuleSet, bool> <>9__178_0;

			public static Func<RuleSet, string> <>9__178_1;

			public static Func<Row, bool> <>9__241_0;

			public static Func<Row, int> <>9__241_1;

			public static Func<Row, int> <>9__241_2;

			public static Func<Row, int> <>9__241_3;

			public static Func<Row, string> <>9__241_4;

			public static Func<RuleRowUi, bool> <>9__243_0;

			internal int <Index>b__75_0(ItemInfo a, ItemInfo b)
			{
				return string.Compare(a.Label, b.Label, StringComparison.CurrentCultureIgnoreCase);
			}

			internal void <Build>b__80_0()
			{
				SetReference(on: false);
			}

			internal void <Build>b__80_1()
			{
				SetReference(on: true);
			}

			internal void <Build>b__80_2(string _)
			{
				RefreshSearch();
			}

			internal void <Build>b__80_3(string text)
			{
				if (!string.IsNullOrEmpty(text.Trim()))
				{
					RefreshSearch();
				}
			}

			internal void <Build>b__80_4()
			{
				AddChest(ungroupedOnly: false);
			}

			internal void <Build>b__80_5()
			{
				AddChest(ungroupedOnly: true);
			}

			internal ItemInfo <GroupSeed>b__86_0(string sc)
			{
				if (!known.TryGetValue(sc, out var value))
				{
					return null;
				}
				return value;
			}

			internal bool <GroupSeed>b__86_1(ItemInfo info)
			{
				return info != null;
			}

			internal string <GroupSeed>b__86_2(ItemInfo info)
			{
				return info.Label;
			}

			internal ItemInfo <ChestItems>b__87_0(string sc)
			{
				if (!known.TryGetValue(sc, out var value))
				{
					return null;
				}
				return value;
			}

			internal bool <ChestItems>b__87_1(ItemInfo info)
			{
				return info != null;
			}

			internal string <ChestItems>b__87_2(ItemInfo info)
			{
				return info.Label;
			}

			internal int <RebuildRows>b__88_0(string key)
			{
				return (!(key == fresh)) ? 1 : 0;
			}

			internal int <RebuildRows>b__88_1(string key)
			{
				return (!HitsChest(key)) ? 1 : 0;
			}

			internal int <RebuildRows>b__88_2(string key)
			{
				return Mod.isSystemGroup(key) ? 1 : 0;
			}

			internal string <RebuildRows>b__88_3(string key)
			{
				return key;
			}

			internal bool <OrderRows>b__120_0(Row row)
			{
				if (Object.op_Implicit((Object)(object)row.Background))
				{
					return groups.ContainsKey(row.Id);
				}
				return false;
			}

			internal int <OrderRows>b__120_1(Row row)
			{
				return (!(row.Id == fresh)) ? 1 : 0;
			}

			internal int <OrderRows>b__120_2(Row row)
			{
				return (!HitsChest(row.Id)) ? 1 : 0;
			}

			internal int <OrderRows>b__120_3(Row row)
			{
				return Mod.isSystemGroup(row.Id) ? 1 : 0;
			}

			internal string <OrderRows>b__120_4(Row row)
			{
				return row.Id;
			}

			internal bool <ApplyVisibility>b__122_0(Cell cell)
			{
				if (selected != null)
				{
					if (!groups[selected].Contains(cell.Info.ScName))
					{
						return pulled.Contains(cell.Info.ScName);
					}
					return true;
				}
				return false;
			}

			internal bool <ApplyVisibility>b__122_1(Cell _)
			{
				return true;
			}

			internal bool <RefreshChestLegend>b__129_0(string id)
			{
				if (HitsChest(id))
				{
					return !legendSlot.ContainsKey(id);
				}
				return false;
			}

			internal int <RefreshChestLegend>b__129_1(string key)
			{
				return (!Mod.isSystemGroup(key)) ? 1 : 0;
			}

			internal string <RefreshChestLegend>b__129_2(string key)
			{
				return key;
			}

			internal int <IndexRules>b__175_0(ItemInfo a, ItemInfo b)
			{
				return string.Compare(a.Label, b.Label, StringComparison.CurrentCultureIgnoreCase);
			}

			internal bool <BuildRuleRows>b__178_0(RuleSet set)
			{
				return set.Kind == RuleKind.Fuzzy;
			}

			internal string <BuildRuleRows>b__178_1(RuleSet set)
			{
				return set.Label;
			}

			internal bool <GroupList>b__241_0(Row row)
			{
				if (Object.op_Implicit((Object)(object)row.Background))
				{
					return groups.ContainsKey(row.Id);
				}
				return false;
			}

			internal int <GroupList>b__241_1(Row row)
			{
				return (!(row.Id == fresh)) ? 1 : 0;
			}

			internal int <GroupList>b__241_2(Row row)
			{
				return (!HitsChest(row.Id)) ? 1 : 0;
			}

			internal int <GroupList>b__241_3(Row row)
			{
				return Mod.isSystemGroup(row.Id) ? 1 : 0;
			}

			internal string <GroupList>b__241_4(Row row)
			{
				return row.Id;
			}

			internal bool <RuleList>b__243_0(RuleRowUi row)
			{
				if (Object.op_Implicit((Object)(object)row.Background))
				{
					return Object.op_Implicit((Object)(object)row.Label);
				}
				return false;
			}
		}

		private const float Width = 960f;

		private const float Height = 630f;

		private const int Columns = 10;

		private const float GridWidth = 664f;

		private const float CellGap = 4f;

		private const int CellPad = 4;

		private static readonly Color Idle = new Color(0.12f, 0.09f, 0.06f, 0.95f);

		private static readonly Color OneGroup = new Color(0.24f, 0.18f, 0.12f, 1f);

		private static readonly Color ManyGroups = new Color(0.34f, 0.16f, 0.12f, 1f);

		private static readonly Color Error = new Color(1f, 0.45f, 0.35f, 1f);

		private static readonly Color Added = new Color(0.32f, 0.68f, 0.36f, 1f);

		private static readonly Color Pulled = new Color(0.28f, 0.3f, 0.32f, 0.45f);

		private static readonly Color PulledHover = new Color(0.42f, 0.44f, 0.46f, 0.72f);

		private static readonly Color[] GroupDots = (Color[])(object)new Color[5]
		{
			new Color(0.95f, 0.76f, 0.22f, 1f),
			new Color(0.3f, 0.72f, 0.95f, 1f),
			new Color(0.92f, 0.4f, 0.58f, 1f),
			new Color(0.62f, 0.45f, 0.95f, 1f),
			new Color(0.95f, 0.5f, 0.22f, 1f)
		};

		private static readonly Color RowChest = new Color(0.28f, 0.48f, 0.3f, 1f);

		private static readonly Color ChestText = new Color(0.65f, 0.9f, 0.55f, 1f);

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

		private static readonly HashSet<string> pulled = new HashSet<string>();

		private static string pendingDelete;

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

		private static readonly List<ItemInfo> catalog = new List<ItemInfo>();

		private static readonly List<Cell> groupCells = new List<Cell>();

		private static readonly List<Cell> chestCells = new List<Cell>();

		private static readonly List<Row> rows = new List<Row>();

		private static readonly List<GameObject> searchRows = new List<GameObject>();

		private static readonly List<Cell> searchCells = new List<Cell>();

		private static readonly HashSet<string> chestNames = new HashSet<string>();

		private static readonly List<string> legendOrder = new List<string>();

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

		private static GameObject canvas;

		private static Container chest;

		private static string selected;

		private static string fresh;

		private static Cell hovered;

		private static Row hotRow;

		private static TMP_InputField nameInput;

		private static TMP_InputField searchInput;

		private static TMP_Text info;

		private static TMP_Text status;

		private static TMP_Text chestTitle;

		private static Button newButton;

		private static Button addAllButton;

		private static Button addLooseButton;

		private static Button groupsTab;

		private static Button patternsTab;

		private static ScrollRect itemScroll;

		private static ScrollRect chestScroll;

		private static RectTransform chestLegend;

		private static ScrollRect listScroll;

		private static RectTransform groupContent;

		private static bool rulesMode;

		private static GameObject searchPopup;

		private static RectTransform searchContent;

		private static ScrollRect searchScroll;

		private static GameObject tooltipPrefab;

		private static int blockFrame = -10;

		private static bool polling;

		private static readonly Color CellFrameColor = new Color(0.82f, 0.74f, 0.52f, 0.55f);

		private static Sprite dotSprite;

		private static Sprite cornerSprite;

		private static readonly List<RuleSet> ruleSets = new List<RuleSet>();

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

		private static readonly List<RuleRowUi> ruleRows = new List<RuleRowUi>();

		private static readonly List<Cell> ruleCells = new List<Cell>();

		private static readonly List<string> postfixScratch = new List<string>();

		private static TMP_InputField composer;

		private static bool addingPrefix;

		private static bool addingPostfix;

		private static bool composerCommit;

		private static bool composerKeep;

		private static bool composerCancel;

		private static int composerCancelFrame = -1;

		private static bool editing;

		private static RuleKind editKind;

		private static string editKindId;

		private static readonly List<string> editPrefixes = new List<string>();

		private static readonly List<string> editPostfixes = new List<string>();

		private static RuleSet renaming;

		private static RectTransform ruleContent;

		private static RuleSet shownRule;

		private static string pendingToken;

		private static readonly Color FrameColor = new Color(1f, 0.86f, 0.2f, 1f);

		private static int groupArea;

		private static int groupFocus;

		private static int ruleArea;

		private static int ruleFocus;

		private static bool padLive;

		private static RectTransform areaFrame;

		private static Cell padTip;

		private static GameObject padTipRoot;

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

		private static float CellEdge => 62f;

		private static IDictionary<string, ISet<string>> groups => ItemGroups.Groups;

		internal static bool IsOpen => Object.op_Implicit((Object)(object)canvas);

		internal static bool BlockKeys
		{
			get
			{
				if (polling)
				{
					return false;
				}
				if (IsOpen)
				{
					blockFrame = Time.frameCount;
					return true;
				}
				return Time.frameCount <= blockFrame + 1;
			}
		}

		private static int AreaCount
		{
			get
			{
				if (!rulesMode)
				{
					return 3;
				}
				return 2;
			}
		}

		private static int Area
		{
			get
			{
				if (!rulesMode)
				{
					return groupArea;
				}
				return ruleArea;
			}
			set
			{
				if (rulesMode)
				{
					ruleArea = value;
				}
				else
				{
					groupArea = value;
				}
			}
		}

		private static int Focus
		{
			get
			{
				if (!rulesMode)
				{
					return groupFocus;
				}
				return ruleFocus;
			}
			set
			{
				if (rulesMode)
				{
					ruleFocus = value;
				}
				else
				{
					groupFocus = value;
				}
			}
		}

		internal static void Tick()
		{
			if (composerCancel && Time.frameCount > composerCancelFrame)
			{
				composerCancel = false;
				if (editing)
				{
					EndEdit(rebuild: true);
				}
			}
			if (!IsOpen)
			{
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if (!Mod.modEnabled.Value || !Mod.groupingEnabled.Value || !Object.op_Implicit((Object)(object)instance) || !instance.IsContainerOpen() || (Object)(object)instance.m_currentContainer != (Object)(object)chest || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead())
			{
				Close();
				return;
			}
			if (Object.op_Implicit((Object)(object)searchPopup) && searchPopup.activeSelf && ZInput.GetKeyDown((KeyCode)323, false) && !PointerOverSearch())
			{
				CloseSearch();
			}
			PadTick();
			if (BackPressed())
			{
				if (pendingDelete != null || pendingToken != null)
				{
					pendingDelete = null;
					pendingToken = null;
					SetStatus("", error: false);
				}
				else
				{
					Close();
				}
			}
		}

		public static void Open(Inventory inventory, Container container)
		{
			if (!IsOpen && inventory != null && Object.op_Implicit((Object)(object)container))
			{
				InventoryGui instance = InventoryGui.instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					GroupUi.Capture(instance);
					CaptureTooltip(instance);
					chest = container;
					selected = null;
					fresh = null;
					hovered = null;
					ResetFocus();
					UITooltip.HideTooltip();
					NoteOpened();
					Index(inventory);
					Build(instance);
					Select(BestGroup(), resetItems: true);
				}
			}
		}

		public static void Close()
		{
			UITooltip.HideTooltip();
			if (Object.op_Implicit((Object)(object)canvas))
			{
				Object.Destroy((Object)(object)canvas);
				blockFrame = Time.frameCount;
			}
			canvas = null;
			chest = null;
			hovered = null;
			ResetFocus();
			selected = null;
			fresh = null;
			pendingDelete = null;
			pendingToken = null;
			opened.Clear();
			pulled.Clear();
			known.Clear();
			catalog.Clear();
			groupCells.Clear();
			chestCells.Clear();
			rows.Clear();
			searchRows.Clear();
			searchCells.Clear();
			chestNames.Clear();
			legendOrder.Clear();
			legendSlot.Clear();
			if (editing)
			{
				ItemGroups.SetPrefixes(editPrefixes);
				ItemGroups.SetPostfixes(editPostfixes);
			}
			ruleSets.Clear();
			ruleByKey.Clear();
			ruleRows.Clear();
			ruleCells.Clear();
			rulesMode = false;
			shownRule = null;
			groupContent = null;
			ruleContent = null;
			composer = null;
			addingPrefix = false;
			addingPostfix = false;
			composerCommit = false;
			composerKeep = false;
			composerCancel = false;
			editing = false;
			renaming = null;
		}

		private static bool BackPressed()
		{
			polling = true;
			try
			{
				return ZInput.GetKeyDown((KeyCode)27, false) || ZInput.GetButtonDown("JoyButtonB");
			}
			finally
			{
				polling = false;
			}
		}

		private static bool PadDown(string key)
		{
			polling = true;
			try
			{
				return ZInput.GetButtonDown(key);
			}
			finally
			{
				polling = false;
			}
		}

		private static void NoteOpened()
		{
			opened.Clear();
			foreach (KeyValuePair<string, ISet<string>> group in groups)
			{
				opened[group.Key] = new HashSet<string>(group.Value);
			}
		}

		private static void Index(Inventory inventory)
		{
			//IL_018e: 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)
			known.Clear();
			catalog.Clear();
			chestNames.Clear();
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance != (Object)null && instance.m_items != null)
			{
				foreach (GameObject item in instance.m_items)
				{
					if (!Object.op_Implicit((Object)(object)item))
					{
						continue;
					}
					ItemDrop component = item.GetComponent<ItemDrop>();
					SharedData val = (((Object)(object)component != (Object)null && component.m_itemData != null) ? component.m_itemData.m_shared : null);
					if (val != null && StorableName(val.m_name))
					{
						bool num = !known.ContainsKey(val.m_name.SCName());
						ItemInfo itemInfo = Remember(val.m_name, val.m_description, val.m_icons, val.m_itemType);
						if (num && itemInfo != null && !val.m_questItem)
						{
							catalog.Add(itemInfo);
						}
					}
				}
			}
			foreach (ItemData item2 in inventory.m_inventory)
			{
				if (item2?.m_shared != null && StorableName(item2.m_shared.m_name))
				{
					chestNames.Add(item2.m_shared.m_name.SCName());
					Remember(item2.m_shared.m_name, item2.m_shared.m_description, item2.m_shared.m_icons, item2.m_shared.m_itemType);
				}
			}
			foreach (ISet<string> value in groups.Values)
			{
				foreach (string item3 in value)
				{
					if (!known.ContainsKey(item3))
					{
						known[item3] = new ItemInfo
						{
							ScName = item3,
							Label = item3,
							Topic = item3
						};
					}
				}
			}
			catalog.Sort((ItemInfo a, ItemInfo b) => string.Compare(a.Label, b.Label, StringComparison.CurrentCultureIgnoreCase));
			IndexRules();
		}

		private static bool StorableName(string raw)
		{
			if (!string.IsNullOrEmpty(raw))
			{
				if (!raw.StartsWith("$item_"))
				{
					return raw.StartsWith("$mod_");
				}
				return true;
			}
			return false;
		}

		private static ItemInfo Remember(string raw, string description, Sprite[] icons, ItemType itemType)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!StorableName(raw))
			{
				return null;
			}
			string text = raw.SCName();
			if (known.TryGetValue(text, out var value))
			{
				return value;
			}
			Sprite icon = null;
			if (icons != null && icons.Length != 0)
			{
				icon = icons[0];
			}
			string label = ((Localization.instance != null) ? Localization.instance.Localize(raw) : raw);
			ItemInfo itemInfo = new ItemInfo
			{
				ScName = text,
				Label = label,
				Topic = raw,
				Description = (description ?? ""),
				Icon = icon,
				ItemType = itemType,
				HasType = true
			};
			known[text] = itemInfo;
			return itemInfo;
		}

		private static void CaptureTooltip(InventoryGui gui)
		{
			tooltipPrefab = null;
			InventoryGrid playerGrid = gui.m_playerGrid;
			InventoryElement val = ((Object.op_Implicit((Object)(object)playerGrid) && Object.op_Implicit((Object)(object)playerGrid.m_elementPrefab)) ? playerGrid.m_elementPrefab.GetComponent<InventoryElement>() : null);
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_tooltip))
			{
				tooltipPrefab = val.m_tooltip.m_tooltipPrefab;
			}
		}

		private static string BestGroup()
		{
			string result = null;
			int num = 0;
			foreach (KeyValuePair<string, ISet<string>> group in groups)
			{
				int num2 = 0;
				foreach (string chestName in chestNames)
				{
					if (group.Value.Contains(chestName))
					{
						num2++;
					}
				}
				if (num2 > num)
				{
					num = num2;
					result = group.Key;
				}
			}
			return result;
		}

		private static void Build(InventoryGui gui)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_0134: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0197: Expected O, but got Unknown
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Expected O, but got Unknown
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Expected O, but got Unknown
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Expected O, but got Unknown
			//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Expected O, but got Unknown
			//IL_063d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0642: Unknown result type (might be due to invalid IL or missing references)
			//IL_0648: Expected O, but got Unknown
			//IL_071b: Unknown result type (might be due to invalid IL or missing references)
			//IL_076c: Unknown result type (might be due to invalid IL or missing references)
			//IL_07aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_07af: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b5: Expected O, but got Unknown
			//IL_07e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f0: Expected O, but got Unknown
			//IL_0869: Unknown result type (might be due to invalid IL or missing references)
			//IL_086e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0874: Expected O, but got Unknown
			canvas = new GameObject("SmartContainersGroups", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			Canvas component = canvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			Canvas componentInParent = ((Component)gui).GetComponentInParent<Canvas>();
			component.sortingOrder = (Object.op_Implicit((Object)(object)componentInParent) ? (componentInParent.sortingOrder + 120) : 1020);
			CanvasScaler component2 = canvas.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.matchWidthOrHeight = 0.5f;
			GroupUi.Stretch(((Graphic)GroupUi.AddImage("Backdrop", canvas.transform, new Color(0f, 0f, 0f, 0.65f))).rectTransform);
			RectTransform rectTransform = ((Graphic)GroupUi.Panel(canvas.transform)).rectTransform;
			rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
			rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			rectTransform.anchoredPosition = Vector2.zero;
			rectTransform.sizeDelta = new Vector2(960f, 630f);
			object obj = <>c.<>9__80_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
					SetReference(on: false);
				};
				<>c.<>9__80_0 = val;
				obj = (object)val;
			}
			groupsTab = GroupUi.Button((Transform)(object)rectTransform, "Groups", 20f, 14f, 118f, 30f, (UnityAction)obj);
			object obj2 = <>c.<>9__80_1;
			if (obj2 == null)
			{
				UnityAction val2 = delegate
				{
					SetReference(on: true);
				};
				<>c.<>9__80_1 = val2;
				obj2 = (object)val2;
			}
			patternsTab = GroupUi.Button((Transform)(object)rectTransform, "Patterns", 144f, 14f, 118f, 30f, (UnityAction)obj2);
			BindTabGlyph(groupsTab);
			PaintTabs();
			nameInput = GroupUi.Input((Transform)(object)rectTransform, "New group name", 20f, 50f, 168f, 32f, 48);
			object obj3 = <>O.<0>__CreateGroup;
			if (obj3 == null)
			{
				UnityAction val3 = CreateGroup;
				<>O.<0>__CreateGroup = val3;
				obj3 = (object)val3;
			}
			newButton = GroupUi.Button((Transform)(object)rectTransform, "New", 196f, 50f, 64f, 32f, (UnityAction)obj3);
			BindPadHint(newButton, "JoyMap");
			searchInput = GroupUi.Input((Transform)(object)rectTransform, "Find an item to add", 276f, 50f, 664f, 32f, 40);
			((UnityEvent<string>)(object)searchInput.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				RefreshSearch();
			});
			((UnityEvent<string>)(object)searchInput.onSelect).AddListener((UnityAction<string>)delegate(string text)
			{
				if (!string.IsNullOrEmpty(text.Trim()))
				{
					RefreshSearch();
				}
			});
			listScroll = Scroll((Transform)(object)rectTransform, "Groups", 20f, 94f, 240f, 468f, out groupContent);
			listScroll.scrollSensitivity = 500f;
			VerticalLayoutGroup obj4 = ((Component)groupContent).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj4).spacing = 4f;
			((LayoutGroup)obj4).padding = new RectOffset(4, 4, 4, 4);
			((HorizontalOrVerticalLayoutGroup)obj4).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = false;
			((Component)groupContent).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			RebuildRows(groupContent);
			ruleContent = GroupUi.Rect("Rules", ((Component)listScroll).transform, 0f, 0f, 0f, 0f);
			ruleContent.anchorMin = new Vector2(0f, 1f);
			ruleContent.anchorMax = new Vector2(1f, 1f);
			ruleContent.pivot = new Vector2(0.5f, 1f);
			ruleContent.anchoredPosition = Vector2.zero;
			ruleContent.sizeDelta = Vector2.zero;
			VerticalLayoutGroup obj5 = ((Component)ruleContent).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj5).spacing = 4f;
			((LayoutGroup)obj5).padding = new RectOffset(4, 4, 4, 4);
			((HorizontalOrVerticalLayoutGroup)obj5).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj5).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj5).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj5).childForceExpandHeight = false;
			((Component)ruleContent).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			BuildRuleRows();
			((Component)ruleContent).gameObject.SetActive(false);
			info = (TMP_Text)(object)GroupUi.Text((Transform)(object)rectTransform, "", 276f, 88f, 664f, 22f, 16f);
			((Graphic)info).color = Color.white;
			info.richText = true;
			info.overflowMode = (TextOverflowModes)0;
			itemScroll = Scroll((Transform)(object)rectTransform, "Items", 276f, 110f, 664f, 208f, out var content);
			SetupGrid(content);
			foreach (ItemInfo item in GroupSeed())
			{
				groupCells.Add(MakeCell(content, item, CellRole.Group));
			}
			chestTitle = (TMP_Text)(object)GroupUi.Text((Transform)(object)rectTransform, "This chest", 276f, 342f, 90f, 20f, 15f);
			chestLegend = GroupUi.Rect("ChestLegend", (Transform)(object)rectTransform, 370f, 342f, 566f, 20f);
			HorizontalLayoutGroup obj6 = ((Component)chestLegend).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj6).spacing = 10f;
			((LayoutGroup)obj6).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)obj6).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj6).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj6).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj6).childForceExpandHeight = false;
			object obj7 = <>c.<>9__80_4;
			if (obj7 == null)
			{
				UnityAction val4 = delegate
				{
					AddChest(ungroupedOnly: false);
				};
				<>c.<>9__80_4 = val4;
				obj7 = (object)val4;
			}
			addAllButton = GroupUi.Button((Transform)(object)rectTransform, "Add all", 276f, 370f, 128f, 28f, (UnityAction)obj7);
			object obj8 = <>c.<>9__80_5;
			if (obj8 == null)
			{
				UnityAction val5 = delegate
				{
					AddChest(ungroupedOnly: true);
				};
				<>c.<>9__80_5 = val5;
				obj8 = (object)val5;
			}
			addLooseButton = GroupUi.Button((Transform)(object)rectTransform, "Add ungrouped", 412f, 370f, 168f, 28f, (UnityAction)obj8);
			BindPadHint(addAllButton, "JoyLStick");
			BindPadHint(addLooseButton, "JoyRStick");
			chestScroll = Scroll((Transform)(object)rectTransform, "Chest", 276f, 406f, 664f, 136f, out var content2);
			SetupGrid(content2);
			foreach (ItemInfo item2 in ChestItems())
			{
				chestCells.Add(MakeCell(content2, item2, CellRole.Chest));
			}
			RectTransform obj9 = GroupUi.Rect("SearchOverlay", (Transform)(object)rectTransform, 276f, 86f, 664f, 232f);
			((Graphic)((Component)obj9).gameObject.AddComponent<Image>()).color = new Color(0.12f, 0.08f, 0.05f, 0.98f);
			searchScroll = Scroll((Transform)(object)obj9, "SearchHits", 0f, 0f, 664f, 192f, out searchContent);
			((Graphic)((Component)searchScroll).GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0f);
			SetupGrid(searchContent);
			object obj10 = <>O.<1>__AddAllSearch;
			if (obj10 == null)
			{
				UnityAction val6 = AddAllSearch;
				<>O.<1>__AddAllSearch = val6;
				obj10 = (object)val6;
			}
			GroupUi.Button((Transform)(object)obj9, "ADD ALL", 8f, 196f, 150f, 32f, (UnityAction)obj10);
			object obj11 = <>O.<2>__CloseSearch;
			if (obj11 == null)
			{
				UnityAction val7 = CloseSearch;
				<>O.<2>__CloseSearch = val7;
				obj11 = (object)val7;
			}
			GroupUi.Button((Transform)(object)obj9, "CLOSE", 506f, 196f, 150f, 32f, (UnityAction)obj11);
			searchPopup = ((Component)obj9).gameObject;
			searchPopup.SetActive(false);
			status = (TMP_Text)(object)GroupUi.Text((Transform)(object)rectTransform, "", 276f, 542f, 530f, 40f, 17f);
			status.overflowMode = (TextOverflowModes)0;
			object obj12 = <>O.<3>__Close;
			if (obj12 == null)
			{
				UnityAction val8 = Close;
				<>O.<3>__Close = val8;
				obj12 = (object)val8;
			}
			GroupUi.Button((Transform)(object)rectTransform, "Close", 820f, 580f, 120f, 34f, (UnityAction)obj12);
		}

		private static void BindTabGlyph(Button button)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			BindPadHint(button, "JoyMenu");
			UIGamePad val = (Object.op_Implicit((Object)(object)button) ? ((Component)button).GetComponent<UIGamePad>() : null);
			GameObject val2 = (Object.op_Implicit((Object)(object)val) ? val.m_hint : null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				RectTransform component = val2.GetComponent<RectTransform>();
				component.anchorMin = new Vector2(1f, 0.5f);
				component.anchorMax = new Vector2(1f, 0.5f);
				component.pivot = new Vector2(1f, 0.5f);
				component.sizeDelta = new Vector2(26f, 26f);
				component.anchoredPosition = new Vector2(11f, 0f);
				TextMeshProUGUI component2 = val2.GetComponent<TextMeshProUGUI>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					((TMP_Text)component2).alignment = (TextAlignmentOptions)4100;
					((TMP_Text)component2).enableAutoSizing = false;
					((TMP_Text)component2).fontSize = 15f;
					((TMP_Text)component2).overflowMode = (TextOverflowModes)0;
					((Graphic)component2).raycastTarget = false;
				}
			}
		}

		private static void BindPadHint(Button button, string key)
		{
			if (Object.op_Implicit((Object)(object)button) && ZInput.instance != null)
			{
				((Component)button).gameObject.AddComponent<UIGamePad>();
				GuiFactory.InitJoyKey(((Component)button).transform, key, ZInput.instance.GetBoundKeyString(key, false));
				((Component)button).GetComponent<UIGamePad>().m_zinputKey = null;
			}
		}

		private static void BindDeleteHint(Button button)
		{
			BindPadHint(button, "JoyButtonX");
			UIGamePad component = ((Component)button).GetComponent<UIGamePad>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			((Behaviour)component).enabled = false;
			GameObject hint = component.m_hint;
			if (Object.op_Implicit((Object)(object)hint))
			{
				TextMeshProUGUI component2 = hint.GetComponent<TextMeshProUGUI>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					((TMP_Text)component2).enableAutoSizing = false;
					((TMP_Text)component2).fontSize = 13f;
					((TMP_Text)component2).overflowMode = (TextOverflowModes)0;
					((TMP_Text)component2).alignment = (TextAlignmentOptions)514;
				}
			}
		}

		private static ScrollRect Scroll(Transform parent, string name, float x, float y, float width, float height, out RectTransform content)
		{
			//IL_002d: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = GroupUi.Rect(name, parent, x, y, width, height);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.35f);
			((Component)val).gameObject.AddComponent<RectMask2D>();
			content = GroupUi.Rect("Content", (Transform)(object)val, 0f, 0f, 0f, 0f);
			content.anchorMin = new Vector2(0f, 1f);
			content.anchorMax = new Vector2(1f, 1f);
			content.pivot = new Vector2(0.5f, 1f);
			content.anchoredPosition = Vector2.zero;
			content.sizeDelta = Vector2.zero;
			ScrollRect obj = ((Component)val).gameObject.AddComponent<ScrollRect>();
			obj.horizontal = false;
			obj.vertical = true;
			obj.movementType = (MovementType)2;
			obj.inertia = false;
			obj.scrollSensitivity = 500f;
			obj.viewport = val;
			obj.content = content;
			return obj;
		}

		private static void SetupGrid(RectTransform content)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0044: Expected O, but got Unknown
			GridLayoutGroup obj = ((Component)content).gameObject.AddComponent<GridLayoutGroup>();
			obj.cellSize = new Vector2(CellEdge, CellEdge);
			obj.spacing = new Vector2(4f, 4f);
			((LayoutGroup)obj).padding = new RectOffset(4, 4, 4, 4);
			obj.constraint = (Constraint)1;
			obj.constraintCount = 10;
			((LayoutGroup)obj).childAlignment = (TextAnchor)0;
			((Component)content).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
		}

		private static IEnumerable<ItemInfo> GroupSeed()
		{
			HashSet<string> hashSet = new HashSet<string>(chestNames);
			foreach (ISet<string> value2 in groups.Values)
			{
				hashSet.UnionWith(value2);
			}
			ItemInfo value;
			return (from sc in hashSet
				select (!known.TryGetValue(sc, out value)) ? null : value into info
				where info != null
				select info).OrderBy<ItemInfo, string>((ItemInfo info) => info.Label, StringComparer.CurrentCultureIgnoreCase);
		}

		private static IEnumerable<ItemInfo> ChestItems()
		{
			ItemInfo value;
			return (from sc in chestNames
				select (!known.TryGetValue(sc, out value)) ? null : value into info
				where info != null
				select info).OrderBy<ItemInfo, string>((ItemInfo info) => info.Label, StringComparer.CurrentCultureIgnoreCase);
		}

		private static void RebuildRows(RectTransform content)
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Expected O, but got Unknown
			hotRow = null;
			foreach (Row row2 in rows)
			{
				if (Object.op_Implicit((Object)(object)row2.Background))
				{
					Object.Destroy((Object)(object)((Component)row2.Background).gameObject);
				}
			}
			rows.Clear();
			foreach (string item in (from key in groups.Keys
				orderby (!(key == fresh)) ? 1 : 0, (!HitsChest(key)) ? 1 : 0, Mod.isSystemGroup(key) ? 1 : 0
				select key).ThenBy<string, string>((string key) => key, StringComparer.OrdinalIgnoreCase))
			{
				string groupId = item;
				Button val = GroupUi.Button((Transform)(object)content, groupId, 0f, 0f, 220f, 28f, (UnityAction)delegate
				{
					Select(groupId, resetItems: true);
				});
				LayoutElement obj = ((Component)val).gameObject.AddComponent<LayoutElement>();
				obj.preferredHeight = 28f;
				obj.minHeight = 28f;
				bool flag = !Mod.isSystemGroup(groupId);
				TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>();
				((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)4097;
				((TMP_Text)componentInChildren).rectTransform.anchoredPosition = new Vector2(16f, 0f);
				((TMP_Text)componentInChildren).rectTransform.sizeDelta = new Vector2(flag ? 160f : 196f, 28f);
				Image val2 = GroupUi.AddImage("Mark", ((Component)val).tr