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 SonicChestFilters v1.0.1
SonicChestFilters.dll
Decompiled 5 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SonicChestFilters")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+daeb12fe14336c3cde1064af94634546a47507bc")] [assembly: AssemblyProduct("SonicChestFilters")] [assembly: AssemblyTitle("SonicChestFilters")] [assembly: AssemblyVersion("1.0.1.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 SonicChestFilters { internal static class ChestFilter { internal static string Query { get; private set; } = string.Empty; internal static bool HasQuery => !string.IsNullOrWhiteSpace(Query); internal static void SetQuery(string query) { Query = query ?? string.Empty; } internal static void Clear() { Query = string.Empty; } internal static bool ItemIsVisible(ItemData item) { if (!HasQuery) { return true; } if (item?.m_shared == null) { return true; } string matchedLabel; return ItemMatch.ItemMatchesPattern(item, Query.Trim(), out matchedLabel); } internal static void ApplyToGrid(InventoryGrid grid, Inventory inventory) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)grid == (Object)null || inventory == null || !(AccessTools.Field(typeof(InventoryGrid), "m_elements")?.GetValue(grid) is List<InventoryElement> list)) { return; } for (int i = 0; i < list.Count; i++) { InventoryElement val = list[i]; if (!((Object)val == (Object)null)) { if (!HasQuery || !val.m_used) { RestoreClickable(val); } else if (ItemIsVisible(inventory.GetItemAt(val.Position.x, val.Position.y))) { RestoreClickable(val); } else { HideOccupied(val); } } } } private static void RestoreClickable(InventoryElement element) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown if ((Object)element.m_button != (Object)null) { ((Selectable)element.m_button).interactable = true; } } private static void HideOccupied(InventoryElement element) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown SetGraphicEnabled((Graphic)(object)element.m_icon, enabled: false); SetGraphicEnabled((Graphic)(object)element.m_amount, enabled: false); SetGraphicEnabled((Graphic)(object)element.m_quality, enabled: false); SetGraphicEnabled((Graphic)(object)element.m_equiped, enabled: false); SetGraphicEnabled((Graphic)(object)element.m_queued, enabled: false); SetGraphicEnabled((Graphic)(object)element.m_noteleport, enabled: false); SetGraphicEnabled((Graphic)(object)element.m_food, enabled: false); if ((Object)element.m_durability != (Object)null) { ((Component)element.m_durability).gameObject.SetActive(false); } if ((Object)element.m_tooltip != (Object)null) { ((Behaviour)element.m_tooltip).enabled = false; } if ((Object)element.m_button != (Object)null) { ((Selectable)element.m_button).interactable = false; } element.m_canBeDroppedOn = false; } private static void SetGraphicEnabled(Graphic graphic, bool enabled) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)graphic != (Object)null) { ((Behaviour)graphic).enabled = enabled; } } } internal static class ChestPanelUi { [CompilerGenerated] private static class <>O { public static UnityAction<string> <0>__OnFilterChanged; public static UnityAction <1>__OnClearClicked; public static UnityAction <2>__OnSortClicked; } private const string FilterRootName = "SonicChestFilters_Root"; private const float ToolbarHeight = 44f; private static GameObject _root; private static Button _clearButton; private static InputField _filterInput; private static string _lastFilterText = string.Empty; private static Container _boundContainer; private static bool _expanded; private static bool _inputBlocked; private static bool FilterFieldFocused { get { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if ((Object)_filterInput != (Object)null) { return _filterInput.isFocused; } return false; } } internal static void EnsureControls(InventoryGui gui) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_005c: 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: Expected O, but got Unknown //IL_006c: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if ((Object)gui == (Object)null || (Object)gui.m_container == (Object)null) { return; } if (SonicChestFiltersPlugin.Enabled == null || !SonicChestFiltersPlugin.Enabled.Value) { DestroyControls(gui); return; } Container val = GameAccess.Get<Container>(gui, "m_currentContainer"); if ((Object)val == (Object)null) { return; } if ((Object)_boundContainer != (Object)val) { RestoreFrame(gui); DestroyWidgets(); } if (GUIManager.Instance != null) { if ((Object)_root == (Object)null) { CreateToolbar(gui); _boundContainer = val; } ApplyFrameLayout(gui); RefreshClearButton(); } } internal static void Tick() { SyncInputBlock(FilterFieldFocused); SyncFilterField(); } internal static void ResetFilterText() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown _lastFilterText = string.Empty; ChestFilter.Clear(); if ((Object)_filterInput != (Object)null) { _filterInput.SetTextWithoutNotify(string.Empty); } RefreshClearButton(); RefreshContainerGrid(); } internal static void DestroyControls() { DestroyControls(InventoryGui.instance); } internal static void DestroyControls(InventoryGui gui) { RestoreFrame(gui); DestroyWidgets(); _boundContainer = null; } private static void CreateToolbar(InventoryGui gui) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0050: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_01c4: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0280: 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_02a3: Expected O, but got Unknown //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Expected O, but got Unknown RectTransform container = gui.m_container; _root = new GameObject("SonicChestFilters_Root", new Type[1] { typeof(RectTransform) }); _root.transform.SetParent((Transform)(object)container, false); RectTransform component = _root.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.sizeDelta = new Vector2(0f, 44f); float num = 101f; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 0.5f); if (SonicChestFiltersPlugin.EnableFilterBox == null || SonicChestFiltersPlugin.EnableFilterBox.Value) { GameObject val2 = GUIManager.Instance.CreateInputField((Transform)(object)component, val, val, new Vector2(num, 0f), (ContentType)0, ModLocalization.Translate("$sonic_chestfilters_filter", "Filter..."), 16, 170f, 28f); if ((Object)val2 != (Object)null) { ((Object)val2).name = "SonicChestFilters_FilterField"; _filterInput = val2.GetComponent<InputField>(); if ((Object)_filterInput != (Object)null) { _filterInput.characterLimit = 64; _filterInput.SetTextWithoutNotify(string.Empty); ((UnityEvent<string>)(object)_filterInput.onValueChanged).AddListener((UnityAction<string>)OnFilterChanged); ((UnityEvent<string>)(object)_filterInput.onEndEdit).AddListener((UnityAction<string>)OnFilterChanged); } num += 133f; } GameObject val3 = GUIManager.Instance.CreateButton(ModLocalization.Translate("$sonic_chestfilters_clear", "Clear"), (Transform)(object)component, val, val, new Vector2(num, 0f), 80f, 28f); if ((Object)val3 != (Object)null) { ((Object)val3).name = "SonicChestFilters_Clear"; _clearButton = val3.GetComponent<Button>(); if ((Object)_clearButton != (Object)null) { ButtonClickedEvent onClick = _clearButton.onClick; object obj = <>O.<1>__OnClearClicked; if (obj == null) { UnityAction val4 = OnClearClicked; <>O.<1>__OnClearClicked = val4; obj = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } num += 88f; } } if (SonicChestFiltersPlugin.EnableSortButton == null || SonicChestFiltersPlugin.EnableSortButton.Value) { GameObject val5 = GUIManager.Instance.CreateButton(ModLocalization.Translate("$sonic_chestfilters_sort", "Sort"), (Transform)(object)component, val, val, new Vector2(num, 0f), 80f, 28f); if ((Object)val5 != (Object)null) { ((Object)val5).name = "SonicChestFilters_Sort"; Button component2 = val5.GetComponent<Button>(); if ((Object)component2 != (Object)null) { ButtonClickedEvent onClick2 = component2.onClick; object obj2 = <>O.<2>__OnSortClicked; if (obj2 == null) { UnityAction val6 = OnSortClicked; <>O.<2>__OnSortClicked = val6; obj2 = (object)val6; } ((UnityEvent)onClick2).AddListener((UnityAction)obj2); } } } _lastFilterText = string.Empty; ChestFilter.Clear(); ChestSort.ResetSession(); } private static void ApplyFrameLayout(InventoryGui gui) { if (!_expanded) { GrowDown(gui.m_container, 44f); GrowDown(FindBackground(gui.m_container), 44f); ShiftDown(GetGridShiftTarget(gui), 44f); _expanded = true; } PositionToolbar(gui); } private static void RestoreFrame(InventoryGui gui) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (!_expanded || (Object)gui == (Object)null || (Object)gui.m_container == (Object)null) { _expanded = false; return; } GrowDown(gui.m_container, -44f); GrowDown(FindBackground(gui.m_container), -44f); ShiftDown(GetGridShiftTarget(gui), -44f); _expanded = false; } private static void PositionToolbar(InventoryGui gui) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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) if (!((Object)_root == (Object)null)) { RectTransform container = gui.m_container; RectTransform component = _root.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.offsetMin = new Vector2(10f, component.offsetMin.y); component.offsetMax = new Vector2(-10f, component.offsetMax.y); float headerBottomLocalY = GetHeaderBottomLocalY(gui, container); Vector2 anchoredPosition = component.anchoredPosition; anchoredPosition.y = LocalYToTopOffset(container, headerBottomLocalY) - 2f; component.anchoredPosition = anchoredPosition; Vector2 sizeDelta = component.sizeDelta; sizeDelta.y = 44f; component.sizeDelta = sizeDelta; } } private static float LocalYToTopOffset(RectTransform container, float localY) { //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_0010: Unknown result type (might be due to invalid IL or missing references) Rect rect = container.rect; float height = ((Rect)(ref rect)).height; float y = container.pivot.y; float num = (1f - y) * height; return localY - num; } private static float GetHeaderBottomLocalY(InventoryGui gui, RectTransform container) { //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) //IL_004d: Unknown result type (might be due to invalid IL or missing references) float lowest = float.PositiveInfinity; ConsiderHeader((Component)(object)gui.m_stackAllButton, container, ref lowest); ConsiderHeader((Component)(object)gui.m_takeAllButton, container, ref lowest); ConsiderHeader((Component)(object)gui.m_containerName, container, ref lowest); if (float.IsPositiveInfinity(lowest)) { Rect rect = container.rect; float height = ((Rect)(ref rect)).height; return (1f - container.pivot.y) * height - 36f; } return lowest; } private static void ConsiderHeader(Component component, RectTransform container, ref float lowest) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)component == (Object)null) { return; } RectTransform component2 = component.GetComponent<RectTransform>(); if (!((Object)component2 == (Object)null) && ((Component)component2).gameObject.activeInHierarchy) { Vector3[] array = (Vector3[])(object)new Vector3[4]; component2.GetWorldCorners(array); Vector3 val = ((Transform)container).InverseTransformPoint(array[0]); if (val.y < lowest) { lowest = val.y; } } } private static RectTransform GetGridShiftTarget(InventoryGui gui) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0032: 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) //IL_0047: Expected O, but got Unknown //IL_0047: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0079: Expected O, but got Unknown InventoryGrid val = GameAccess.Get<InventoryGrid>(gui, "m_containerGrid"); if ((Object)val == (Object)null) { return null; } RectTransform component = ((Component)val).GetComponent<RectTransform>(); if ((Object)component != (Object)null && (Object)component != (Object)gui.m_container) { return component; } if ((Object)val.m_gridRoot != (Object)null && (Object)val.m_gridRoot != (Object)gui.m_container) { return val.m_gridRoot; } return null; } private static RectTransform FindBackground(RectTransform container) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0052: Expected O, but got Unknown if ((Object)container == (Object)null) { return null; } Transform val = ((Transform)container).Find("Bkg"); if ((Object)val == (Object)null) { return null; } RectTransform val2 = (RectTransform)(object)((val is RectTransform) ? val : null); if ((Object)val2 == (Object)null || (Object)val2 == (Object)container) { return null; } return val2; } private static void GrowDown(RectTransform rt, float extra) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0010: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0040: Unknown result type (might be due to invalid IL or missing references) if (!((Object)rt == (Object)null)) { if (!Mathf.Approximately(rt.anchorMin.y, rt.anchorMax.y)) { Vector2 offsetMin = rt.offsetMin; offsetMin.y -= extra; rt.offsetMin = offsetMin; } else { Rect rect = rt.rect; float height = ((Rect)(ref rect)).height; rt.SetSizeWithCurrentAnchors((Axis)1, height + extra); rt.anchoredPosition += new Vector2(0f, (0f - extra) * (1f - rt.pivot.y)); } } } private static void ShiftDown(RectTransform rt, float extra) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!((Object)rt == (Object)null)) { rt.anchoredPosition += new Vector2(0f, 0f - extra); } } private static void DestroyWidgets() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown SyncInputBlock(shouldBlock: false); _filterInput = null; _clearButton = null; _lastFilterText = string.Empty; if ((Object)_root != (Object)null) { Object.Destroy((Object)(object)_root); _root = null; } } private static void SyncInputBlock(bool shouldBlock) { if (_inputBlocked != shouldBlock) { GUIManager.BlockInput(shouldBlock); _inputBlocked = shouldBlock; } } private static void SyncFilterField() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if (!((Object)_filterInput == (Object)null)) { string text = _filterInput.text ?? string.Empty; if (!(text == _lastFilterText)) { OnFilterChanged(text); } } } private static void OnFilterChanged(string text) { string text2 = text ?? string.Empty; if (!(text2 == _lastFilterText)) { _lastFilterText = text2; ChestFilter.SetQuery(text2); RefreshClearButton(); RefreshContainerGrid(); } } private static void OnClearClicked() { ResetFilterText(); } private static void OnSortClicked() { ChestSort.SortCurrent(InventoryGui.instance); RefreshContainerGrid(); } private static void RefreshClearButton() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if ((Object)_clearButton != (Object)null) { ((Selectable)_clearButton).interactable = ChestFilter.HasQuery; } } private static void RefreshContainerGrid() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown InventoryGui instance = InventoryGui.instance; InventoryGrid val = GameAccess.Get<InventoryGrid>(instance, "m_containerGrid"); if ((Object)instance == (Object)null || (Object)val == (Object)null) { return; } Container val2 = GameAccess.Get<Container>(instance, "m_currentContainer"); if (!((Object)val2 == (Object)null)) { Inventory inventory = val2.GetInventory(); if (inventory != null) { ItemData val3 = GameAccess.Get<ItemData>(instance, "m_dragItem"); val.UpdateInventory(inventory, Player.m_localPlayer, val3); } } } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] internal static class InventoryGui_UpdateContainer_Patch { private static void Postfix(InventoryGui __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (!((Object)__instance == (Object)null) && !((Object)GameAccess.Get<Container>(__instance, "m_currentContainer") == (Object)null)) { ChestPanelUi.EnsureControls(__instance); } } } [HarmonyPatch(typeof(InventoryGui), "CloseContainer")] internal static class InventoryGui_CloseContainer_Patch { private static void Postfix(InventoryGui __instance) { ChestFilter.Clear(); ChestSort.ResetSession(); ChestPanelUi.DestroyControls(__instance); } } [HarmonyPatch(typeof(InventoryGrid), "UpdateInventory")] internal static class InventoryGrid_UpdateInventory_Patch { private static void Postfix(InventoryGrid __instance, Inventory inventory) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_002f: Expected O, but got Unknown InventoryGui instance = InventoryGui.instance; InventoryGrid val = GameAccess.Get<InventoryGrid>(instance, "m_containerGrid"); if (!((Object)instance == (Object)null) && !((Object)__instance != (Object)val)) { ChestFilter.ApplyToGrid(__instance, inventory); } } } internal static class ChestSort { private static bool _reverse; internal static void ResetSession() { _reverse = false; } internal static void SortCurrent(InventoryGui gui) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_00b7: 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) if ((Object)gui == (Object)null) { return; } if (IsDragging(gui)) { Say("Cannot sort while dragging an item."); return; } Container val = GameAccess.Get<Container>(gui, "m_currentContainer"); if ((Object)val == (Object)null) { return; } if (!val.IsOwner()) { Say("Cannot sort: not the chest owner."); return; } Inventory inventory = val.GetInventory(); if (inventory != null) { MergeStacks(inventory); List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); list.Sort(CompareItems); if (_reverse) { list.Reverse(); } int width = inventory.GetWidth(); for (int i = 0; i < list.Count; i++) { list[i].m_gridPos = new Vector2i(i % width, i / width); } GameAccess.Call(inventory, "Changed", true, false); _reverse = !_reverse; if (SonicChestFiltersPlugin.DebugEnabled) { SonicChestFiltersPlugin.Debug($"Sorted {list.Count} item stacks (reverse={_reverse})."); } } } private static int CompareItems(ItemData a, ItemData b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected I4, but got Unknown //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected I4, but got Unknown int num = ((int)a.m_shared.m_itemType).CompareTo((int)b.m_shared.m_itemType); if (num != 0) { return num; } string strA = ItemMatch.GetLocalizedName(a.m_shared.m_name) ?? string.Empty; string strB = ItemMatch.GetLocalizedName(b.m_shared.m_name) ?? string.Empty; int num2 = string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase); if (num2 != 0) { return num2; } int num3 = b.m_quality.CompareTo(a.m_quality); if (num3 != 0) { return num3; } return string.Compare(a.m_shared.m_name, b.m_shared.m_name, StringComparison.OrdinalIgnoreCase); } private static void MergeStacks(Inventory inventory) { bool flag; do { flag = false; List<ItemData> allItems = inventory.GetAllItems(); for (int i = 0; i < allItems.Count; i++) { if (flag) { break; } ItemData val = allItems[i]; int maxStackSize = val.m_shared.m_maxStackSize; if (maxStackSize <= 1 || val.m_stack >= maxStackSize) { continue; } for (int j = i + 1; j < allItems.Count; j++) { ItemData val2 = allItems[j]; if (!CanStackTogether(val, val2)) { continue; } int num = maxStackSize - val.m_stack; if (num > 0) { int num2 = Mathf.Min(num, val2.m_stack); val.m_stack += num2; val2.m_stack -= num2; if (val2.m_stack <= 0) { inventory.RemoveItem(val2); } flag = true; } break; } } } while (flag); } private static bool CanStackTogether(ItemData source, ItemData target) { if (source == null || target == null || source.m_shared == null || target.m_shared == null) { return false; } if (source.m_shared.m_name != target.m_shared.m_name || source.m_quality != target.m_quality || source.m_variant != target.m_variant || source.m_worldLevel != target.m_worldLevel) { return false; } if (source.m_customData.Count != target.m_customData.Count) { return false; } foreach (KeyValuePair<string, string> customDatum in source.m_customData) { if (!target.m_customData.TryGetValue(customDatum.Key, out var value) || value != customDatum.Value) { return false; } } return true; } private static bool IsDragging(InventoryGui gui) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown object obj = AccessToolsField(gui, "m_dragGo"); Object val = (Object)((obj is Object) ? obj : null); if (val != null && val != (Object)null) { return true; } return AccessToolsField(gui, "m_dragItem") != null; } private static object AccessToolsField(object instance, string name) { return AccessTools.Field(instance.GetType(), name)?.GetValue(instance); } private static void Say(string message) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown Player localPlayer = Player.m_localPlayer; if ((Object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } else if ((Object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString(message); } } } internal static class GameAccess { internal static T Get<T>(object instance, string fieldName) where T : class { if (instance == null) { return null; } return AccessTools.Field(instance.GetType(), fieldName)?.GetValue(instance) as T; } internal static object Get(object instance, string fieldName) { if (instance == null) { return null; } return AccessTools.Field(instance.GetType(), fieldName)?.GetValue(instance); } internal static void Call(object instance, string methodName, params object[] args) { if (instance != null) { MethodInfo methodInfo = AccessTools.Method(instance.GetType(), methodName, (Type[])null, (Type[])null); if (!(methodInfo == null)) { methodInfo.Invoke(instance, BindArguments(methodInfo, args)); } } } private static object[] BindArguments(MethodInfo method, object[] args) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0) { return null; } object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { if (args != null && i < args.Length) { array[i] = args[i]; continue; } if (parameters[i].HasDefaultValue) { array[i] = parameters[i].DefaultValue; continue; } Type parameterType = parameters[i].ParameterType; array[i] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null); } return array; } } internal static class ItemLocate { private sealed class HighlightedChest { private readonly List<RendererGlow> _renderers = new List<RendererGlow>(); internal static HighlightedChest TryCreate(Container container) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Renderer[] componentsInChildren = ((Component)container).GetComponentsInChildren<Renderer>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } HighlightedChest highlightedChest = new HighlightedChest(); foreach (Renderer val in componentsInChildren) { if (!((Object)val == (Object)null) && !(val is ParticleSystemRenderer)) { RendererGlow rendererGlow = RendererGlow.TryCreate(val); if (rendererGlow != null) { highlightedChest._renderers.Add(rendererGlow); } } } if (highlightedChest._renderers.Count == 0) { return null; } return highlightedChest; } internal void ApplyGlow(Color color) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _renderers.Count; i++) { _renderers[i].Apply(color); } } internal void Restore() { for (int i = 0; i < _renderers.Count; i++) { _renderers[i].Restore(); } _renderers.Clear(); } } private sealed class RendererGlow { private readonly Renderer _renderer; private readonly bool _usedMaterialInstances; private readonly Material[] _originalSharedMaterials; private readonly Material[] _instancedMaterials; private readonly Color[] _originalEmission; private readonly bool[] _hadEmissionKeyword; private RendererGlow(Renderer renderer, bool usedMaterialInstances, Material[] originalSharedMaterials, Material[] instancedMaterials, Color[] originalEmission, bool[] hadEmissionKeyword) { _renderer = renderer; _usedMaterialInstances = usedMaterialInstances; _originalSharedMaterials = originalSharedMaterials; _instancedMaterials = instancedMaterials; _originalEmission = originalEmission; _hadEmissionKeyword = hadEmissionKeyword; } internal static RendererGlow TryCreate(Renderer renderer) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0142: Expected O, but got Unknown Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return null; } renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor("_EmissionColor", Color.black); renderer.SetPropertyBlock(PropertyBlock); if (SupportsEmissionViaPropertyBlock(renderer)) { return new RendererGlow(renderer, usedMaterialInstances: false, null, null, null, null); } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length]; Color[] array3 = (Color[])(object)new Color[sharedMaterials.Length]; bool[] array4 = new bool[sharedMaterials.Length]; bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = (array[i] = sharedMaterials[i]); if ((Object)val == (Object)null) { array2[i] = val; continue; } Material val2 = (array2[i] = new Material(val)); array4[i] = val2.IsKeywordEnabled("_EMISSION"); if (val2.HasProperty("_EmissionColor")) { array3[i] = val2.GetColor("_EmissionColor"); val2.EnableKeyword("_EMISSION"); flag = true; } else { array3[i] = Color.black; } } if (!flag) { for (int j = 0; j < array2.Length; j++) { if ((Object)array2[j] != (Object)null && (Object)array2[j] != (Object)array[j]) { Object.Destroy((Object)(object)array2[j]); } } return null; } renderer.materials = array2; return new RendererGlow(renderer, usedMaterialInstances: true, array, array2, array3, array4); } private static bool SupportsEmissionViaPropertyBlock(Renderer renderer) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Material[] sharedMaterials = renderer.sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)val != (Object)null && val.HasProperty("_EmissionColor")) { return true; } } return false; } internal void Apply(Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) if ((Object)_renderer == (Object)null) { return; } if (!_usedMaterialInstances) { _renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor("_EmissionColor", color); _renderer.SetPropertyBlock(PropertyBlock); } else { if (_instancedMaterials == null) { return; } for (int i = 0; i < _instancedMaterials.Length; i++) { Material val = _instancedMaterials[i]; if ((Object)val != (Object)null && val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", color); } } } } internal void Restore() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) if ((Object)_renderer == (Object)null) { return; } if (!_usedMaterialInstances) { _renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor("_EmissionColor", Color.black); _renderer.SetPropertyBlock(PropertyBlock); return; } if (_originalSharedMaterials != null) { _renderer.sharedMaterials = _originalSharedMaterials; } if (_instancedMaterials == null) { return; } for (int i = 0; i < _instancedMaterials.Length; i++) { Material val = _instancedMaterials[i]; if (!((Object)val == (Object)null)) { if (_originalEmission != null && val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", _originalEmission[i]); } if (_hadEmissionKeyword != null && !_hadEmissionKeyword[i]) { val.DisableKeyword("_EMISSION"); } Object.Destroy((Object)(object)val); } } } } private const string EmissionColorProperty = "_EmissionColor"; private static readonly List<HighlightedChest> Active = new List<HighlightedChest>(); private static readonly MaterialPropertyBlock PropertyBlock = new MaterialPropertyBlock(); private static bool _commandRegistered; private static float _activeUntil = -1f; private static Color _baseGlow = new Color(1f, 0.85f, 0.2f, 1f); internal static bool IsActive => SonicChestFiltersPlugin.LocateIsActive; internal static void RegisterCommand() { if (!_commandRegistered && IsActive && CommandManager.Instance != null) { _commandRegistered = true; CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new LocateCommand()); } } internal static List<string> CommandOptions() { return new List<string> { "clear" }; } internal static void ClearHighlights() { for (int i = 0; i < Active.Count; i++) { Active[i].Restore(); } Active.Clear(); _activeUntil = -1f; } internal static void Tick() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!IsActive || Active.Count == 0) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup >= _activeUntil) { ClearHighlights(); return; } float num = 0.45f + 0.55f * (0.5f + 0.5f * Mathf.Sin(realtimeSinceStartup * 5f)); Color color = _baseGlow * num; color.a = 1f; for (int i = 0; i < Active.Count; i++) { Active[i].ApplyGlow(color); } } internal static void OnCommand(string[] args, Terminal context) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown if (!IsActive) { Say("Item locate is disabled.", context); return; } if (args != null && args.Length >= 1 && string.Equals(args[0], "clear", StringComparison.OrdinalIgnoreCase)) { ClearHighlights(); Say("Cleared nearby chest highlights.", context); return; } Player localPlayer = Player.m_localPlayer; if ((Object)localPlayer == (Object)null) { Say("No local player.", context); return; } string pattern; string displayName; if (args == null || args.Length == 0) { if (!TryGetHeldItemPattern(localPlayer, out pattern, out displayName)) { Say("Hold an item or use: locate <item name>", context); return; } } else { pattern = string.Join(" ", args).Trim(); if (pattern.Length == 0) { Say("Usage: locate [item|*pattern*|clear]", context); return; } displayName = pattern; } SearchAndHighlight(localPlayer, pattern, displayName, context); } private static bool TryGetHeldItemPattern(Player player, out string pattern, out string displayName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown pattern = string.Empty; displayName = string.Empty; Humanoid val = (Humanoid)player; ItemData val2 = val.RightItem ?? val.LeftItem; if (val2?.m_shared == null) { return false; } string text = null; if ((Object)val2.m_dropPrefab != (Object)null) { text = ((Object)val2.m_dropPrefab).name; } if (!string.IsNullOrEmpty(text)) { pattern = text; displayName = text; return true; } pattern = val2.m_shared.m_name; displayName = ItemMatch.FormatDisplayName(val2.m_shared.m_name); return !string.IsNullOrEmpty(pattern); } private static void SearchAndHighlight(Player player, string pattern, string displayName, Terminal context) { //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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown ClearHighlights(); _baseGlow = ParseGlowColor(SonicChestFiltersPlugin.ItemLocateGlowColor?.Value); int num = ((SonicChestFiltersPlugin.ItemLocateMaxHighlights != null) ? Mathf.Clamp(SonicChestFiltersPlugin.ItemLocateMaxHighlights.Value, 1, 50) : 10); float num2 = ((SonicChestFiltersPlugin.ItemLocateDurationSeconds != null) ? Mathf.Clamp(SonicChestFiltersPlugin.ItemLocateDurationSeconds.Value, 3f, 120f) : 15f); List<Container> list = NearbyContainers.Get(player); int num3 = 0; List<string> list2 = new List<string>(); for (int i = 0; i < list.Count; i++) { Container val = list[i]; if ((Object)val == (Object)null) { continue; } Inventory inventory; try { inventory = val.GetInventory(); } catch { continue; } if (inventory == null || !InventoryContains(inventory, pattern, list2)) { continue; } num3++; if (Active.Count < num) { HighlightedChest highlightedChest = HighlightedChest.TryCreate(val); if (highlightedChest != null) { Active.Add(highlightedChest); } } } string arg = ((list2.Count > 0) ? string.Join(", ", list2) : ItemMatch.FormatDisplayName(displayName)); if (num3 == 0) { Say("No nearby chests contain " + ItemMatch.FormatDisplayName(displayName) + ".", context); return; } _activeUntil = Time.realtimeSinceStartup + num2; Tick(); if (num3 > Active.Count) { Say($"Found {arg} in {num3} chests (showing nearest {Active.Count}).", context); } else { Say($"Found {arg} in {num3} chests.", context); } if (SonicChestFiltersPlugin.DebugEnabled) { SonicChestFiltersPlugin.Debug($"Item locate '{pattern}': matches={num3}, glowing={Active.Count}, duration={num2:0.#}s."); } } private static bool InventoryContains(Inventory inventory, string pattern, List<string> matchedLabels) { List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null || allItems.Count == 0) { return false; } bool result = false; for (int i = 0; i < allItems.Count; i++) { if (ItemMatch.ItemMatchesPattern(allItems[i], pattern, out var matchedLabel)) { result = true; AddUniqueLabel(matchedLabels, matchedLabel); } } return result; } private static void AddUniqueLabel(List<string> labels, string label) { if (string.IsNullOrEmpty(label)) { return; } for (int i = 0; i < labels.Count; i++) { if (string.Equals(labels[i], label, StringComparison.OrdinalIgnoreCase)) { return; } } labels.Add(label); } private static Color ParseGlowColor(string raw) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); ((Color)(ref result))..ctor(1f, 0.85f, 0.2f, 1f); if (string.IsNullOrWhiteSpace(raw)) { return result; } string[] array = raw.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length < 3) { return result; } if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { return result; } return new Color(Mathf.Clamp01(result2), Mathf.Clamp01(result3), Mathf.Clamp01(result4), 1f); } private static void Say(string message, Terminal context) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if ((Object)context != (Object)null) { context.AddString(message); } else if ((Object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString(message); } else if (SonicChestFiltersPlugin.ModLogger != null) { SonicChestFiltersPlugin.ModLogger.LogInfo((object)message); } } } internal sealed class LocateCommand : ConsoleCommand { public override string Name => "locate"; public override string Help => "[item|clear] Highlight nearby eligible chests containing an item (or clear). No args uses held item."; public override void Run(string[] args, Terminal context) { ItemLocate.OnCommand(args, context); } public override List<string> CommandOptionList() { return ItemLocate.CommandOptions(); } } internal static class ItemMatch { private static Func<string, string> _localizeName; private static bool _localizeResolved; internal static bool NameMatches(string value, string pattern) { if (string.IsNullOrEmpty(pattern)) { return false; } if (pattern.IndexOf('*') < 0) { return string.Equals(value, pattern, StringComparison.OrdinalIgnoreCase); } string[] array = pattern.Split('*'); int num = 0; for (int i = 0; i < array.Length; i++) { string text = array[i]; if (text.Length == 0) { continue; } if (i == 0) { if (!value.StartsWith(text, StringComparison.OrdinalIgnoreCase)) { return false; } num = text.Length; continue; } if (i == array.Length - 1 && pattern[pattern.Length - 1] != '*') { if (!value.EndsWith(text, StringComparison.OrdinalIgnoreCase)) { return false; } return value.Length - text.Length >= num; } int num2 = value.IndexOf(text, num, StringComparison.OrdinalIgnoreCase); if (num2 < 0) { return false; } num = num2 + text.Length; } return true; } internal static bool LocateNameMatches(string value, string pattern) { if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(pattern)) { return false; } if (NameMatches(value, pattern)) { return true; } string text = pattern.Replace("*", string.Empty).Trim(); if (text.Length == 0) { return false; } return value.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0; } internal static bool ItemMatchesPattern(ItemData item, string pattern, out string matchedLabel) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown matchedLabel = string.Empty; if (item?.m_shared == null || string.IsNullOrWhiteSpace(pattern)) { return false; } string name = item.m_shared.m_name; string localizedName = GetLocalizedName(name); if (!string.IsNullOrEmpty(localizedName) && LocateNameMatches(localizedName, pattern)) { matchedLabel = localizedName; return true; } if (!string.IsNullOrEmpty(name) && LocateNameMatches(name, pattern)) { matchedLabel = ((!string.IsNullOrEmpty(localizedName)) ? localizedName : FormatDisplayName(name)); return true; } if (!string.IsNullOrEmpty(name) && name[0] == '$' && LocateNameMatches(name.Substring(1), pattern)) { matchedLabel = ((!string.IsNullOrEmpty(localizedName)) ? localizedName : FormatDisplayName(name)); return true; } if ((Object)item.m_dropPrefab != (Object)null) { string name2 = ((Object)item.m_dropPrefab).name; if (!string.IsNullOrEmpty(name2) && LocateNameMatches(name2, pattern)) { matchedLabel = ((!string.IsNullOrEmpty(localizedName)) ? localizedName : name2); return true; } } return false; } internal static string GetLocalizedName(string sharedName) { if (string.IsNullOrEmpty(sharedName)) { return sharedName; } EnsureLocalizeResolver(); if (_localizeName == null) { return FormatDisplayName(sharedName); } try { string text = _localizeName(sharedName); if (!string.IsNullOrEmpty(text) && text[0] != '$') { return text; } } catch { } return FormatDisplayName(sharedName); } internal static string FormatDisplayName(string name) { if (string.IsNullOrEmpty(name)) { return name; } if (name.StartsWith("$item_", StringComparison.OrdinalIgnoreCase) && name.Length > 6) { string text = name.Substring(6); if (text.Length == 0) { return name; } return char.ToUpperInvariant(text[0]) + text.Substring(1); } if (name.StartsWith("$", StringComparison.Ordinal) && name.Length > 1) { return name.Substring(1); } return name; } private static void EnsureLocalizeResolver() { if (_localizeResolved) { return; } _localizeResolved = true; try { Type type = AccessTools.TypeByName("Localization"); if (type == null) { return; } MethodInfo getInstance = AccessTools.PropertyGetter(type, "instance"); MethodInfo localize = AccessTools.Method(type, "Localize", new Type[1] { typeof(string) }, (Type[])null); if (getInstance == null || localize == null) { localize = AccessTools.Method(type, "Translate", new Type[1] { typeof(string) }, (Type[])null); } if (!(getInstance == null) && !(localize == null)) { _localizeName = delegate(string token) { object obj = getInstance.Invoke(null, null); return (obj == null) ? token : ((localize.Invoke(obj, new object[1] { token }) as string) ?? token); }; } } catch (Exception ex) { SonicChestFiltersPlugin.Debug("Localization resolver failed: " + ex.Message); } } } internal static class ModLocalization { internal const string FilterPlaceholder = "$sonic_chestfilters_filter"; internal const string Clear = "$sonic_chestfilters_clear"; internal const string Sort = "$sonic_chestfilters_sort"; internal static void Register() { if (LocalizationManager.Instance != null) { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "$sonic_chestfilters_filter"; localization.AddTranslation(ref text, "Filter..."); text = "$sonic_chestfilters_clear"; localization.AddTranslation(ref text, "Clear"); text = "$sonic_chestfilters_sort"; localization.AddTranslation(ref text, "Sort"); } } internal static string Translate(string token, string fallback) { if (LocalizationManager.Instance != null) { string text = LocalizationManager.Instance.TryTranslate(token); if (!string.IsNullOrEmpty(text) && text[0] != '[' && text != token) { return text; } } if (Localization.instance != null) { string text2 = Localization.instance.Localize(token); if (!string.IsNullOrEmpty(text2) && text2 != token) { return text2; } } return fallback; } } internal readonly struct ContainerTraits { internal readonly Container Container; internal readonly bool HasPiece; internal readonly bool IsMoving; internal readonly bool IsIncinerator; internal ContainerTraits(Container container, bool hasPiece, bool isMoving, bool isIncinerator) { Container = container; HasPiece = hasPiece; IsMoving = isMoving; IsIncinerator = isIncinerator; } } internal readonly struct ContainerDistance { internal readonly Container Container; internal readonly float DistanceSq; internal ContainerDistance(Container container, float distanceSq) { Container = container; DistanceSq = distanceSq; } } internal static class NearbyContainers { private static readonly List<Container> CachedContainers = new List<Container>(); private static readonly List<ContainerDistance> ScanBuffer = new List<ContainerDistance>(); private static readonly Dictionary<int, ContainerTraits> TraitCache = new Dictionary<int, ContainerTraits>(); private static Player _cachedPlayer; private static Vector3 _cachedPlayerPosition; private static float _containerCacheCreatedAt = -1000f; private static float _cachedRange = -1f; private static bool _cachedRequirePiece; private static bool _cachedIgnoreMoving; private static bool _cachedIgnoreObliterators; private static bool _cachedBalrondCompatibility; internal static void InvalidateAll() { CachedContainers.Clear(); ScanBuffer.Clear(); TraitCache.Clear(); _cachedPlayer = null; _containerCacheCreatedAt = -1000f; _cachedRange = -1f; } internal static List<Container> Get(Player player) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)player == (Object)null) { return CachedContainers; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (ContainerCacheIsValid(player, realtimeSinceStartup)) { return CachedContainers; } RefreshContainerCache(player, realtimeSinceStartup); return CachedContainers; } private static bool ContainerCacheIsValid(Player player, float now) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0015: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) if ((Object)_cachedPlayer != (Object)player) { return false; } if (now - _containerCacheCreatedAt >= 0.5f) { return false; } Vector3 val = ((Component)player).transform.position - _cachedPlayerPosition; if (((Vector3)(ref val)).sqrMagnitude >= 1f) { return false; } if (SonicChestFiltersPlugin.ContainerRange == null) { return false; } if (!Mathf.Approximately(_cachedRange, SonicChestFiltersPlugin.ContainerRange.Value)) { return false; } if (_cachedRequirePiece != SonicChestFiltersPlugin.RequirePlayerPlacedContainer.Value || _cachedIgnoreMoving != SonicChestFiltersPlugin.IgnoreMovingContainers.Value || _cachedIgnoreObliterators != SonicChestFiltersPlugin.IgnoreObliterators.Value || _cachedBalrondCompatibility != SonicChestFiltersPlugin.BalrondCompatibility.Value) { return false; } return true; } private static void RefreshContainerCache(Player player, float now) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) CachedContainers.Clear(); ScanBuffer.Clear(); PruneTraitCache(); float num = Mathf.Max(0f, SonicChestFiltersPlugin.ContainerRange.Value); float num2 = num * num; Vector3 position = ((Component)player).transform.position; float num3 = (SonicChestFiltersPlugin.DebugEnabled ? Time.realtimeSinceStartup : 0f); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); Container[] array2 = array; foreach (Container val in array2) { if ((Object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled) { continue; } Vector3 val2 = ((Component)val).transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude > num2) { continue; } ContainerTraits traits = GetTraits(val); if ((SonicChestFiltersPlugin.IgnoreObliterators.Value && traits.IsIncinerator) || (SonicChestFiltersPlugin.RequirePlayerPlacedContainer.Value && !traits.HasPiece) || ShouldIgnoreMovingContainer(val, traits)) { continue; } try { if (val.GetInventory() == null) { continue; } } catch (Exception) { continue; } ScanBuffer.Add(new ContainerDistance(val, sqrMagnitude)); } ScanBuffer.Sort((ContainerDistance a, ContainerDistance b) => a.DistanceSq.CompareTo(b.DistanceSq)); for (int num4 = 0; num4 < ScanBuffer.Count; num4++) { CachedContainers.Add(ScanBuffer[num4].Container); } _cachedPlayer = player; _cachedPlayerPosition = position; _containerCacheCreatedAt = now; _cachedRange = SonicChestFiltersPlugin.ContainerRange.Value; _cachedRequirePiece = SonicChestFiltersPlugin.RequirePlayerPlacedContainer.Value; _cachedIgnoreMoving = SonicChestFiltersPlugin.IgnoreMovingContainers.Value; _cachedIgnoreObliterators = SonicChestFiltersPlugin.IgnoreObliterators.Value; _cachedBalrondCompatibility = SonicChestFiltersPlugin.BalrondCompatibility.Value; if (SonicChestFiltersPlugin.DebugEnabled) { float num5 = (Time.realtimeSinceStartup - num3) * 1000f; SonicChestFiltersPlugin.Debug($"Container cache refreshed: scanned={array.Length}, eligible={CachedContainers.Count}, time={num5:0.00}ms."); } } private static void PruneTraitCache() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (TraitCache.Count == 0) { return; } List<int> list = null; foreach (KeyValuePair<int, ContainerTraits> item in TraitCache) { if ((Object)item.Value.Container == (Object)null) { if (list == null) { list = new List<int>(); } list.Add(item.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { TraitCache.Remove(list[i]); } } } private static bool ShouldIgnoreMovingContainer(Container container, ContainerTraits traits) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!traits.IsMoving || SonicChestFiltersPlugin.IgnoreMovingContainers == null || !SonicChestFiltersPlugin.IgnoreMovingContainers.Value) { return false; } try { Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(true); if ((Object)componentInParent != (Object)null) { if (componentInParent.InUse() || componentInParent.IsAttached()) { return true; } return false; } } catch { } return true; } private static bool HasPlayerPlacedPiece(Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown try { if ((Object)((Component)container).GetComponentInParent<Piece>() != (Object)null) { return true; } if (!SonicChestFiltersPlugin.BalrondCompatibility.Value) { return false; } Transform root = ((Component)container).transform.root; if ((Object)root == (Object)null) { return false; } Piece[] componentsInChildren = ((Component)root).GetComponentsInChildren<Piece>(true); return componentsInChildren != null && componentsInChildren.Length != 0; } catch { return false; } } private static ContainerTraits GetTraits(Container container) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown int instanceID = ((Object)container).GetInstanceID(); if (TraitCache.TryGetValue(instanceID, out var value) && (Object)(object)value.Container == (Object)(object)container && (value.HasPiece || !SonicChestFiltersPlugin.BalrondCompatibility.Value)) { return value; } bool hasPiece = HasPlayerPlacedPiece(container); bool flag = false; bool flag2 = false; try { if ((Object)((Component)container).GetComponentInParent<Incinerator>(true) != (Object)null) { flag2 = true; } } catch { } try { Component[] componentsInParent = ((Component)container).GetComponentsInParent<Component>(true); for (int i = 0; i < componentsInParent.Length; i++) { switch (((object)componentsInParent[i]).GetType().Name) { case "Ship": case "Vagon": case "Wagon": flag = true; break; case "Incinerator": flag2 = true; break; } if (flag && flag2) { break; } } } catch { } ContainerTraits containerTraits = new ContainerTraits(container, hasPiece, flag, flag2); TraitCache[instanceID] = containerTraits; return containerTraits; } } [BepInPlugin("com.sonicdm.valheim.sonicchestfilters", "Sonic Chest Filters", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class SonicChestFiltersPlugin : BaseUnityPlugin { public const string PluginGuid = "com.sonicdm.valheim.sonicchestfilters"; public const string PluginName = "Sonic Chest Filters"; public const string PluginVersion = "1.0.1"; internal const string NearbyCraftingForkedGuid = "com.sonicdm.valheim.nearbycraftingforked"; internal static ManualLogSource ModLogger; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> AutoReloadConfig; internal static ConfigEntry<bool> DebugLogging; internal static ConfigEntry<float> ContainerRange; internal static ConfigEntry<bool> RequirePlayerPlacedContainer; internal static ConfigEntry<bool> IgnoreMovingContainers; internal static ConfigEntry<bool> IgnoreObliterators; internal static ConfigEntry<bool> BalrondCompatibility; internal static ConfigEntry<bool> EnableFilterBox; internal static ConfigEntry<bool> EnableSortButton; internal static ConfigEntry<bool> ItemLocateEnabled; internal static ConfigEntry<int> ItemLocateMaxHighlights; internal static ConfigEntry<float> ItemLocateDurationSeconds; internal static ConfigEntry<string> ItemLocateGlowColor; private Harmony _harmony; private DateTime _configLastWriteUtc; private float _configWatchNextCheck; private DateTime _configPendingWriteUtc; private float _configPendingSince = -1f; private bool _loggedLocateSkip; internal static bool NearbyCraftingForkedPresent { get; private set; } internal static bool DebugEnabled { get { if (DebugLogging != null) { return DebugLogging.Value; } return false; } } internal static bool LocateIsActive { get { if (NearbyCraftingForkedPresent) { return false; } if (Enabled == null || !Enabled.Value) { return false; } if (ItemLocateEnabled != null) { return ItemLocateEnabled.Value; } return false; } } private void Awake() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Expected O, but got Unknown ModLogger = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Sonic Chest Filters."); AutoReloadConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoReloadConfig", true, "Automatically reload this mod's config when the .cfg file changes on disk."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Write diagnostic information to BepInEx LogOutput.log."); ContainerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Containers", "ContainerRange", 20f, new ConfigDescription("Maximum distance in metres from the player when locating chests.", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); RequirePlayerPlacedContainer = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "RequirePlayerPlacedContainer", true, "Only locate containers attached to a Piece (normally player-built storage)."); IgnoreMovingContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreMovingContainers", true, "Ignore ships, and ignore carts that are currently attached or in use. Parked carts stay eligible for locate."); IgnoreObliterators = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreObliterators", true, "Ignore Obliterators (Incinerator) when locating items."); BalrondCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "BalrondConstructions", true, "Recognize storage prefabs where Container and Piece are siblings under the same prefab root."); EnableFilterBox = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableFilterBox", true, "Show a live Valheim text box on the open chest to filter visible items."); EnableSortButton = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableSortButton", true, "Show a Sort button on the open chest."); ItemLocateEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Item Locate", "Enabled", true, "Enable the 'locate' console command. Ignored when Nearby Crafting Forked is loaded."); ItemLocateMaxHighlights = ((BaseUnityPlugin)this).Config.Bind<int>("Item Locate", "MaxHighlights", 10, new ConfigDescription("Maximum chests to glow (nearest first).", (AcceptableValueBase)new AcceptableValueRange<int>(1, 50), Array.Empty<object>())); ItemLocateDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Item Locate", "DurationSeconds", 15f, new ConfigDescription("How long chest glows last before auto-clear.", (AcceptableValueBase)new AcceptableValueRange<float>(3f, 120f), Array.Empty<object>())); ItemLocateGlowColor = ((BaseUnityPlugin)this).Config.Bind<string>("Item Locate", "GlowColor", "1,0.85,0.2", "Emission tint for highlighted chests as R,G,B in 0-1 range."); ModLocalization.Register(); DetectNearbyCraftingForked(); if (LocateIsActive) { ItemLocate.RegisterCommand(); } ContainerRange.SettingChanged += OnContainerSettingChanged; RequirePlayerPlacedContainer.SettingChanged += OnContainerSettingChanged; IgnoreMovingContainers.SettingChanged += OnContainerSettingChanged; IgnoreObliterators.SettingChanged += OnContainerSettingChanged; BalrondCompatibility.SettingChanged += OnContainerSettingChanged; Enabled.SettingChanged += OnEnabledChanged; _configLastWriteUtc = GetConfigWriteTimeUtc(); _harmony = new Harmony("com.sonicdm.valheim.sonicchestfilters"); try { _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Sonic Chest Filters 1.0.1 loaded."); } catch (Exception ex) { try { _harmony.UnpatchSelf(); } catch { } Enabled.Value = false; ((BaseUnityPlugin)this).Logger.LogError((object)"Sonic Chest Filters failed to apply its Harmony patches and has been disabled."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void Start() { DetectNearbyCraftingForked(); if (LocateIsActive) { ItemLocate.RegisterCommand(); } } private void DetectNearbyCraftingForked() { NearbyCraftingForkedPresent = Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("com.sonicdm.valheim.nearbycraftingforked"); if (NearbyCraftingForkedPresent && !_loggedLocateSkip) { _loggedLocateSkip = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Item locate disabled: Nearby Crafting Forked is loaded (use nearby / locate)."); } } private void Update() { WatchConfigFileForChanges(); if (LocateIsActive) { ItemLocate.Tick(); } ChestPanelUi.Tick(); } private static void OnContainerSettingChanged(object sender, EventArgs e) { NearbyContainers.InvalidateAll(); if (DebugEnabled) { Debug("Container-related configuration changed; caches invalidated."); } } private static void OnEnabledChanged(object sender, EventArgs e) { ResetRuntimeState(); } internal static void ResetRuntimeState() { NearbyContainers.InvalidateAll(); ItemLocate.ClearHighlights(); ChestFilter.Clear(); ChestSort.ResetSession(); ChestPanelUi.ResetFilterText(); } internal static void Debug(string message) { if (DebugEnabled && ModLogger != null) { ModLogger.LogInfo((object)("[DEBUG] " + message)); } } private void WatchConfigFileForChanges() { if (AutoReloadConfig == null || !AutoReloadConfig.Value) { _configPendingSince = -1f; return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _configWatchNextCheck) { return; } _configWatchNextCheck = unscaledTime + 1f; DateTime configWriteTimeUtc = GetConfigWriteTimeUtc(); if (!(configWriteTimeUtc == DateTime.MinValue)) { if (configWriteTimeUtc == _configLastWriteUtc) { _configPendingSince = -1f; } else if (_configPendingSince < 0f || configWriteTimeUtc != _configPendingWriteUtc) { _configPendingWriteUtc = configWriteTimeUtc; _configPendingSince = unscaledTime; } else if (!(unscaledTime - _configPendingSince < 0.75f)) { _configLastWriteUtc = configWriteTimeUtc; _configPendingSince = -1f; ReloadConfigFromDisk(); } } } private DateTime GetConfigWriteTimeUtc() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return DateTime.MinValue; } return File.GetLastWriteTimeUtc(configFilePath); } catch { return DateTime.MinValue; } } private void ReloadConfigFromDisk() { try { ((BaseUnityPlugin)this).Config.Reload(); _configLastWriteUtc = GetConfigWriteTimeUtc(); _configPendingSince = -1f; ResetRuntimeState(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Sonic Chest Filters config reloaded from disk."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"Sonic Chest Filters failed to reload config from disk."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void OnDestroy() { if (ContainerRange != null) { ContainerRange.SettingChanged -= OnContainerSettingChanged; } if (RequirePlayerPlacedContainer != null) { RequirePlayerPlacedContainer.SettingChanged -= OnContainerSettingChanged; } if (IgnoreMovingContainers != null) { IgnoreMovingContainers.SettingChanged -= OnContainerSettingChanged; } if (IgnoreObliterators != null) { IgnoreObliterators.SettingChanged -= OnContainerSettingChanged; } if (BalrondCompatibility != null) { BalrondCompatibility.SettingChanged -= OnContainerSettingChanged; } if (Enabled != null) { Enabled.SettingChanged -= OnEnabledChanged; } ResetRuntimeState(); ChestPanelUi.DestroyControls(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } }