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 CatosInventorySorter v0.2.0
CatosInventorySorter.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Catosaur")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Sorts the local player's Valheim inventory using native inventory change callbacks.")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+494c17d12b074258215f2d254cb2e06f563f61b8")] [assembly: AssemblyProduct("CatosInventorySorter")] [assembly: AssemblyTitle("CatosInventorySorter")] [assembly: AssemblyVersion("0.2.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CatosInventorySorter { internal static class ConfigHotReload { private static ConfigFile _config; private static DateTime _loadedWriteTime; private static DateTime _candidateWriteTime; private static float _candidateSince; private static float _nextPoll; private static float _nextWarning; private static bool _pendingChange; internal static void Initialize(ConfigFile config) { _config = config; _loadedWriteTime = ReadWriteTime(); _candidateWriteTime = _loadedWriteTime; } internal static void Update() { if (_config == null || Time.unscaledTime < _nextPoll) { return; } _nextPoll = Time.unscaledTime + 0.4f; try { DateTime dateTime = ReadWriteTime(); if (dateTime == _loadedWriteTime) { _candidateWriteTime = dateTime; _candidateSince = 0f; _pendingChange = false; } else if (dateTime != _candidateWriteTime) { _candidateWriteTime = dateTime; _candidateSince = Time.unscaledTime; _pendingChange = true; } else if (_pendingChange && !(Time.unscaledTime - _candidateSince < 0.8f)) { _config.Reload(); _loadedWriteTime = ReadWriteTime(); _candidateWriteTime = _loadedWriteTime; _candidateSince = 0f; _pendingChange = false; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Configuration file changed; settings reloaded."); } } } catch (Exception ex) { if (Time.unscaledTime >= _nextWarning) { _nextWarning = Time.unscaledTime + 5f; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("Could not hot-reload configuration: " + ex.Message)); } } } } private static DateTime ReadWriteTime() { string configFilePath = _config.ConfigFilePath; if (!File.Exists(configFilePath)) { return DateTime.MinValue; } return File.GetLastWriteTimeUtc(configFilePath); } } [HarmonyPatch(typeof(InventoryGui), "Awake")] internal static class InventoryGuiPatches { private static void Postfix(InventoryGui __instance) { try { InventorySortButton.Attach(__instance); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Could not create inventory sort button: " + ex.Message)); } } } } internal static class InventorySortButton { [CompilerGenerated] private static class <>O { public static UnityAction <0>__SortPlayerInventory; } private static Button _button; private static TMP_Text _label; private static ConfigEntry<KeyboardShortcut> _sortShortcut; private static readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4]; internal static void Attach(InventoryGui gui) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)gui) || Object.op_Implicit((Object)(object)_button)) { return; } object? obj = AccessTools.Field(typeof(InventoryGui), "m_player")?.GetValue(gui); Transform val = (Transform)((obj is Transform) ? obj : null); object? obj2 = AccessTools.Field(typeof(InventoryGui), "m_inventoryRoot")?.GetValue(gui); Transform val2 = (Transform)((obj2 is Transform) ? obj2 : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2)) { GameObject val3 = new GameObject("CatosInventorySorterButton", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); val3.transform.SetParent(val2, false); _button = val3.GetComponent<Button>(); Image component = val3.GetComponent<Image>(); ((Graphic)component).color = new Color(0.16f, 0.23f, 0.17f, 0.98f); ((Selectable)_button).targetGraphic = (Graphic)(object)component; ((Selectable)_button).transition = (Transition)1; ColorBlock colors = ((Selectable)_button).colors; ((ColorBlock)(ref colors)).normalColor = new Color(0.82f, 0.92f, 0.82f, 1f); ((ColorBlock)(ref colors)).highlightedColor = Color.white; ((ColorBlock)(ref colors)).pressedColor = new Color(0.6f, 0.8f, 0.6f, 1f); ((ColorBlock)(ref colors)).selectedColor = Color.white; ((Selectable)_button).colors = colors; Button button = _button; Navigation navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)button).navigation = navigation; ButtonClickedEvent onClick = _button.onClick; object obj3 = <>O.<0>__SortPlayerInventory; if (obj3 == null) { UnityAction val4 = SortPlayerInventory; <>O.<0>__SortPlayerInventory = val4; obj3 = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj3); Transform transform = ((Component)_button).transform; RectTransform val5 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (Object.op_Implicit((Object)(object)val5)) { val5.anchorMin = new Vector2(0.5f, 0.5f); val5.anchorMax = new Vector2(0.5f, 0.5f); val5.pivot = new Vector2(0f, 1f); val5.sizeDelta = new Vector2(180f, 34f); ((Transform)val5).localScale = Vector3.one; } ((Component)_button).transform.SetAsLastSibling(); GameObject val6 = new GameObject("Label", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val6.transform.SetParent(((Component)_button).transform, false); Transform transform2 = val6.transform; Transform obj4 = ((transform2 is RectTransform) ? transform2 : null); ((RectTransform)obj4).anchorMin = Vector2.zero; ((RectTransform)obj4).anchorMax = Vector2.one; ((RectTransform)obj4).offsetMin = Vector2.zero; ((RectTransform)obj4).offsetMax = Vector2.zero; _label = (TMP_Text)(object)val6.GetComponent<TextMeshProUGUI>(); object? obj5 = AccessTools.Field(typeof(InventoryGui), "m_containerName")?.GetValue(gui); TMP_Text val7 = (TMP_Text)((obj5 is TMP_Text) ? obj5 : null); if (Object.op_Implicit((Object)(object)val7)) { _label.font = val7.font; _label.fontSharedMaterial = val7.fontSharedMaterial; _label.fontSize = val7.fontSize; } else { _label.font = TMP_Settings.defaultFontAsset; _label.fontSize = 16f; } _label.alignment = (TextAlignmentOptions)514; ((Graphic)_label).color = Color.white; _label.textWrappingMode = (TextWrappingModes)0; _label.overflowMode = (TextOverflowModes)1; _label.enableAutoSizing = true; _label.fontSizeMin = 11f; _label.fontSizeMax = 18f; _label.text = FormatLabel(InventorySorter.GetCriterion()); PositionBesideInventory(gui, val, (RectTransform)(object)((val2 is RectTransform) ? val2 : null), val5); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Inventory sort button attached beside the player inventory grid."); } } } internal static void Configure(ConfigFile config) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) _sortShortcut = config.Bind<KeyboardShortcut>("Controls", "SortShortcut", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Sort the local player's inventory while the inventory screen is open."); } internal static void Update() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } if (!Object.op_Implicit((Object)(object)_button)) { Attach(instance); } if (Object.op_Implicit((Object)(object)_button)) { object? obj = AccessTools.Field(typeof(InventoryGui), "m_player")?.GetValue(instance); Transform playerPanel = (Transform)((obj is Transform) ? obj : null); object? obj2 = AccessTools.Field(typeof(InventoryGui), "m_inventoryRoot")?.GetValue(instance); Transform val = (Transform)((obj2 is Transform) ? obj2 : null); Transform overlayRoot = ((val is RectTransform) ? val : null); Transform transform = ((Component)_button).transform; PositionBesideInventory(instance, playerPanel, (RectTransform)(object)overlayRoot, (RectTransform)(object)((transform is RectTransform) ? transform : null)); RefreshLabel(); } if (InventoryGui.IsVisible() && _sortShortcut != null) { KeyboardShortcut value = _sortShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { SortPlayerInventory(); } } } internal static void Destroy() { if (Object.op_Implicit((Object)(object)_button)) { Object.Destroy((Object)(object)((Component)_button).gameObject); } _button = null; _label = null; } private static void SortPlayerInventory() { try { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { SortCriterion criterion = InventorySorter.GetCriterion(); bool flag = ((criterion == SortCriterion.Weight) ? ModConfig.WeightDescending.Value : ModConfig.QuantityDescending.Value); bool flag2 = InventorySorter.Sort(((Humanoid)localPlayer).GetInventory(), localPlayer, criterion, flag); if (Object.op_Implicit((Object)(object)_label)) { _label.text = FormatLabel(criterion); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)(flag2 ? $"Sorted player inventory by {criterion} (descending={flag})." : "Player inventory already matches the selected sort order.")); } } } catch (Exception arg) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"Inventory sort failed safely: {arg}"); } } } private static void RefreshLabel() { if (Object.op_Implicit((Object)(object)_label)) { string text = FormatLabel(InventorySorter.GetCriterion()); if (_label.text != text) { _label.text = text; } } } private static string FormatLabel(SortCriterion criterion) { return "Sort: " + criterion; } private static void PositionBesideInventory(InventoryGui gui, Transform playerPanel, RectTransform overlayRoot, RectTransform buttonRect) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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_0173: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)gui) || !Object.op_Implicit((Object)(object)playerPanel) || !Object.op_Implicit((Object)(object)overlayRoot) || !Object.op_Implicit((Object)(object)buttonRect)) { return; } object? obj = AccessTools.Field(typeof(InventoryGui), "m_playerGrid")?.GetValue(gui); InventoryGrid val = (InventoryGrid)((obj is InventoryGrid) ? obj : null); RectTransform val2 = (RectTransform)((val != null) ? /*isinst with value type is only supported in some contexts*/: null); if (!Object.op_Implicit((Object)(object)val2)) { val2 = (RectTransform)(object)((playerPanel is RectTransform) ? playerPanel : null); } if (Object.op_Implicit((Object)(object)val2)) { val2.GetWorldCorners(_corners); Vector3 val3 = ((Transform)overlayRoot).InverseTransformPoint(_corners[2]); Rect rect = overlayRoot.rect; Rect rect2 = buttonRect.rect; float num; if (!(((Rect)(ref rect2)).width > 0f)) { num = 180f; } else { rect2 = buttonRect.rect; num = ((Rect)(ref rect2)).width; } float num2 = num; rect2 = buttonRect.rect; float num3; if (!(((Rect)(ref rect2)).height > 0f)) { num3 = 34f; } else { rect2 = buttonRect.rect; num3 = ((Rect)(ref rect2)).height; } float num4 = num3; float num5 = Mathf.Clamp(val3.x + 24f, ((Rect)(ref rect)).xMin + 8f, ((Rect)(ref rect)).xMax - num2 - 8f); float num6 = Mathf.Clamp(val3.y + 24f, ((Rect)(ref rect)).yMin + num4 + 8f, ((Rect)(ref rect)).yMax - 8f); ((Transform)buttonRect).localPosition = new Vector3(num5, num6, 0f); } } } internal enum SortCriterion { Weight, Quantity } internal enum SpecialItemsMode { Ignore, SortFirst } internal enum SpecialItemCategory { Other, Armor, Food, Arrows } internal static class InventorySorter { private sealed class Slot { internal int X; internal int Y; internal Slot(int x, int y) { X = x; Y = y; } } private static readonly MethodInfo ChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); internal static bool Sort(Inventory inventory, Player player, SortCriterion criterion, bool descending) { //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) if (inventory == null || (Object)(object)player == (Object)null || ChangedMethod == null) { return false; } int width = inventory.GetWidth(); int height = inventory.GetHeight(); if (width <= 0 || height <= 1) { return false; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null || allItems.Count < 2) { return false; } HashSet<ItemData> hashSet = new HashSet<ItemData>(); List<ItemData> list = new List<ItemData>(); inventory.GetBoundItems(list); foreach (ItemData item2 in list) { if (item2 != null) { hashSet.Add(item2); } } List<ItemData> list2 = new List<ItemData>(); HashSet<long> hashSet2 = new HashSet<long>(); HashSet<long> hashSet3 = new HashSet<long>(); SpecialItemsMode specialItemsMode = GetSpecialItemsMode(); foreach (ItemData item3 in allItems) { if (item3 == null || item3.m_shared == null) { return false; } int x = item3.m_gridPos.x; int y = item3.m_gridPos.y; if (x < 0 || y < 0 || x >= width || y >= height) { return false; } long item = PositionKey(x, y); if (!hashSet3.Add(item)) { return false; } if (y == 0 || hashSet.Contains(item3) || ((Humanoid)player).IsItemEquiped(item3) || (specialItemsMode == SpecialItemsMode.Ignore && IsSpecialItem(item3))) { hashSet2.Add(item); } else { list2.Add(item3); } } list2.Sort((ItemData a, ItemData b) => Compare(a, b, criterion, descending, specialItemsMode)); List<Slot> list3 = new List<Slot>(); for (int num = 1; num < height; num++) { for (int num2 = 0; num2 < width; num2++) { if (!hashSet2.Contains(PositionKey(num2, num))) { list3.Add(new Slot(num2, num)); } } } if (list3.Count < list2.Count) { return false; } bool flag = false; for (int num3 = 0; num3 < list2.Count; num3++) { ItemData val = list2[num3]; Slot slot = list3[num3]; if (val.m_gridPos.x != slot.X || val.m_gridPos.y != slot.Y) { val.m_gridPos = new Vector2i(slot.X, slot.Y); flag = true; } } if (flag) { try { ChangedMethod.Invoke(inventory, new object[2] { true, false }); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"Valheim inventory change notification failed: {arg}"); } return false; } } return flag; } private static int Compare(ItemData left, ItemData right, SortCriterion criterion, bool descending, SpecialItemsMode specialItemsMode) { if (specialItemsMode == SpecialItemsMode.SortFirst) { int num = GetSpecialItemRank(left).CompareTo(GetSpecialItemRank(right)); if (num != 0) { return num; } } int num2 = ((criterion != SortCriterion.Weight) ? left.m_stack.CompareTo(right.m_stack) : TotalWeight(left).CompareTo(TotalWeight(right))); if (descending) { num2 = -num2; } if (num2 != 0) { return num2; } if (left.m_gridPos.y == right.m_gridPos.y) { return left.m_gridPos.x.CompareTo(right.m_gridPos.x); } return left.m_gridPos.y.CompareTo(right.m_gridPos.y); } private static float TotalWeight(ItemData item) { return item.m_shared.m_weight * (float)item.m_stack; } private static long PositionKey(int x, int y) { return ((long)y << 32) | (uint)x; } private static bool IsSpecialItem(ItemData item) { return GetSpecialItemCategory(item) != SpecialItemCategory.Other; } private static SpecialItemCategory GetSpecialItemCategory(ItemData item) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected I4, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 if (item == null || item.m_shared == null) { return SpecialItemCategory.Other; } ItemType itemType = item.m_shared.m_itemType; switch (itemType - 6) { default: if ((int)itemType != 17) { break; } goto case 0; case 3: return SpecialItemCategory.Arrows; case 0: case 1: case 5: case 6: return SpecialItemCategory.Armor; case 2: case 4: break; } if (!(item.m_shared.m_food > 0f)) { return SpecialItemCategory.Other; } return SpecialItemCategory.Food; } private static int GetSpecialItemRank(ItemData item) { SpecialItemCategory specialItemCategory = GetSpecialItemCategory(item); string[] array = ((ModConfig.SpecialItemsOrder != null) ? ModConfig.SpecialItemsOrder.Value : "Armor,Food,Arrows").Split(new char[1] { ',' }); int num = 0; string[] array2 = array; for (int i = 0; i < array2.Length; i++) { if (Enum.TryParse<SpecialItemCategory>(array2[i].Trim(), ignoreCase: true, out var result) && result != SpecialItemCategory.Other) { if (result == specialItemCategory) { return num; } num++; } } if (specialItemCategory != SpecialItemCategory.Other) { return num; } return int.MaxValue; } private static SpecialItemsMode GetSpecialItemsMode() { if (ModConfig.SpecialItemsMode == null || !Enum.TryParse<SpecialItemsMode>(ModConfig.SpecialItemsMode.Value, ignoreCase: true, out var result)) { return SpecialItemsMode.Ignore; } return result; } internal static SortCriterion GetCriterion() { if (!Enum.TryParse<SortCriterion>(ModConfig.SortMode.Value, ignoreCase: true, out var result)) { return SortCriterion.Weight; } return result; } } internal static class ModConfig { internal static ConfigEntry<string> SortMode; internal static ConfigEntry<bool> WeightDescending; internal static ConfigEntry<bool> QuantityDescending; internal static ConfigEntry<string> SpecialItemsMode; internal static ConfigEntry<string> SpecialItemsOrder; internal static void Bind(ConfigFile config) { SortMode = config.Bind<string>("Sorting", "SortMode", "Weight", "Sort criterion: Weight or Quantity. Changes are picked up while the game is running."); WeightDescending = config.Bind<bool>("Sorting", "WeightDescending", true, "Sort heaviest total stacks first by default. Set false for lightest first. Changes are picked up while the game is running."); QuantityDescending = config.Bind<bool>("Sorting", "QuantityDescending", true, "Sort highest stack quantities first by default. Set false for lowest first. Changes are picked up while the game is running."); SpecialItemsMode = config.Bind<string>("Sorting", "SpecialItemsMode", "SortFirst", "How to handle arrows, armor, and food: SortFirst sorts them before other items; Ignore keeps them in place. Changes are picked up while the game is running."); SpecialItemsOrder = config.Bind<string>("Sorting", "SpecialItemsOrder", "Armor,Food,Arrows", "Order for special items when SpecialItemsMode is SortFirst. Use a comma-separated list containing Armor, Food, and Arrows. Changes are picked up while the game is running."); InventorySortButton.Configure(config); } } [BepInPlugin("com.catosaur.catosinventorysorter", "Catos Inventory Sorter", "0.1.0")] [BepInProcess("valheim.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.catosaur.catosinventorysorter"; public const string Name = "Catos Inventory Sorter"; public const string Version = "0.1.0"; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); ConfigHotReload.Initialize(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.catosaur.catosinventorysorter"); _harmony.PatchAll(typeof(InventoryGuiPatches)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Catos Inventory Sorter 0.1.0 client-only loaded."); } private void OnDestroy() { InventorySortButton.Destroy(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchAll("com.catosaur.catosinventorysorter"); } } private void Update() { ConfigHotReload.Update(); InventorySortButton.Update(); } } }