Decompiled source of ValheimAutoSort v2.4.0

ValheimAutoSort.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using System.Threading;
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: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("ValheimAutoSort")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("ValheimAutoSort")]
[assembly: AssemblyTitle("ValheimAutoSort")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace ValheimAutoSort
{
	[BepInPlugin("com.yourname.valheim.autosort", "AutoSort", "2.1.0")]
	[BepInProcess("valheim.exe")]
	public class AutoSortPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.yourname.valheim.autosort";

		public const string PluginName = "AutoSort";

		public const string PluginVersion = "2.1.0";

		internal static ManualLogSource Log;

		public static ConfigEntry<bool> ModEnabled;

		public static ConfigEntry<bool> LogDebug;

		public static ConfigEntry<bool> EnableTagOverride;

		public static ConfigEntry<KeyboardShortcut> SortKeybind;

		public static ConfigEntry<float> ScanRadius;

		public static ConfigEntry<bool> EnableGroundSuck;

		public static ConfigEntry<float> GroundSuckRadius;

		public static ConfigEntry<float> GroundSuckInterval;

		public static ConfigEntry<bool> HighlightContainers;

		public static ConfigEntry<bool> PingContainers;

		public static ConfigEntry<string> PingVFX;

		public static ConfigEntry<string> Cat_Stone;

		public static ConfigEntry<string> Cat_Wood;

		public static ConfigEntry<string> Cat_Ore;

		public static ConfigEntry<string> Cat_Metal;

		public static ConfigEntry<string> Cat_Gem;

		public static ConfigEntry<string> Cat_Leather;

		public static ConfigEntry<string> Cat_Bone;

		public static ConfigEntry<string> Cat_Fiber;

		public static ConfigEntry<string> Cat_Seed;

		public static ConfigEntry<string> Cat_Food;

		public static ConfigEntry<string> Cat_Potion;

		public static ConfigEntry<string> Cat_Fish;

		public static ConfigEntry<string> Cat_Arrow;

		public static ConfigEntry<string> Cat_Weapon;

		public static ConfigEntry<string> Cat_Shield;

		public static ConfigEntry<string> Cat_Armor;

		public static ConfigEntry<string> Cat_Tool;

		public static ConfigEntry<string> Cat_Magic;

		public static ConfigEntry<string> Cat_Trophy;

		public static ConfigEntry<string> Cat_Furniture;

		public static ConfigEntry<string> Cat_Misc;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			//IL_051e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0528: Expected O, but got Unknown
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ModEnabled", true, "Master switch. Set to false to disable all AutoSort behaviour without uninstalling.");
			LogDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "LogDebug", false, "Print verbose debug messages to the BepInEx console. Turn on when troubleshooting. Also prints the prefab name of any item sorted — useful for adding custom items to a category.");
			EnableTagOverride = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Chest Tagging", "EnableTagOverride", true, new ConfigDescription("Allow chest categories to be set via the in-chest GUI button or the 'autosort_tag <Category>' console command. Tagged chests always override inferred categories and are never repurposed by the sort pass.", (AcceptableValueBase)null, Array.Empty<object>()));
			SortKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Sort Pass", "SortKeybind", new KeyboardShortcut((KeyCode)114, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), new ConfigDescription("Keyboard shortcut that triggers a full sort of all chests within ScanRadius of the player. Default: Alt+R. Only fires when no GUI/inventory is open.", (AcceptableValueBase)null, Array.Empty<object>()));
			ScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Sort Pass", "ScanRadius", 30f, new ConfigDescription("Radius in metres around the player within which chests are included in a sort pass. Larger values cover more chests but scan more objects each press. Default 30 covers a typical house interior from end to end.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 128f), Array.Empty<object>()));
			EnableGroundSuck = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Ground Items", "EnableGroundSuck", true, "When enabled, items lying on the ground within GroundSuckRadius of the player are periodically pulled into nearby matching chests.");
			GroundSuckRadius = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Ground Items", "GroundSuckRadius", 8f, new ConfigDescription("How far from the player (metres) to look for ground items to suck up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 32f), Array.Empty<object>()));
			GroundSuckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Ground Items", "GroundSuckInterval", 5f, new ConfigDescription("Seconds between each ground-item scan.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			HighlightContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Effects", "HighlightContainers", true, "Briefly flash a chest with a blue emission glow when an item is sorted into it.");
			PingContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Effects", "PingContainers", true, "Spawn a particle VFX at a chest when an item is sorted into it.");
			PingVFX = ((BaseUnityPlugin)this).Config.Bind<string>("5 - Effects", "PingVFX", "vfx_Potion_health_medium", "VFX prefab name to spawn on sort. Leave blank to disable. Browse names at: https://valheim-modding.github.io/Jotunn/data/prefabs/prefab-list.html");
			Cat_Stone = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Stone", "Stone, Flint, Obsidian, Coal, BlackMarble, Grausten", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Wood = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Wood", "Wood, FineWood, RoundLog, YggdrasilWood, AncientBark, ElderBark, AshWood, WoodBeam", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Ore = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Ore", "CopperOre, TinOre, IronScrap, SilverOre, BlackMetalScrap, FlametalOre, MucusOre, CopperScrap", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Metal = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Metal", "Bronze, Iron, Silver, BlackMetal, Copper, Tin, Flametal, DvergrMetal, BlackCore, MorgenCore, BronzeNails, IronNails", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Gem = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Gem", "Amber, AmberPearl, Ruby, SilverNecklace, BlackGem, Coins", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Leather = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Leather", "LeatherScraps, DeerHide, ScaleHide, WolfPelt, LoxPelt, TrollHide, AskHide", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Bone = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Bone", "BoneFragments, WitheredBone, Chitin, Carapace, HardAntler, DragonEgg", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Fiber = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Fiber", "Flax, FlaxThread, Barley, BarleyFlour, Thistle, Dandelion, Bloodbag, Guck, LinenThread, JuteRed, JuteBlue", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Seed = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Seed", "Acorn, AncientSeed, BeechSeeds, BirchSeeds, CarrotSeeds, TurnipSeeds, OnionSeeds, FlaxSeeds, BarleySeeds, JuteSeedRed, SeedCarrot, SeedTurnip, SeedOnion, SeedBarley, SeedFlax, PineCone, FirCone, Surtling_Immature", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Food = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Food", "Mushroom, MushroomBlue, MushroomYellow, Raspberry, Blueberries, Cloudberry, Carrot, Turnip, Onion, Honey, Egg, Entrails, NeckTail, DeerMeat, WolfMeat, LoxMeat, SerpentMeat, SerpentMeatCooked, ChickenMeat, ChickenEgg, VoltureMeat, AsksvinMeat, CharredMeat, CarrotSoup, TurnipStew, OnionSoup, QueensJam, Bread, FishWraps, MinceMeatSauce, Sausages, BlackSoup, WolfMeatSkewer, WolfJerky, LoxPie, LoxMeatPie, SerpentStew, BloodPudding, EyeScream, BugMeat, MisthareSupreme, HareMeat, YggdrasilPorridge, MarinatedGreens, ScalpSkewer, SeekerAspic, FishNBread, Salad, SpicedMeat, AshenMeat, CookedBugMeat, CookedChickenMeat, CookedDeerMeat, CookedWolfMeat, CookedLoxMeat, CookedHareMeat, CookedVoltureMeat, CookedAsksvinMeat, CookedCharredMeat, BarleyWine, CloudberryWine", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Potion = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Potion", "MeadBase, MeadBaseFrostResist, MeadBaseHealthMinor, MeadBaseHealthMedium, MeadBaseHealthMajor, MeadBaseStaminaMinor, MeadBaseStaminaMedium, MeadBaseStaminaLingering, MeadBasePoisonResist, MeadBaseTasty, MeadBaseEitrMinor, MeadBaseEitrMedium, MeadFrostResist, MeadHealthMinor, MeadHealthMedium, MeadHealthMajor, MeadStaminaMinor, MeadStaminaMedium, MeadStaminaLingering, MeadPoisonResist, MeadTasty, MeadEitrMinor, MeadEitrMedium", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Fish = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Fish", "Fish1, Fish2, Fish3, Fish4_cave, Fish5, Fish6, Fish7, Fish8, Fish9, Fish10, Fish11, Fish12, FishCooked, FishAndBread", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Arrow = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Arrow", "ArrowWood, ArrowFlint, ArrowBronze, ArrowIron, ArrowObsidian, ArrowSilver, ArrowNeedle, ArrowFire, ArrowPoison, ArrowFrost, ArrowCharred, ArrowCarapace, BoltBone, BoltIron, BoltBlackmetal, BoltCarapace, BoltCharred", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Weapon = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Weapon", "", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.\nLeave blank — weapons are detected automatically by item type.");
			Cat_Shield = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Shield", "", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.\nLeave blank — shields are detected automatically by item type.");
			Cat_Armor = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Armor", "", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.\nLeave blank — armor is detected automatically by item type.");
			Cat_Tool = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Tool", "", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.\nLeave blank — tools are detected automatically by item type.");
			Cat_Magic = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Magic", "Eitr, Sap, SoftTissue, Wisp, WispTorch, DvergrNeedle, Dundr, GemstoneGreen, GemstoneBlue, GemstoneRed, VolcanicRock, AshflameKindling, CharredRemains, Emberlite", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Trophy = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Trophy", "TrophyBoar, TrophyNeck, TrophyDeer, TrophyGreydwarf, TrophyGreydwarfBrute, TrophyGreydwarfShaman, TrophyForestTroll, TrophySkeletonPoison, TrophySkeleton, TrophyDraugr, TrophyDraugrElite, TrophyBlob, TrophyLeech, TrophyDraugrFem, TrophyWraith, TrophyAbomination, TrophyLox, TrophySGolem, TrophyWolf, TrophyHatchling, TrophyFenring, TrophySerpent, TrophyDeathsquito, TrophyGrowth, TrophySeeker, TrophySeekerBrute, TrophyTick, TrophyHare, TrophyGjall, TrophyCharredMelee, TrophyCharredArcher, TrophyCharredTwitcher, TrophyCharredWarlock, TrophyFader, TrophyEikthyr, TrophyElder, TrophyBonemass, TrophyDragonQueen, TrophyGoblinKing, TrophyQueenBee, TrophyVolture, TrophyAskvin", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.");
			Cat_Furniture = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Furniture", "", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.\nAdd furniture/building piece prefab names here if desired.");
			Cat_Misc = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Categories", "Misc", "", "\nComma-separated prefab names. Add modded items here. Enable LogDebug to print prefab names as items are sorted.\nAny prefab listed here is forced to Misc regardless of other rules.");
			ItemCategorizer.LoadFromConfig();
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				ItemCategorizer.LoadFromConfig();
			};
			ItemCategorizer.InitJsonWatcher();
			_harmony = new Harmony("com.yourname.valheim.autosort");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)("AutoSort 2.1.0 loaded. " + $"Sort keybind: {SortKeybind.Value}. Scan radius: {ScanRadius.Value} m."));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public static class ChestEffects
	{
		[CompilerGenerated]
		private sealed class <HighlightContainer>d__4 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Container container;

			private Renderer[] <renderers>5__2;

			private Color[] <originalColors>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <HighlightContainer>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<renderers>5__2 = null;
				<originalColors>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Expected O, but got Unknown
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0166: 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)
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					if ((Object)(object)container == (Object)null)
					{
						return false;
					}
					<renderers>5__2 = ((Component)container).GetComponentsInChildren<Renderer>();
					if (<renderers>5__2 == null || <renderers>5__2.Length == 0)
					{
						return false;
					}
					<originalColors>5__3 = (Color[])(object)new Color[<renderers>5__2.Length];
					for (int j = 0; j < <renderers>5__2.Length; j++)
					{
						Material material2 = <renderers>5__2[j].material;
						<originalColors>5__3[j] = (material2.HasProperty("_EmissionColor") ? material2.GetColor("_EmissionColor") : Color.black);
						if (material2.HasProperty("_EmissionColor"))
						{
							material2.EnableKeyword("_EMISSION");
							material2.SetColor("_EmissionColor", new Color(0.2f, 0.6f, 1f, 1f) * 1.5f);
						}
					}
					<>2__current = (object)new WaitForSeconds(0.6f);
					<>1__state = 1;
					return true;
				}
				case 1:
					<>1__state = -1;
					if ((Object)(object)container != (Object)null)
					{
						for (int i = 0; i < <renderers>5__2.Length; i++)
						{
							if (!((Object)(object)<renderers>5__2[i] == (Object)null))
							{
								Material material = <renderers>5__2[i].material;
								if (material.HasProperty("_EmissionColor"))
								{
									material.SetColor("_EmissionColor", <originalColors>5__3[i]);
								}
							}
						}
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static readonly Dictionary<Container, float> _cooldowns = new Dictionary<Container, float>();

		private const float CooldownSeconds = 2f;

		public static void PlayEffect(Container container)
		{
			if (!AutoSortPlugin.ModEnabled.Value || (Object)(object)container == (Object)null)
			{
				return;
			}
			float time = Time.time;
			if (!_cooldowns.TryGetValue(container, out var value) || !(time - value < 2f))
			{
				_cooldowns[container] = time;
				if (AutoSortPlugin.PingContainers.Value)
				{
					SpawnVFX(container);
				}
				if (AutoSortPlugin.HighlightContainers.Value)
				{
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(HighlightContainer(container));
				}
			}
		}

		private static void SpawnVFX(Container container)
		{
			//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_006c: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			string value = AutoSortPlugin.PingVFX.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab(value) : null);
			if ((Object)(object)val == (Object)null)
			{
				if (AutoSortPlugin.LogDebug.Value)
				{
					AutoSortPlugin.Log.LogDebug((object)("[AutoSort] VFX prefab '" + value + "' not found."));
				}
			}
			else
			{
				Vector3 val2 = ((Component)container).transform.position + Vector3.up * 1.2f;
				Object.Instantiate<GameObject>(val, val2, Quaternion.identity);
			}
		}

		[IteratorStateMachine(typeof(<HighlightContainer>d__4))]
		private static IEnumerator HighlightContainer(Container container)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <HighlightContainer>d__4(0)
			{
				container = container
			};
		}
	}
	public class ChestOwnership
	{
		public Container Container { get; }

		public SortCategory Category { get; set; }

		public bool IsTagged { get; }

		public int Count { get; }

		public bool IsFull
		{
			get
			{
				Inventory inventory = Container.GetInventory();
				if (inventory == null)
				{
					return false;
				}
				return inventory.GetEmptySlots() == 0;
			}
		}

		public int EmptySlots
		{
			get
			{
				Inventory inventory = Container.GetInventory();
				if (inventory == null)
				{
					return 0;
				}
				return inventory.GetEmptySlots();
			}
		}

		public int Capacity
		{
			get
			{
				Inventory inventory = Container.GetInventory();
				int? num = ((inventory != null) ? new int?(inventory.GetWidth()) : null);
				Inventory inventory2 = Container.GetInventory();
				return (num * ((inventory2 != null) ? new int?(inventory2.GetHeight()) : null)).GetValueOrDefault();
			}
		}

		public bool IsFreeChest { get; set; }

		public ChestOwnership(Container c, SortCategory cat, bool isTagged, int count)
		{
			Container = c;
			Category = cat;
			IsTagged = isTagged;
			Count = count;
		}
	}
	public static class ChestOwnershipResolver
	{
		private class VSlot
		{
			public string Name;

			public int Stack;

			public int MaxStack;

			public VSlot(string name, int stack, int maxStack)
			{
				Name = name;
				Stack = stack;
				MaxStack = maxStack;
			}
		}

		public static List<ChestOwnership> Resolve(Vector3 origin, float radius)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			List<ChestOwnership> list = new List<ChestOwnership>();
			foreach (Container item in ContainersTracker.GetNearby(origin, radius))
			{
				if (IsAccessible(item))
				{
					ChestOwnership chestOwnership = ResolveContainer(item);
					if (chestOwnership != null)
					{
						list.Add(chestOwnership);
					}
				}
			}
			list.Sort(delegate(ChestOwnership a, ChestOwnership b)
			{
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				if (a.IsTagged != b.IsTagged)
				{
					if (!a.IsTagged)
					{
						return 1;
					}
					return -1;
				}
				if (a.IsTagged && b.IsTagged)
				{
					int num = a.Category.CompareTo(b.Category);
					if (num != 0)
					{
						return num;
					}
					return ((Component)b.Container).transform.position.x.CompareTo(((Component)a.Container).transform.position.x);
				}
				return b.Count.CompareTo(a.Count);
			});
			if (AutoSortPlugin.LogDebug.Value)
			{
				AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] Resolved {list.Count} chest(s):");
				foreach (ChestOwnership item2 in list)
				{
					AutoSortPlugin.Log.LogDebug((object)($"  [{item2.Category}] tagged={item2.IsTagged} count={item2.Count} " + $"full={item2.IsFull} free={item2.IsFreeChest} slots={item2.EmptySlots}/{item2.Capacity}"));
				}
			}
			return list;
		}

		public static Dictionary<ItemData, Container> PlanSortFull(List<ChestOwnership> ownerships)
		{
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			List<ChestOwnership> ownerships2 = ownerships;
			Dictionary<Container, List<VSlot>> virtualSlots = new Dictionary<Container, List<VSlot>>();
			foreach (ChestOwnership item4 in ownerships2)
			{
				Inventory inventory = item4.Container.GetInventory();
				List<VSlot> list = new List<VSlot>();
				if (inventory != null)
				{
					foreach (ItemData allItem in inventory.GetAllItems())
					{
						list.Add(new VSlot(allItem.m_shared.m_name, allItem.m_stack, allItem.m_shared.m_maxStackSize));
					}
				}
				virtualSlots[item4.Container] = list;
			}
			List<ChestOwnership> first = ownerships2.Where((ChestOwnership o) => o.IsTagged).ToList();
			List<ChestOwnership> inferred = ownerships2.Where((ChestOwnership o) => !o.IsTagged).ToList();
			inferred = SortInferredByPosition(inferred);
			ownerships2 = first.Concat(inferred).ToList();
			if (AutoSortPlugin.LogDebug.Value)
			{
				AutoSortPlugin.Log.LogDebug((object)"[AutoSort] Inferred chest spatial planning order:");
				for (int i = 0; i < inferred.Count; i++)
				{
					Vector3 position = ((Component)inferred[i].Container).transform.position;
					AutoSortPlugin.Log.LogDebug((object)($"  [{i}] [{inferred[i].Category}] " + $"x={position.x:F1} z={position.z:F1} " + $"free={inferred[i].IsFreeChest} slots={inferred[i].EmptySlots}/{inferred[i].Capacity}"));
				}
			}
			Dictionary<Container, SortCategory> freeClaimed = new Dictionary<Container, SortCategory>();
			List<(ItemData, Container, ChestOwnership)> list2 = new List<(ItemData, Container, ChestOwnership)>();
			foreach (ChestOwnership item5 in ownerships2)
			{
				Inventory inventory2 = item5.Container.GetInventory();
				if (inventory2 == null)
				{
					continue;
				}
				foreach (ItemData allItem2 in inventory2.GetAllItems())
				{
					if (allItem2.m_stack > 0)
					{
						list2.Add((allItem2, item5.Container, item5));
					}
				}
			}
			list2 = (from x in list2
				orderby (x.owner.IsTagged && x.owner.Category == ItemCategorizer.GetCategory(x.item)) ? 1 : 0 descending, ItemCategorizer.GetCategory(x.item).ToString(), ItemCategorizer.GetItemKey(x.item)
				select x).ToList();
			Dictionary<ItemData, Container> dictionary = new Dictionary<ItemData, Container>(ReferenceEqualityComparer.Instance);
			foreach (var item6 in list2)
			{
				ItemData item2 = item6.Item1;
				Container item3 = item6.Item2;
				SortCategory category = ItemCategorizer.GetCategory(item2);
				string name = item2.m_shared.m_name;
				int maxStackSize = item2.m_shared.m_maxStackSize;
				Container c2 = (dictionary[item2] = FindDest(item2, category, item3) ?? item3);
				VirtualRemove(item3, name, item2.m_stack);
				VirtualAdd(c2, name, item2.m_stack, maxStackSize);
			}
			return dictionary;
			static int Capacity(Container c)
			{
				Inventory inventory3 = c.GetInventory();
				if (inventory3 == null)
				{
					return 0;
				}
				return inventory3.GetWidth() * inventory3.GetHeight();
			}
			Container? FindDest(ItemData item, SortCategory cat, Container home)
			{
				string sharedName4 = item.m_shared.m_name;
				int maxStack2 = item.m_shared.m_maxStackSize;
				ChestOwnership chestOwnership = ownerships2.FirstOrDefault((ChestOwnership o) => o.IsTagged && !o.IsFreeChest && o.Category == cat && VirtualRoom(o.Container, sharedName4, maxStack2) > 0);
				if (chestOwnership != null)
				{
					return chestOwnership.Container;
				}
				ChestOwnership chestOwnership2 = ownerships2.FirstOrDefault((ChestOwnership o) => !o.IsTagged && !o.IsFreeChest && o.Category == cat && VirtualRoom(o.Container, sharedName4, maxStack2) > 0 && virtualSlots[o.Container].Any((VSlot s) => s.Name == sharedName4));
				if (chestOwnership2 != null)
				{
					return chestOwnership2.Container;
				}
				ChestOwnership chestOwnership3 = ownerships2.FirstOrDefault((ChestOwnership o) => !o.IsTagged && !o.IsFreeChest && o.Category == cat && VirtualRoom(o.Container, sharedName4, maxStack2) > 0);
				if (chestOwnership3 != null)
				{
					return chestOwnership3.Container;
				}
				ChestOwnership chestOwnership4 = ownerships2.FirstOrDefault(delegate(ChestOwnership o)
				{
					if (freeClaimed.TryGetValue(o.Container, out var value))
					{
						if (value == cat)
						{
							return VirtualRoom(o.Container, sharedName4, maxStack2) > 0;
						}
						return false;
					}
					return (o.IsFreeChest || o.Category == SortCategory.Unknown) && VirtualRoom(o.Container, sharedName4, maxStack2) > 0;
				});
				if (chestOwnership4 != null)
				{
					freeClaimed[chestOwnership4.Container] = cat;
					chestOwnership4.IsFreeChest = false;
					chestOwnership4.Category = cat;
					return chestOwnership4.Container;
				}
				return null;
			}
			int VirtualAdd(Container c, string sharedName, int stack, int maxStack)
			{
				List<VSlot> list3 = virtualSlots[c];
				int num = Capacity(c);
				int num2 = stack;
				foreach (VSlot item7 in list3)
				{
					if (!(item7.Name != sharedName) && item7.Stack < item7.MaxStack)
					{
						int num3 = Math.Min(item7.MaxStack - item7.Stack, num2);
						item7.Stack += num3;
						num2 -= num3;
						if (num2 == 0)
						{
							return stack;
						}
					}
				}
				while (num2 > 0 && list3.Count < num)
				{
					int num4 = Math.Min(maxStack, num2);
					list3.Add(new VSlot(sharedName, num4, maxStack));
					num2 -= num4;
				}
				return stack - num2;
			}
			void VirtualRemove(Container c, string sharedName, int stack)
			{
				string sharedName2 = sharedName;
				List<VSlot> list4 = virtualSlots[c];
				VSlot vSlot = list4.FirstOrDefault((VSlot s) => s.Name == sharedName2 && s.Stack == stack);
				if (vSlot == null)
				{
					vSlot = (from s in list4
						where s.Name == sharedName2 && s.Stack >= stack
						orderby s.Stack - stack
						select s).FirstOrDefault();
				}
				if (vSlot == null)
				{
					vSlot = list4.FirstOrDefault((VSlot s) => s.Name == sharedName2);
				}
				if (vSlot != null)
				{
					vSlot.Stack -= stack;
					if (vSlot.Stack <= 0)
					{
						list4.Remove(vSlot);
					}
				}
			}
			int VirtualRoom(Container c, string sharedName, int maxStack)
			{
				string sharedName3 = sharedName;
				List<VSlot> list5 = virtualSlots[c];
				int num5 = Capacity(c);
				int num6 = Math.Max(0, num5 - list5.Count);
				int num7 = list5.Where((VSlot s) => s.Name == sharedName3 && s.Stack < s.MaxStack).Sum((VSlot s) => s.MaxStack - s.Stack);
				return num6 * maxStack + num7;
			}
		}

		public static Container? FindBestDestination(ItemData item, List<ChestOwnership> ownerships, Container? sourceContainer)
		{
			Container sourceContainer2 = sourceContainer;
			ItemData item2 = item;
			SortCategory itemCat = ItemCategorizer.GetCategory(item2);
			string itemKey = ItemCategorizer.GetItemKey(item2);
			List<ChestOwnership> list = ownerships.Where((ChestOwnership o) => !o.IsFreeChest && o.Category == itemCat).ToList();
			if (list.Count > 0)
			{
				ChestOwnership chestOwnership = list.FirstOrDefault((ChestOwnership o) => o.IsTagged && (Object)(object)o.Container != (Object)(object)sourceContainer2 && HasRoomFor(o.Container, item2));
				if (chestOwnership != null)
				{
					return chestOwnership.Container;
				}
				ChestOwnership chestOwnership2 = list.FirstOrDefault(delegate(ChestOwnership o)
				{
					if (!o.IsTagged && (Object)(object)o.Container != (Object)(object)sourceContainer2 && HasRoomFor(o.Container, item2))
					{
						Inventory inventory = o.Container.GetInventory();
						if (inventory == null)
						{
							return false;
						}
						return inventory.GetAllItems().Any((ItemData i) => ItemCategorizer.GetItemKey(i) == itemKey);
					}
					return false;
				});
				if (chestOwnership2 != null)
				{
					return chestOwnership2.Container;
				}
				ChestOwnership chestOwnership3 = list.FirstOrDefault((ChestOwnership o) => (Object)(object)o.Container != (Object)(object)sourceContainer2 && HasRoomFor(o.Container, item2));
				if (chestOwnership3 != null)
				{
					return chestOwnership3.Container;
				}
			}
			ChestOwnership chestOwnership4 = ownerships.FirstOrDefault((ChestOwnership o) => (o.IsFreeChest || o.Category == SortCategory.Unknown) && o.EmptySlots > 0 && (Object)(object)o.Container != (Object)(object)sourceContainer2);
			if (chestOwnership4 != null)
			{
				chestOwnership4.IsFreeChest = false;
				chestOwnership4.Category = itemCat;
				return chestOwnership4.Container;
			}
			return null;
		}

		public static bool HasRoomFor(Container container, ItemData item)
		{
			ItemData item2 = item;
			Inventory inventory = container.GetInventory();
			if (inventory == null)
			{
				return false;
			}
			if (inventory.GetEmptySlots() > 0)
			{
				return true;
			}
			return inventory.GetAllItems().Any((ItemData i) => i.m_shared.m_name == item2.m_shared.m_name && i.m_stack < i.m_shared.m_maxStackSize);
		}

		public static ChestOwnership? ResolveContainer(Container container)
		{
			Inventory inventory = container.GetInventory();
			if (inventory == null)
			{
				return null;
			}
			if (AutoSortPlugin.EnableTagOverride.Value && ItemCategorizer.TryParseChestTag(GetChestTag(container), out var category))
			{
				return new ChestOwnership(container, category, isTagged: true, int.MaxValue);
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null || allItems.Count == 0)
			{
				return new ChestOwnership(container, SortCategory.Unknown, isTagged: false, 0)
				{
					IsFreeChest = true
				};
			}
			Dictionary<SortCategory, int> dictionary = new Dictionary<SortCategory, int>();
			foreach (ItemData item in allItems)
			{
				SortCategory category2 = ItemCategorizer.GetCategory(item);
				dictionary.TryGetValue(category2, out var value);
				dictionary[category2] = value + item.m_stack;
			}
			KeyValuePair<SortCategory, int> keyValuePair = dictionary.OrderByDescending((KeyValuePair<SortCategory, int> kv) => kv.Value).First();
			return new ChestOwnership(container, keyValuePair.Key, isTagged: false, keyValuePair.Value);
		}

		public static bool IsAccessible(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				return component.IsValid();
			}
			return false;
		}

		public static string GetChestTag(Container container)
		{
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return string.Empty;
			}
			return component.GetZDO().GetString("tag", string.Empty);
		}

		public static (SortCategory category, bool isTagged, bool isFree) GetContainerStatus(Container container)
		{
			ChestOwnership chestOwnership = ResolveContainer(container);
			if (chestOwnership == null)
			{
				return (SortCategory.Unknown, false, true);
			}
			return (chestOwnership.Category, chestOwnership.IsTagged, chestOwnership.IsFreeChest);
		}

		private static List<ChestOwnership> SortInferredByPosition(List<ChestOwnership> inferred)
		{
			if (inferred.Count <= 1)
			{
				return inferred;
			}
			List<ChestOwnership> list = (from o in inferred
				orderby Mathf.Round(((Component)o.Container).transform.position.z / 1.5f) descending, ((Component)o.Container).transform.position.x
				select o).ToList();
			Dictionary<SortCategory, int> catFirstIndex = new Dictionary<SortCategory, int>();
			for (int i = 0; i < list.Count; i++)
			{
				SortCategory category = list[i].Category;
				if (!catFirstIndex.ContainsKey(category))
				{
					catFirstIndex[category] = i;
				}
			}
			return (from t in list.Select((ChestOwnership o, int idx) => (o, idx))
				orderby catFirstIndex[t.o.Category], t.idx
				select t.o).ToList();
		}

		public static List<(ItemData item, Container src, Container dst)> PlanSort(List<ChestOwnership> ownerships)
		{
			Dictionary<ItemData, Container> dictionary = PlanSortFull(ownerships);
			List<(ItemData, Container, Container)> list = new List<(ItemData, Container, Container)>();
			foreach (ChestOwnership ownership in ownerships)
			{
				Inventory inventory = ownership.Container.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (dictionary.TryGetValue(allItem, out var value) && (Object)(object)value != (Object)(object)ownership.Container)
					{
						list.Add((allItem, ownership.Container, value));
					}
				}
			}
			return list;
		}
	}
	internal sealed class ReferenceEqualityComparer : IEqualityComparer<ItemData>
	{
		public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();

		public bool Equals(ItemData x, ItemData y)
		{
			return x == y;
		}

		public int GetHashCode(ItemData obj)
		{
			return RuntimeHelpers.GetHashCode(obj);
		}
	}
	public static class ContainersTracker
	{
		private static readonly List<Container> _containers = new List<Container>();

		public static bool IsRearrangingItem { get; set; } = false;


		public static IReadOnlyList<Container> All => _containers;

		public static void Register(Container c)
		{
			if ((Object)(object)c != (Object)null && !_containers.Contains(c))
			{
				_containers.Add(c);
			}
		}

		public static void Unregister(Container c)
		{
			_containers.Remove(c);
		}

		public static void Cleanup()
		{
			_containers.RemoveAll(delegate(Container c)
			{
				if ((Object)(object)c == (Object)null)
				{
					return true;
				}
				ZNetView component = ((Component)c).GetComponent<ZNetView>();
				return (Object)(object)component == (Object)null || !component.IsValid();
			});
		}

		public static List<Container> GetNearby(Vector3 origin, float radius)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			Cleanup();
			List<Container> list = new List<Container>();
			float num = radius * radius;
			foreach (Container container in _containers)
			{
				if ((Object)(object)container != (Object)null)
				{
					Vector3 val = ((Component)container).transform.position - origin;
					if (((Vector3)(ref val)).sqrMagnitude <= num)
					{
						list.Add(container);
					}
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	public static class Patch_Container_Awake
	{
		[HarmonyPostfix]
		public static void Postfix(Container __instance)
		{
			if (!AutoSortPlugin.ModEnabled.Value || ((Object)__instance).name.StartsWith("Treasure") || __instance.GetInventory() == null)
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			long @long = zDO.GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L);
			long owner = zDO.GetOwner();
			if (@long != 0L || owner != 0L)
			{
				ContainersTracker.Register(__instance);
				if (AutoSortPlugin.LogDebug.Value)
				{
					AutoSortPlugin.Log.LogDebug((object)("[AutoSort] Registered chest '" + ((Object)__instance).name + "'"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Container), "OnDestroyed")]
	public static class Patch_Container_OnDestroyed
	{
		[HarmonyPostfix]
		public static void Postfix(Container __instance)
		{
			ContainersTracker.Unregister(__instance);
		}
	}
	public static class GroundItemSucker
	{
		private static float _timer = 0f;

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

		public static void Tick(float dt)
		{
			if (AutoSortPlugin.ModEnabled.Value && AutoSortPlugin.EnableGroundSuck.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && !ContainersTracker.IsRearrangingItem)
			{
				_timer += dt;
				if (!(_timer < AutoSortPlugin.GroundSuckInterval.Value))
				{
					_timer = 0f;
					SuckNearbyGroundItems();
				}
			}
		}

		private static void SuckNearbyGroundItems()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			float value = AutoSortPlugin.ScanRadius.Value;
			float value2 = AutoSortPlugin.GroundSuckRadius.Value;
			List<ChestOwnership> list = ChestOwnershipResolver.Resolve(position, value);
			if (list.Count == 0)
			{
				return;
			}
			ItemDrop[] array = Object.FindObjectsOfType<ItemDrop>();
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>();
			ItemDrop[] array2 = array;
			foreach (ItemDrop obj in array2)
			{
				ZNetView val = ((obj != null) ? ((Component)obj).GetComponent<ZNetView>() : null);
				if ((Object)(object)val != (Object)null && val.IsValid())
				{
					hashSet.Add(val.GetZDO().m_uid);
				}
			}
			_claimedZdoids.IntersectWith(hashSet);
			List<(ItemDrop, ZDOID)> list2 = new List<(ItemDrop, ZDOID)>();
			array2 = array;
			foreach (ItemDrop val2 in array2)
			{
				if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy)
				{
					continue;
				}
				ZNetView component = ((Component)val2).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					ZDOID uid = component.GetZDO().m_uid;
					if (!_claimedZdoids.Contains(uid) && component.GetZDO().GetInt("inUse", 0) == 0 && !(Vector3.Distance(((Component)val2).transform.position, position) > value2) && val2.m_itemData?.m_shared != null)
					{
						list2.Add((val2, uid));
					}
				}
			}
			if (list2.Count == 0)
			{
				return;
			}
			ContainersTracker.IsRearrangingItem = true;
			HashSet<Container> hashSet2 = new HashSet<Container>();
			HashSet<string> hashSet3 = new HashSet<string>();
			int num = 0;
			try
			{
				foreach (var (val3, item) in list2)
				{
					if (!((Object)(object)val3 == (Object)null) && ((Component)val3).gameObject.activeInHierarchy)
					{
						ItemData itemData = val3.m_itemData;
						Container val4 = ChestOwnershipResolver.FindBestDestination(itemData, list, null);
						if ((Object)(object)val4 == (Object)null)
						{
							hashSet3.Add(ItemCategorizer.GetCategory(itemData).ToString());
						}
						else if (ChestOwnershipResolver.HasRoomFor(val4, itemData) && val4.GetInventory().AddItem(itemData))
						{
							_claimedZdoids.Add(item);
							hashSet2.Add(val4);
							ChestEffects.PlayEffect(val4);
							ZNetScene.instance.Destroy(((Component)val3).gameObject);
							num++;
						}
					}
				}
				foreach (Container item2 in hashSet2)
				{
					SortEngine.MarkDirty(item2);
				}
			}
			finally
			{
				ContainersTracker.IsRearrangingItem = false;
			}
			if (num > 0 && AutoSortPlugin.LogDebug.Value)
			{
				AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] Ground sucker pulled {num} item(s).");
			}
			if (hashSet3.Count > 0)
			{
				Player localPlayer2 = Player.m_localPlayer;
				if (localPlayer2 != null)
				{
					((Character)localPlayer2).Message((MessageType)2, "<color=#ffaa44>AutoSort: no chest for " + string.Join(", ", hashSet3) + " — items left on ground.</color>", 0, (Sprite)null);
				}
			}
		}
	}
	public static class InventoryExtensions
	{
		public static string SaveInventory(this Inventory inventory)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			inventory.Save(val);
			return val.GetBase64();
		}

		public static void LoadInventory(this Inventory inventory, string data)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			if (!string.IsNullOrEmpty(data))
			{
				ZPackage val = new ZPackage(data);
				inventory.Load(val);
			}
		}
	}
	public enum SortCategory
	{
		Stone,
		Wood,
		Metal,
		Ore,
		Gem,
		Leather,
		Bone,
		Fiber,
		Seed,
		Food,
		Potion,
		Fish,
		Arrow,
		Weapon,
		Shield,
		Armor,
		Tool,
		Magic,
		Trophy,
		Furniture,
		Misc,
		Unknown
	}
	public static class ItemCategorizer
	{
		private enum MatchMode
		{
			Equals,
			StartsWith,
			Contains
		}

		private static Dictionary<string, SortCategory> _configMap = new Dictionary<string, SortCategory>(StringComparer.OrdinalIgnoreCase);

		private static Dictionary<string, SortCategory> _jsonMap = new Dictionary<string, SortCategory>(StringComparer.OrdinalIgnoreCase);

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

		private static FileSystemWatcher? _jsonWatcher;

		private static Timer? _reloadTimer;

		private const int ReloadDelayMs = 400;

		private static readonly Dictionary<string, SortCategory> _exactMap = new Dictionary<string, SortCategory>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"Stone",
				SortCategory.Stone
			},
			{
				"Flint",
				SortCategory.Stone
			},
			{
				"Obsidian",
				SortCategory.Stone
			},
			{
				"Coal",
				SortCategory.Stone
			},
			{
				"BlackMarble",
				SortCategory.Stone
			},
			{
				"Grausten",
				SortCategory.Stone
			},
			{
				"Wood",
				SortCategory.Wood
			},
			{
				"FineWood",
				SortCategory.Wood
			},
			{
				"RoundLog",
				SortCategory.Wood
			},
			{
				"YggdrasilWood",
				SortCategory.Wood
			},
			{
				"AncientBark",
				SortCategory.Wood
			},
			{
				"ElderBark",
				SortCategory.Wood
			},
			{
				"AshWood",
				SortCategory.Wood
			},
			{
				"WoodBeam",
				SortCategory.Wood
			},
			{
				"CopperOre",
				SortCategory.Ore
			},
			{
				"TinOre",
				SortCategory.Ore
			},
			{
				"IronScrap",
				SortCategory.Ore
			},
			{
				"SilverOre",
				SortCategory.Ore
			},
			{
				"BlackMetalScrap",
				SortCategory.Ore
			},
			{
				"FlametalOre",
				SortCategory.Ore
			},
			{
				"MucusOre",
				SortCategory.Ore
			},
			{
				"CopperScrap",
				SortCategory.Ore
			},
			{
				"Bronze",
				SortCategory.Metal
			},
			{
				"Iron",
				SortCategory.Metal
			},
			{
				"Silver",
				SortCategory.Metal
			},
			{
				"BlackMetal",
				SortCategory.Metal
			},
			{
				"Copper",
				SortCategory.Metal
			},
			{
				"Tin",
				SortCategory.Metal
			},
			{
				"Flametal",
				SortCategory.Metal
			},
			{
				"DvergrMetal",
				SortCategory.Metal
			},
			{
				"BlackCore",
				SortCategory.Metal
			},
			{
				"MorgenCore",
				SortCategory.Metal
			},
			{
				"BronzeNails",
				SortCategory.Metal
			},
			{
				"IronNails",
				SortCategory.Metal
			},
			{
				"Amber",
				SortCategory.Gem
			},
			{
				"AmberPearl",
				SortCategory.Gem
			},
			{
				"Ruby",
				SortCategory.Gem
			},
			{
				"SilverNecklace",
				SortCategory.Gem
			},
			{
				"BlackGem",
				SortCategory.Gem
			},
			{
				"Coins",
				SortCategory.Gem
			},
			{
				"LeatherScraps",
				SortCategory.Leather
			},
			{
				"DeerHide",
				SortCategory.Leather
			},
			{
				"ScaleHide",
				SortCategory.Leather
			},
			{
				"WolfPelt",
				SortCategory.Leather
			},
			{
				"LoxPelt",
				SortCategory.Leather
			},
			{
				"TrollHide",
				SortCategory.Leather
			},
			{
				"AskHide",
				SortCategory.Leather
			},
			{
				"BoneFragments",
				SortCategory.Bone
			},
			{
				"WitheredBone",
				SortCategory.Bone
			},
			{
				"Chitin",
				SortCategory.Bone
			},
			{
				"Carapace",
				SortCategory.Bone
			},
			{
				"HardAntler",
				SortCategory.Bone
			},
			{
				"DragonEgg",
				SortCategory.Bone
			},
			{
				"Flax",
				SortCategory.Fiber
			},
			{
				"FlaxThread",
				SortCategory.Fiber
			},
			{
				"Barley",
				SortCategory.Fiber
			},
			{
				"BarleyFlour",
				SortCategory.Fiber
			},
			{
				"Thistle",
				SortCategory.Fiber
			},
			{
				"Dandelion",
				SortCategory.Fiber
			},
			{
				"Bloodbag",
				SortCategory.Fiber
			},
			{
				"Guck",
				SortCategory.Fiber
			},
			{
				"LinenThread",
				SortCategory.Fiber
			},
			{
				"JuteRed",
				SortCategory.Fiber
			},
			{
				"JuteBlue",
				SortCategory.Fiber
			},
			{
				"Eitr",
				SortCategory.Magic
			},
			{
				"Sap",
				SortCategory.Magic
			},
			{
				"SoftTissue",
				SortCategory.Magic
			},
			{
				"Wisp",
				SortCategory.Magic
			},
			{
				"WispTorch",
				SortCategory.Magic
			},
			{
				"DvergrNeedle",
				SortCategory.Magic
			},
			{
				"Dundr",
				SortCategory.Magic
			},
			{
				"GemstoneGreen",
				SortCategory.Magic
			},
			{
				"GemstoneBlue",
				SortCategory.Magic
			},
			{
				"GemstoneRed",
				SortCategory.Magic
			},
			{
				"VolcanicRock",
				SortCategory.Magic
			},
			{
				"AshflameKindling",
				SortCategory.Magic
			},
			{
				"CharredRemains",
				SortCategory.Magic
			},
			{
				"Emberlite",
				SortCategory.Magic
			},
			{
				"Acorn",
				SortCategory.Seed
			},
			{
				"AncientSeed",
				SortCategory.Seed
			},
			{
				"BeechSeeds",
				SortCategory.Seed
			},
			{
				"BirchSeeds",
				SortCategory.Seed
			},
			{
				"CarrotSeeds",
				SortCategory.Seed
			},
			{
				"TurnipSeeds",
				SortCategory.Seed
			},
			{
				"OnionSeeds",
				SortCategory.Seed
			},
			{
				"FlaxSeeds",
				SortCategory.Seed
			},
			{
				"BarleySeeds",
				SortCategory.Seed
			},
			{
				"JuteSeedRed",
				SortCategory.Seed
			},
			{
				"SeedCarrot",
				SortCategory.Seed
			},
			{
				"SeedTurnip",
				SortCategory.Seed
			},
			{
				"SeedOnion",
				SortCategory.Seed
			},
			{
				"SeedBarley",
				SortCategory.Seed
			},
			{
				"SeedFlax",
				SortCategory.Seed
			},
			{
				"PineCone",
				SortCategory.Seed
			},
			{
				"FirCone",
				SortCategory.Seed
			},
			{
				"Surtling_Immature",
				SortCategory.Seed
			},
			{
				"Mushroom",
				SortCategory.Food
			},
			{
				"MushroomBlue",
				SortCategory.Food
			},
			{
				"MushroomYellow",
				SortCategory.Food
			},
			{
				"Raspberry",
				SortCategory.Food
			},
			{
				"Blueberries",
				SortCategory.Food
			},
			{
				"Cloudberry",
				SortCategory.Food
			},
			{
				"Carrot",
				SortCategory.Food
			},
			{
				"Turnip",
				SortCategory.Food
			},
			{
				"Onion",
				SortCategory.Food
			},
			{
				"Honey",
				SortCategory.Food
			},
			{
				"Egg",
				SortCategory.Food
			},
			{
				"Entrails",
				SortCategory.Food
			},
			{
				"NeckTail",
				SortCategory.Food
			},
			{
				"DeerMeat",
				SortCategory.Food
			},
			{
				"WolfMeat",
				SortCategory.Food
			},
			{
				"LoxMeat",
				SortCategory.Food
			},
			{
				"SerpentMeat",
				SortCategory.Food
			},
			{
				"SerpentMeatCooked",
				SortCategory.Food
			},
			{
				"ChickenMeat",
				SortCategory.Food
			},
			{
				"ChickenEgg",
				SortCategory.Food
			},
			{
				"VoltureMeat",
				SortCategory.Food
			},
			{
				"AsksvinMeat",
				SortCategory.Food
			},
			{
				"CharredMeat",
				SortCategory.Food
			},
			{
				"CarrotSoup",
				SortCategory.Food
			},
			{
				"TurnipStew",
				SortCategory.Food
			},
			{
				"OnionSoup",
				SortCategory.Food
			},
			{
				"QueensJam",
				SortCategory.Food
			},
			{
				"Bread",
				SortCategory.Food
			},
			{
				"FishWraps",
				SortCategory.Food
			},
			{
				"MinceMeatSauce",
				SortCategory.Food
			},
			{
				"Sausages",
				SortCategory.Food
			},
			{
				"BlackSoup",
				SortCategory.Food
			},
			{
				"WolfMeatSkewer",
				SortCategory.Food
			},
			{
				"WolfJerky",
				SortCategory.Food
			},
			{
				"LoxPie",
				SortCategory.Food
			},
			{
				"LoxMeatPie",
				SortCategory.Food
			},
			{
				"SerpentStew",
				SortCategory.Food
			},
			{
				"BloodPudding",
				SortCategory.Food
			},
			{
				"EyeScream",
				SortCategory.Food
			},
			{
				"BugMeat",
				SortCategory.Food
			},
			{
				"MisthareSupreme",
				SortCategory.Food
			},
			{
				"HareMeat",
				SortCategory.Food
			},
			{
				"YggdrasilPorridge",
				SortCategory.Food
			},
			{
				"MarinatedGreens",
				SortCategory.Food
			},
			{
				"ScalpSkewer",
				SortCategory.Food
			},
			{
				"SeekerAspic",
				SortCategory.Food
			},
			{
				"FishNBread",
				SortCategory.Food
			},
			{
				"Salad",
				SortCategory.Food
			},
			{
				"SpicedMeat",
				SortCategory.Food
			},
			{
				"AshenMeat",
				SortCategory.Food
			},
			{
				"CookedBugMeat",
				SortCategory.Food
			},
			{
				"CookedChickenMeat",
				SortCategory.Food
			},
			{
				"CookedDeerMeat",
				SortCategory.Food
			},
			{
				"CookedWolfMeat",
				SortCategory.Food
			},
			{
				"CookedLoxMeat",
				SortCategory.Food
			},
			{
				"CookedHareMeat",
				SortCategory.Food
			},
			{
				"CookedVoltureMeat",
				SortCategory.Food
			},
			{
				"CookedAsksvinMeat",
				SortCategory.Food
			},
			{
				"CookedCharredMeat",
				SortCategory.Food
			},
			{
				"BarleyWine",
				SortCategory.Food
			},
			{
				"CloudberryWine",
				SortCategory.Food
			},
			{
				"Fish1",
				SortCategory.Fish
			},
			{
				"Fish2",
				SortCategory.Fish
			},
			{
				"Fish3",
				SortCategory.Fish
			},
			{
				"Fish4_cave",
				SortCategory.Fish
			},
			{
				"Fish5",
				SortCategory.Fish
			},
			{
				"Fish6",
				SortCategory.Fish
			},
			{
				"Fish7",
				SortCategory.Fish
			},
			{
				"Fish8",
				SortCategory.Fish
			},
			{
				"Fish9",
				SortCategory.Fish
			},
			{
				"Fish10",
				SortCategory.Fish
			},
			{
				"Fish11",
				SortCategory.Fish
			},
			{
				"Fish12",
				SortCategory.Fish
			},
			{
				"FishCooked",
				SortCategory.Fish
			},
			{
				"FishAndBread",
				SortCategory.Fish
			},
			{
				"MeadBase",
				SortCategory.Potion
			},
			{
				"MeadBaseFrostResist",
				SortCategory.Potion
			},
			{
				"MeadBaseHealthMinor",
				SortCategory.Potion
			},
			{
				"MeadBaseHealthMedium",
				SortCategory.Potion
			},
			{
				"MeadBaseHealthMajor",
				SortCategory.Potion
			},
			{
				"MeadBaseStaminaMinor",
				SortCategory.Potion
			},
			{
				"MeadBaseStaminaMedium",
				SortCategory.Potion
			},
			{
				"MeadBaseStaminaLingering",
				SortCategory.Potion
			},
			{
				"MeadBasePoisonResist",
				SortCategory.Potion
			},
			{
				"MeadBaseTasty",
				SortCategory.Potion
			},
			{
				"MeadBaseEitrMinor",
				SortCategory.Potion
			},
			{
				"MeadBaseEitrMedium",
				SortCategory.Potion
			},
			{
				"MeadFrostResist",
				SortCategory.Potion
			},
			{
				"MeadHealthMinor",
				SortCategory.Potion
			},
			{
				"MeadHealthMedium",
				SortCategory.Potion
			},
			{
				"MeadHealthMajor",
				SortCategory.Potion
			},
			{
				"MeadStaminaMinor",
				SortCategory.Potion
			},
			{
				"MeadStaminaMedium",
				SortCategory.Potion
			},
			{
				"MeadStaminaLingering",
				SortCategory.Potion
			},
			{
				"MeadPoisonResist",
				SortCategory.Potion
			},
			{
				"MeadTasty",
				SortCategory.Potion
			},
			{
				"MeadEitrMinor",
				SortCategory.Potion
			},
			{
				"MeadEitrMedium",
				SortCategory.Potion
			},
			{
				"ArrowWood",
				SortCategory.Arrow
			},
			{
				"ArrowFlint",
				SortCategory.Arrow
			},
			{
				"ArrowBronze",
				SortCategory.Arrow
			},
			{
				"ArrowIron",
				SortCategory.Arrow
			},
			{
				"ArrowObsidian",
				SortCategory.Arrow
			},
			{
				"ArrowSilver",
				SortCategory.Arrow
			},
			{
				"ArrowNeedle",
				SortCategory.Arrow
			},
			{
				"ArrowFire",
				SortCategory.Arrow
			},
			{
				"ArrowPoison",
				SortCategory.Arrow
			},
			{
				"ArrowFrost",
				SortCategory.Arrow
			},
			{
				"ArrowCharred",
				SortCategory.Arrow
			},
			{
				"ArrowCarapace",
				SortCategory.Arrow
			},
			{
				"BoltBone",
				SortCategory.Arrow
			},
			{
				"BoltIron",
				SortCategory.Arrow
			},
			{
				"BoltBlackmetal",
				SortCategory.Arrow
			},
			{
				"BoltCarapace",
				SortCategory.Arrow
			},
			{
				"BoltCharred",
				SortCategory.Arrow
			},
			{
				"TrophyBoar",
				SortCategory.Trophy
			},
			{
				"TrophyNeck",
				SortCategory.Trophy
			},
			{
				"TrophyDeer",
				SortCategory.Trophy
			},
			{
				"TrophyGreydwarf",
				SortCategory.Trophy
			},
			{
				"TrophyGreydwarfBrute",
				SortCategory.Trophy
			},
			{
				"TrophyGreydwarfShaman",
				SortCategory.Trophy
			},
			{
				"TrophyForestTroll",
				SortCategory.Trophy
			},
			{
				"TrophySkeletonPoison",
				SortCategory.Trophy
			},
			{
				"TrophySkeleton",
				SortCategory.Trophy
			},
			{
				"TrophyDraugr",
				SortCategory.Trophy
			},
			{
				"TrophyDraugrElite",
				SortCategory.Trophy
			},
			{
				"TrophyBlob",
				SortCategory.Trophy
			},
			{
				"TrophyLeech",
				SortCategory.Trophy
			},
			{
				"TrophyDraugrFem",
				SortCategory.Trophy
			},
			{
				"TrophyWraith",
				SortCategory.Trophy
			},
			{
				"TrophyAbomination",
				SortCategory.Trophy
			},
			{
				"TrophyLox",
				SortCategory.Trophy
			},
			{
				"TrophySGolem",
				SortCategory.Trophy
			},
			{
				"TrophyWolf",
				SortCategory.Trophy
			},
			{
				"TrophyHatchling",
				SortCategory.Trophy
			},
			{
				"TrophyFenring",
				SortCategory.Trophy
			},
			{
				"TrophySerpent",
				SortCategory.Trophy
			},
			{
				"TrophyDeathsquito",
				SortCategory.Trophy
			},
			{
				"TrophyGrowth",
				SortCategory.Trophy
			},
			{
				"TrophySeeker",
				SortCategory.Trophy
			},
			{
				"TrophySeekerBrute",
				SortCategory.Trophy
			},
			{
				"TrophyTick",
				SortCategory.Trophy
			},
			{
				"TrophyHare",
				SortCategory.Trophy
			},
			{
				"TrophyGjall",
				SortCategory.Trophy
			},
			{
				"TrophyCharredMelee",
				SortCategory.Trophy
			},
			{
				"TrophyCharredArcher",
				SortCategory.Trophy
			},
			{
				"TrophyCharredTwitcher",
				SortCategory.Trophy
			},
			{
				"TrophyCharredWarlock",
				SortCategory.Trophy
			},
			{
				"TrophyFader",
				SortCategory.Trophy
			},
			{
				"TrophyEikthyr",
				SortCategory.Trophy
			},
			{
				"TrophyElder",
				SortCategory.Trophy
			},
			{
				"TrophyBonemass",
				SortCategory.Trophy
			},
			{
				"TrophyDragonQueen",
				SortCategory.Trophy
			},
			{
				"TrophyGoblinKing",
				SortCategory.Trophy
			},
			{
				"TrophyQueenBee",
				SortCategory.Trophy
			},
			{
				"TrophyVolture",
				SortCategory.Trophy
			},
			{
				"TrophyAskvin",
				SortCategory.Trophy
			}
		};

		private static readonly (string key, SortCategory cat, MatchMode mode)[] _prefabRules = new(string, SortCategory, MatchMode)[89]
		{
			("ArmorAshlands", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorBerserker", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorBronze", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorCarapace", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorFenring", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorFlametal", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorIron", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorLeather", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorMage", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorPadded", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorRags", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorRoot", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorTroll", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorWolf", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorDress", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorTunic", SortCategory.Armor, MatchMode.StartsWith),
			("ArmorHarvester", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetAshlands", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetBronze", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetCarapace", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetDrake", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetDverger", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetFenring", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetFlametal", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetIron", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetLeather", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetMage", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetOdin", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetPadded", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetRoot", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetTroll", SortCategory.Armor, MatchMode.StartsWith),
			("HelmetYule", SortCategory.Armor, MatchMode.StartsWith),
			("CapeAsh", SortCategory.Armor, MatchMode.StartsWith),
			("CapeDeerHide", SortCategory.Armor, MatchMode.StartsWith),
			("CapeFeather", SortCategory.Armor, MatchMode.StartsWith),
			("CapeLinen", SortCategory.Armor, MatchMode.StartsWith),
			("CapeLox", SortCategory.Armor, MatchMode.StartsWith),
			("CapeOdin", SortCategory.Armor, MatchMode.StartsWith),
			("CapeTroll", SortCategory.Armor, MatchMode.StartsWith),
			("CapeWolf", SortCategory.Armor, MatchMode.StartsWith),
			("ShieldAsh", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldBlack", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldBronze", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldCarapace", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldFlametal", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldIron", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldKnight", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldSerpent", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldSilver", SortCategory.Shield, MatchMode.StartsWith),
			("ShieldWood", SortCategory.Shield, MatchMode.StartsWith),
			("Sword", SortCategory.Weapon, MatchMode.StartsWith),
			("Axe", SortCategory.Weapon, MatchMode.StartsWith),
			("Club", SortCategory.Weapon, MatchMode.StartsWith),
			("Knife", SortCategory.Weapon, MatchMode.StartsWith),
			("Mace", SortCategory.Weapon, MatchMode.StartsWith),
			("Sledge", SortCategory.Weapon, MatchMode.StartsWith),
			("Spear", SortCategory.Weapon, MatchMode.StartsWith),
			("Bow", SortCategory.Weapon, MatchMode.StartsWith),
			("Crossbow", SortCategory.Weapon, MatchMode.StartsWith),
			("Arbalest", SortCategory.Weapon, MatchMode.StartsWith),
			("AtgeirHilder", SortCategory.Weapon, MatchMode.StartsWith),
			("AtgeirBronze", SortCategory.Weapon, MatchMode.StartsWith),
			("AtgeirIron", SortCategory.Weapon, MatchMode.StartsWith),
			("AtgeirBlackmetal", SortCategory.Weapon, MatchMode.StartsWith),
			("Battleaxe", SortCategory.Weapon, MatchMode.StartsWith),
			("GreatSword", SortCategory.Weapon, MatchMode.StartsWith),
			("THSword", SortCategory.Weapon, MatchMode.StartsWith),
			("Staff", SortCategory.Weapon, MatchMode.StartsWith),
			("Wand", SortCategory.Weapon, MatchMode.StartsWith),
			("Pickaxe", SortCategory.Tool, MatchMode.StartsWith),
			("Hammer", SortCategory.Tool, MatchMode.StartsWith),
			("Hoe", SortCategory.Tool, MatchMode.StartsWith),
			("Cultivator", SortCategory.Tool, MatchMode.StartsWith),
			("FishingRod", SortCategory.Tool, MatchMode.StartsWith),
			("Arrow", SortCategory.Arrow, MatchMode.StartsWith),
			("Bolt", SortCategory.Arrow, MatchMode.StartsWith),
			("Trophy", SortCategory.Trophy, MatchMode.StartsWith),
			("Mead", SortCategory.Potion, MatchMode.StartsWith),
			("Fish", SortCategory.Fish, MatchMode.StartsWith),
			("Mushroom", SortCategory.Food, MatchMode.StartsWith),
			("Cooked", SortCategory.Food, MatchMode.StartsWith),
			("Seeds", SortCategory.Seed, MatchMode.Contains),
			("Seed", SortCategory.Seed, MatchMode.Contains),
			("Ore", SortCategory.Ore, MatchMode.Contains),
			("Scrap", SortCategory.Ore, MatchMode.Contains),
			("hide", SortCategory.Leather, MatchMode.Contains),
			("pelt", SortCategory.Leather, MatchMode.Contains),
			("bone", SortCategory.Bone, MatchMode.Contains),
			("trophy", SortCategory.Trophy, MatchMode.Contains)
		};

		public static string JsonFilePath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? AppDomain.CurrentDomain.BaseDirectory, "autosort_categories.json");

		public static IReadOnlyList<string> GetJsonExtraCategories()
		{
			return _jsonExtraCategories;
		}

		public static void InitJsonWatcher()
		{
			string jsonFilePath = JsonFilePath;
			if (!File.Exists(jsonFilePath))
			{
				WriteDefaultJson(jsonFilePath);
			}
			LoadFromJson();
			try
			{
				_jsonWatcher = new FileSystemWatcher(Path.GetDirectoryName(jsonFilePath), Path.GetFileName(jsonFilePath))
				{
					NotifyFilter = (NotifyFilters.Size | NotifyFilters.LastWrite),
					EnableRaisingEvents = true
				};
				_jsonWatcher.Changed += OnJsonChanged;
				_jsonWatcher.Created += OnJsonChanged;
				AutoSortPlugin.Log.LogInfo((object)("[AutoSort] Watching " + jsonFilePath + " for live category edits."));
			}
			catch (Exception ex)
			{
				AutoSortPlugin.Log.LogWarning((object)("[AutoSort] Could not start JSON watcher: " + ex.Message));
			}
		}

		private static void OnJsonChanged(object sender, FileSystemEventArgs e)
		{
			_reloadTimer?.Dispose();
			_reloadTimer = new Timer(delegate
			{
				LoadFromJson();
				AutoSortPlugin.Log.LogInfo((object)"[AutoSort] categories.json reloaded.");
			}, null, 400, -1);
		}

		public static void LoadFromJson()
		{
			string jsonFilePath = JsonFilePath;
			if (!File.Exists(jsonFilePath))
			{
				return;
			}
			try
			{
				string input = File.ReadAllText(jsonFilePath);
				Dictionary<string, SortCategory> dictionary = new Dictionary<string, SortCategory>(StringComparer.OrdinalIgnoreCase);
				List<string> list = new List<string>();
				foreach (Match item in new Regex("\"(?<cat>[^\"]+)\"\\s*:\\s*\\[(?<items>[^\\]]*)\\]", RegexOptions.Singleline).Matches(input))
				{
					string text = item.Groups["cat"].Value.Trim();
					string value = item.Groups["items"].Value;
					if (!Enum.TryParse<SortCategory>(text, ignoreCase: true, out var result))
					{
						result = SortCategory.Misc;
						list.Add(text);
					}
					foreach (Match item2 in Regex.Matches(value, "\"([^\"]+)\""))
					{
						string text2 = item2.Groups[1].Value.Trim();
						if (!string.IsNullOrEmpty(text2))
						{
							dictionary[text2] = result;
						}
					}
				}
				_jsonMap = dictionary;
				_jsonExtraCategories = list;
				if (AutoSortPlugin.LogDebug.Value)
				{
					AutoSortPlugin.Log.LogDebug((object)($"[AutoSort] JSON category map loaded: {dictionary.Count} items, " + $"{list.Count} custom categories."));
				}
			}
			catch (Exception ex)
			{
				AutoSortPlugin.Log.LogWarning((object)("[AutoSort] Failed to parse autosort_categories.json: " + ex.Message));
			}
		}

		private static void WriteDefaultJson(string path)
		{
			try
			{
				File.WriteAllText(path, "{\n  \"_comment\": \"AutoSort category overrides. Edit freely — changes are detected live in-game.\",\n  \"_comment2\": \"Keys are category names (see SortCategory enum). Values are prefab name lists.\",\n  \"_comment3\": \"Add modded items here. Use LogDebug=true in the .cfg to print prefab names.\",\n  \"_comment4\": \"You can also add CUSTOM category names — those items will sort into Misc chests.\",\n\n  \"Stone\":   [],\n  \"Wood\":    [],\n  \"Ore\":     [],\n  \"Metal\":   [],\n  \"Gem\":     [],\n  \"Leather\": [],\n  \"Bone\":    [],\n  \"Fiber\":   [],\n  \"Seed\":    [],\n  \"Food\":    [],\n  \"Potion\":  [],\n  \"Fish\":    [],\n  \"Arrow\":   [],\n  \"Weapon\":  [],\n  \"Shield\":  [],\n  \"Armor\":   [],\n  \"Tool\":    [],\n  \"Magic\":   [],\n  \"Trophy\":  [],\n  \"Furniture\":[],\n  \"Misc\":    []\n}\n");
			}
			catch
			{
			}
		}

		public static void LoadFromConfig()
		{
			Dictionary<string, SortCategory> dictionary = new Dictionary<string, SortCategory>(StringComparer.OrdinalIgnoreCase);
			ParseInto(dictionary, AutoSortPlugin.Cat_Stone.Value, SortCategory.Stone);
			ParseInto(dictionary, AutoSortPlugin.Cat_Wood.Value, SortCategory.Wood);
			ParseInto(dictionary, AutoSortPlugin.Cat_Ore.Value, SortCategory.Ore);
			ParseInto(dictionary, AutoSortPlugin.Cat_Metal.Value, SortCategory.Metal);
			ParseInto(dictionary, AutoSortPlugin.Cat_Gem.Value, SortCategory.Gem);
			ParseInto(dictionary, AutoSortPlugin.Cat_Leather.Value, SortCategory.Leather);
			ParseInto(dictionary, AutoSortPlugin.Cat_Bone.Value, SortCategory.Bone);
			ParseInto(dictionary, AutoSortPlugin.Cat_Fiber.Value, SortCategory.Fiber);
			ParseInto(dictionary, AutoSortPlugin.Cat_Seed.Value, SortCategory.Seed);
			ParseInto(dictionary, AutoSortPlugin.Cat_Food.Value, SortCategory.Food);
			ParseInto(dictionary, AutoSortPlugin.Cat_Potion.Value, SortCategory.Potion);
			ParseInto(dictionary, AutoSortPlugin.Cat_Fish.Value, SortCategory.Fish);
			ParseInto(dictionary, AutoSortPlugin.Cat_Arrow.Value, SortCategory.Arrow);
			ParseInto(dictionary, AutoSortPlugin.Cat_Weapon.Value, SortCategory.Weapon);
			ParseInto(dictionary, AutoSortPlugin.Cat_Shield.Value, SortCategory.Shield);
			ParseInto(dictionary, AutoSortPlugin.Cat_Armor.Value, SortCategory.Armor);
			ParseInto(dictionary, AutoSortPlugin.Cat_Tool.Value, SortCategory.Tool);
			ParseInto(dictionary, AutoSortPlugin.Cat_Magic.Value, SortCategory.Magic);
			ParseInto(dictionary, AutoSortPlugin.Cat_Trophy.Value, SortCategory.Trophy);
			ParseInto(dictionary, AutoSortPlugin.Cat_Furniture.Value, SortCategory.Furniture);
			ParseInto(dictionary, AutoSortPlugin.Cat_Misc.Value, SortCategory.Misc);
			_configMap = dictionary;
			if (AutoSortPlugin.LogDebug.Value)
			{
				AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] Category config loaded: {dictionary.Count} explicit item mappings.");
			}
		}

		private static void ParseInto(Dictionary<string, SortCategory> map, string csv, SortCategory cat)
		{
			if (string.IsNullOrWhiteSpace(csv))
			{
				return;
			}
			string[] array = csv.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!string.IsNullOrEmpty(text))
				{
					map[text] = cat;
				}
			}
		}

		public static SortCategory GetCategory(ItemData item)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected I4, but got Unknown
			if (item?.m_shared == null)
			{
				return SortCategory.Unknown;
			}
			string itemKey = GetItemKey(item);
			if (_jsonMap.TryGetValue(itemKey, out var value))
			{
				if (AutoSortPlugin.LogDebug.Value)
				{
					AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] '{itemKey}' → {value} (json)");
				}
				return value;
			}
			if (_configMap.TryGetValue(itemKey, out var value2))
			{
				if (AutoSortPlugin.LogDebug.Value)
				{
					AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] '{itemKey}' → {value2} (config)");
				}
				return value2;
			}
			ItemType itemType = item.m_shared.m_itemType;
			switch (itemType - 3)
			{
			case 0:
			case 1:
			case 11:
			case 12:
			case 19:
				return SortCategory.Weapon;
			case 2:
				return SortCategory.Shield;
			case 3:
			case 4:
			case 8:
			case 14:
				return SortCategory.Armor;
			case 16:
				return SortCategory.Tool;
			case 18:
				return SortCategory.Fish;
			case 6:
			case 20:
				return SortCategory.Arrow;
			default:
			{
				if (_exactMap.TryGetValue(itemKey, out var value3))
				{
					if (AutoSortPlugin.LogDebug.Value)
					{
						AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] '{itemKey}' → {value3} (built-in exact)");
					}
					return value3;
				}
				string text = itemKey.ToLowerInvariant();
				(string, SortCategory, MatchMode)[] prefabRules = _prefabRules;
				for (int i = 0; i < prefabRules.Length; i++)
				{
					(string, SortCategory, MatchMode) tuple = prefabRules[i];
					var (text2, sortCategory, _) = tuple;
					if (tuple.Item3 switch
					{
						MatchMode.Equals => text == text2.ToLowerInvariant(), 
						MatchMode.StartsWith => text.StartsWith(text2.ToLowerInvariant()), 
						MatchMode.Contains => text.Contains(text2.ToLowerInvariant()), 
						_ => false, 
					})
					{
						if (AutoSortPlugin.LogDebug.Value)
						{
							AutoSortPlugin.Log.LogDebug((object)$"[AutoSort] '{itemKey}' → {sortCategory} (prefix rule)");
						}
						return sortCategory;
					}
				}
				if (AutoSortPlugin.LogDebug.Value)
				{
					AutoSortPlugin.Log.LogDebug((object)("[AutoSort] '" + itemKey + "' → Misc (no match) — add to config if needed"));
				}
				return SortCategory.Misc;
			}
			}
		}

		public static string GetItemKey(ItemData item)
		{
			if (item == null)
			{
				return string.Empty;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name;
			}
			string text = item.m_shared?.m_name ?? string.Empty;
			if (!text.StartsWith("$item_"))
			{
				return text;
			}
			return text.Substring(6);
		}

		public static bool TryParseChestTag(string zdoTag, out SortCategory category)
		{
			category = SortCategory.Unknown;
			if (string.IsNullOrWhiteSpace(zdoTag))
			{
				return false;
			}
			Match match = Regex.Match(zdoTag, "\\[([^\\]]+)\\]");
			if (!match.Success)
			{
				return false;
			}
			return Enum.TryParse<SortCategory>(match.Groups[1].Value.Trim(), ignoreCase: true, out category);
		}
	}
	[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData)
	})]
	public static class Patch_Inventory_MoveItemToThis
	{
		[HarmonyPostfix]
		public static void Postfix(Inventory __instance, ItemData item)
		{
			if (!ContainersTracker.IsRearrangingItem && AutoSortPlugin.ModEnabled.Value && (!((Object)(object)Player.m_localPlayer != (Object)null) || ((Humanoid)Player.m_localPlayer).GetInventory() != __instance))
			{
				Container val = PatchHelpers.FindContainerForInventory(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					SortEngine.TriggerItemSort(item, val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
	public static class Patch_Inventory_AddItem
	{
		[ThreadStatic]
		private static ItemData? _pendingItem;

		[HarmonyPrefix]
		public static void Prefix(ItemData item)
		{
			_pendingItem = item;
		}

		[HarmonyPostfix]
		public static void Postfix(Inventory __instance, bool __result)
		{
			ItemData pendingItem = _pendingItem;
			_pendingItem = null;
			if (__result && !ContainersTracker.IsRearrangingItem && AutoSortPlugin.ModEnabled.Value && (!((Object)(object)Player.m_localPlayer != (Object)null) || ((Humanoid)Player.m_localPlayer).GetInventory() != __instance) && pendingItem != null)
			{
				Container val = PatchHelpers.FindContainerForInventory(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					SortEngine.TriggerItemSort(pendingItem, val);
				}
			}
		}
	}
	internal static class PatchHelpers
	{
		internal static Container? FindContainerForInventory(Inventory inv)
		{
			foreach (Container item in ContainersTracker.All)
			{
				if ((Object)(object)item != (Object)null && item.GetInventory() == inv)
				{
					return item;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	public static class Patch_Player_Update
	{
		[HarmonyPostfix]
		public static void Postfix(Player __instance)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && AutoSortPlugin.ModEnabled.Value)
			{
				GroundItemSucker.Tick(Time.deltaTime);
				if (!ContainersTracker.IsRearrangingItem && !StoreGui.IsVisible() && !Minimap.IsOpen() && IsKeybindDown(AutoSortPlugin.SortKeybind.Value))
				{
					SortEngine.TriggerSortPass();
				}
			}
		}

		private static bool IsKeybindDown(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0)
			{
				return false;
			}
			if (!Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Show")]
	public static class Patch_InventoryGui_Show
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__6_0;

			public static UnityAction<BaseEventData> <>9__6_1;

			internal void <CreateButton>b__6_0()
			{
				CycleCategory(forward: true);
			}

			internal void <CreateButton>b__6_1(BaseEventData data)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Invalid comparison between Unknown and I4
				if ((int)((PointerEventData)data).button == 1)
				{
					CycleCategory(forward: false);
				}
			}
		}

		[CompilerGenerated]
		private sealed class <WaitAndPositionButton>d__5 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitAndPositionButton>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Expected O, but got Unknown
				//IL_017f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0192: Unknown result type (might be due to invalid IL or missing references)
				//IL_019e: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if ((Object)(object)_btn == (Object)null || (Object)(object)((Component)_btn).gameObject == (Object)null)
					{
						return false;
					}
					if (!((Component)_btn).gameObject.activeSelf)
					{
						return false;
					}
					RectTransform component = ((Component)_btn).GetComponent<RectTransform>();
					if ((Object)(object)component == (Object)null)
					{
						return false;
					}
					component.anchorMin = new Vector2(1f, 1f);
					component.anchorMax = new Vector2(1f, 1f);
					component.pivot = new Vector2(1f, 1f);
					float num = 0f;
					bool flag = false;
					Transform parent = ((Component)_btn).transform.parent;
					if ((Object)(object)parent != (Object)null)
					{
						foreach (Transform item in parent)
						{
							Transform val = item;
							if ((Object)(object)((Component)val).gameObject == (Object)(object)((Component)_btn).gameObject || !((Component)val).gameObject.activeSelf)
							{
								continue;
							}
							string name = ((Object)val).name;
							if (!name.StartsWith("QuickStack", StringComparison.OrdinalIgnoreCase) && !name.StartsWith("StoreAll", StringComparison.OrdinalIgnoreCase) && !name.StartsWith("Restock", StringComparison.OrdinalIgnoreCase) && !name.StartsWith("Sort", StringComparison.OrdinalIgnoreCase))
							{
								continue;
							}
							RectTransform component2 = ((Component)val).GetComponent<RectTransform>();
							if (!((Object)(object)component2 == (Object)null) && !(component2.anchorMin.x < 0.9f))
							{
								float num2 = component2.anchoredPosition.y - component2.sizeDelta.y;
								if (num2 < num)
								{
									num = num2;
									flag = true;
								}
							}
						}
					}
					float num3 = ((!flag) ? (-6f) : (num - 4f));
					component.anchoredPosition = new Vector2(-6f, num3);
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static Button? _btn = null;

		private static TextMeshProUGUI? _btnText = null;

		internal static Container? CurrentContainer = null;

		private static readonly SortCategory[] _cycle = (SortCategory[])Enum.GetValues(typeof(SortCategory));

		private static GameObject? _pickerPanel = null;

		private static bool _pickerOpen = false;

		[HarmonyPostfix]
		public static void Postfix(InventoryGui __instance, Container? container)
		{
			if (AutoSortPlugin.ModEnabled.Value && AutoSortPlugin.EnableTagOverride.Value && !((Object)(object)container == (Object)null))
			{
				CurrentContainer = container;
				if ((Object)(object)_btn != (Object)null && (Object)(object)((Component)_btn).gameObject == (Object)null)
				{
					_btn = null;
					_btnText = null;
				}
				if ((Object)(object)_btn == (Object)null)
				{
					CreateButton(__instance);
				}
				if (!((Object)(object)_btn == (Object)null))
				{
					((Component)_btn).gameObject.SetActive(true);
					RefreshButtonText(container);
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(WaitAndPositionButton());
				}
			}
		}

		[IteratorStateMachine(typeof(<WaitAndPositionButton>d__5))]
		private static IEnumerator WaitAndPositionButton()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitAndPositionButton>d__5(0);
		}

		private static void CreateButton(InventoryGui gui)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			Button takeAllButton = GetTakeAllButton(gui);
			if ((Object)(object)takeAllButton == (Object)null)
			{
				AutoSortPlugin.Log.LogWarning((object)"[AutoSort] Could not find TakeAll button to clone. Category button unavailable — use 'autosort_tag' console command instead.");
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)takeAllButton).gameObject, ((Component)takeAllButton).transform.parent);
			((Object)val).name = "AutoSort_CategoryButton";
			_btn = val.GetComponent<Button>();
			_btnText = val.GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)_btn == (Object)null)
			{
				AutoSortPlugin.Log.LogWarning((object)"[AutoSort] Cloned button has no Button component.");
				Object.Destroy((Object)(object)val);
				return;
			}
			((UnityEventBase)_btn.onClick).RemoveAllListeners();
			ButtonClickedEvent onClick = _btn.onClick;
			object obj = <>c.<>9__6_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					CycleCategory(forward: true);
				};
				<>c.<>9__6_0 = val2;
				obj = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			EventTrigger obj2 = val.GetComponent<EventTrigger>() ?? val.AddComponent<EventTrigger>();
			obj2.triggers.Clear();
			Entry val3 = new Entry
			{
				eventID = (EventTriggerType)4
			};
			((UnityEvent<BaseEventData>)(object)val3.callback).AddListener((UnityAction<BaseEventData>)delegate(BaseEventData data)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Invalid comparison between Unknown and I4
				if ((int)((PointerEventData)data).button == 1)
				{
					CycleCategory(forward: false);
				}
			});
			obj2.triggers.Add(val3);
			if ((Object)(object)_btnText != (Object)null)
			{
				((TMP_Text)_btnText).text = "Auto";
			}
			val.SetActive(false);
		}

		private static void CycleCategory(bool forward)
		{
			if (!forward)
			{
				SetCategory(SortCategory.Unknown);
				ClosePickerPanel();
			}
			else if (_pickerOpen)
			{
				ClosePickerPanel();
			}
			else
			{
				OpenPickerPanel();
			}
		}

		private static void OpenPickerPanel()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Expected O, but got Unknown
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Expected O, but got Unknown
			//IL_0502: Unknown result type (might be due to invalid IL or missing references)
			//IL_0517: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_0555: Unknown result type (might be due to invalid IL or missing references)
			//IL_057a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Expected O, but got Unknown
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_btn == (Object)null)
			{
				return;
			}
			ClosePickerPanel();
			Transform parent = ((Component)_btn).transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			RectTransform component = ((Component)_btn).GetComponent<RectTransform>();
			float num = (((Object)(object)component != (Object)null) ? component.sizeDelta.x : 100f);
			float num2 = (((Object)(object)component != (Object)null) ? component.sizeDelta.y : 28f);
			List<SortCategory> list = new List<SortCategory> { SortCategory.Unknown };
			foreach (SortCategory value in Enum.GetValues(typeof(SortCategory)))
			{
				if (value != SortCategory.Unknown)
				{
					list.Add(value);
				}
			}
			foreach (string extra in ItemCategorizer.GetJsonExtraCategories())
			{
				if (!list.Exists((SortCategory c) => c.ToString().Equals(extra, StringComparison.OrdinalIgnoreCase)))
				{
					list.Add(SortCategory.Misc);
				}
			}
			float num3 = num2 + 2f;
			float num4 = num;
			float num5 = 5f * num3 + 4f;
			float num6 = (float)list.Count * num3 + 4f;
			GameObject val = new GameObject("AutoSort_Picker");
			val.transform.SetParent(parent, false);
			RectTransform obj = val.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(1f, 1f);
			obj.anchorMax = new Vector2(1f, 1f);
			obj.pivot = new Vector2(1f, 1f);
			obj.anchoredPosition = new Vector2(0f - (num4 + 6f), ((Object)(object)component != (Object)null) ? component.anchoredPosition.y : (-6f));
			obj.sizeDelta = new Vector2(num4, num5);
			((Graphic)val.AddComponent<Image>()).color = new Color(0.08f, 0.06f, 0.04f, 0.96f);
			GameObject val2 = new GameObject("AutoSort_Picker_Viewport");
			val2.transform.SetParent(val.transform, false);
			RectTransform val3 = val2.AddComponent<RectTransform>();
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = new Vector2(0f, 0f);
			val3.offsetMax = new Vector2(-14f, 0f);
			val2.AddComponent<RectMask2D>();
			GameObject val4 = new GameObject("AutoSort_Picker_Content");
			val4.transform.SetParent(val2.transform, false);
			RectTransform val5 = val4.AddComponent<RectTransform>();
			val5.anchorMin = new Vector2(0f, 1f);
			val5.anchorMax = new Vector2(1f, 1f);
			val5.pivot = new Vector2(0.5f, 1f);
			val5.anchoredPosition = Vector2.zero;
			val5.sizeDelta = new Vector2(0f, num6);
			for (int i = 0; i < list.Count; i++)
			{
				SortCategory sortCategory2 = list[i];
				string text = ((sortCategory2 == SortCategory.Unknown) ? "Auto (clear)" : sortCategory2.ToString());
				GameObject obj2 = Object.Instantiate<GameObject>(((Component)_btn).gameObject, val4.transform);
				((Object)obj2).name = $"AutoSort_Pick_{sortCategory2}";
				RectTransform component2 = obj2.GetComponent<RectTransform>();
				component2.anchorMin = new Vector2(0f, 1f);
				component2.anchorMax = new Vector2(1f, 1f);
				component2.pivot = new Vector2(0.5f, 1f);
				component2.sizeDelta = new Vector2(0f, num2);
				component2.anchoredPosition = new Vector2(0f, 0f - (2f + (float)i * num3));
				TextMeshProUGUI componentInChildren = obj2.GetComponentInChildren<TextMeshProUGUI>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					((TMP_Text)componentInChildren).text = text;
					((Graphic)componentInChildren).color = (Color)((sortCategory2 == SortCategory.Unknown) ? new Color(0.6f, 0.6f, 0.6f) : CategoryColour(sortCategory2));
				}
				Button component3 = obj2.GetComponent<Button>();
				if ((Object)(object)component3 != (Object)null)
				{
					((UnityEventBase)component3.onClick).RemoveAllListeners();
					SortCategory capturedCat = sortCategory2;
					((UnityEvent)component3.onClick).AddListener((UnityAction)delegate
					{
						SetCategory(capturedCat);
						ClosePickerPanel();
					});
				}
				obj2.SetActive(true);
			}
			ScrollRect obj3 = val.AddComponent<ScrollRect>();
			obj3.content = val5;
			obj3.viewport = val3;
			obj3.horizontal = false;
			obj3.vertical = true;
			obj3.scrollSensitivity = 20f;
			obj3.movementType = (MovementType)2;
			obj3.inertia = false;
			GameObject val6 = new GameObject("AutoSort_Picker_Scrollbar");
			val6.transform.SetParent(val.transform, false);
			RectTransform obj4 = val6.AddComponent<RectTransform>();
			obj4.anchorMin = new Vector2(1f, 0f);
			obj4.anchorMax = new Vector2(1f, 1f);
			obj4.pivot = new Vector2(1f, 0.5f);
			obj4.offsetMin = new Vector2(-12f, 2f);
			obj4.offsetMax = new Vector2(0f, -2f);
			((Graphic)val6.AddComponent<Image>()).color = new Color(0.15f, 0.12f, 0.08f, 1f);
			GameObject val7 = new GameObject("AutoSort_Picker_Scrollbar_Handle");
			val7.transform.SetParent(val6.transform, false);
			RectTransform val8 = val7.AddComponent<RectTransform>();
			val8.anchorMin = Vector2.zero;
			val8.anchorMax = Vector2.one;
			val8.sizeDelta = Vector2.zero;
			((Graphic)val7.AddComponent<Image>()).color = new Color(0.55f, 0.45f, 0.25f, 1f);
			Scrollbar val9 = val6.AddComponent<Scrollbar>();
			val9.handleRect = val8;
			val9.direction = (Direction)2;
			val9.value = 1f;
			obj3.verticalScrollbar = val9;
			obj3.verticalScrollbarVisibility = (ScrollbarVisibility)1;
			val.SetActive(true);
			_pickerPanel = val;
			_pickerOpen = true;
		}

		private static void ClosePickerPanel()
		{
			ForceClosePicker();
		}

		internal static void ForceClosePicker()
		{
			if ((Object)(object)_pickerPanel != (Object)null)
			{
				Object.Destroy((Object)(object)_pickerPanel);
				_pickerPanel = null;
			}
			_pickerOpen = false;
		}

		private static void SetCategory(SortCategory cat)
		{
			Container currentContainer = CurrentContainer;
			if ((Object)(object)currentContainer == (Object)null)
			{
				return;
			}
			ZNetView component = ((Component)currentContainer).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				if (cat == SortCategory.Unknown)
				{
					component.GetZDO().Set("tag", string.Empty);
				}
				else
				{
					component.GetZDO().Set("tag", $"[{cat}]");
				}
				RefreshButtonText(currentContainer);
				string text = ((cat == SortCategory.Unknown) ? "AutoSort: tag cleared — chest will be <color=#aaaaaa>inferred</color>" : $"AutoSort: chest pinned to <color=#a0c8ff>{cat}</color>");
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null);
				}
			}
		}

		private static SortCategory GetCurrentCategory(Container container)
		{
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return SortCategory.Unknown;
			}
			ItemCategorizer.TryParseChestTag(component.GetZDO().GetString("tag", string.Empty), out var category);
			return category;
		}

		private static void RefreshButtonText(Container container)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_btnText == (Object)null))
			{
				SortCategory currentCategory = GetCurrentCategory(container);
				if (currentCategory == SortCategory.Unknown)
				{
					((TMP_Text)_btnText).text = "Auto";
					((Graphic)_btnText).color = new Color(0.75f, 0.65f, 0.45f);
				}
				else
				{
					((TMP_Text)_btnText).text = currentCategory.ToString();
					((Graphic)_btnText).color = CategoryColour(currentCategory);
				}
			}
		}

		private static Color CategoryColour(SortCategory cat)
		{
			//IL_006e: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: U