Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimAutoSort v2.4.0
ValheimAutoSort.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
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