using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; 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: AssemblyTitle("Chest/Item Finder")] [assembly: AssemblyDescription("Search loaded Valheim containers and highlight matching chests.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("LEGIOmods")] [assembly: AssemblyProduct("Chest/Item Finder")] [assembly: AssemblyCopyright("Copyright 2026 LEGIOmods")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6b6cc84c-baa4-4d0f-84f9-5f752751d33d")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI for code, localization, documentation, and package preparation.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "OpenAI")] [assembly: AssemblyMetadata("AI_Agent", "OpenAI Codex")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.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 ChestFinder { [DefaultExecutionOrder(10000)] [BepInPlugin("LEGIOmods.ChestFinder", "Chest/Item Finder", "1.0.0")] public class ChestFinderPlugin : BaseUnityPlugin { private sealed class ItemSuggestion { public readonly ItemNameInfo Info; public ItemSuggestion(ItemNameInfo info) { Info = info; } } private sealed class SearchResult { public readonly Container Container; public readonly string DisplayName; public readonly int Count; public SearchResult(Container container, string displayName, int count) { Container = container; DisplayName = displayName; Count = count; } } public const string GUID = "LEGIOmods.ChestFinder"; public const string NAME = "Chest/Item Finder"; public const string VERSION = "1.0.0"; private static ChestFinderPlugin instance; private static readonly List Results = new List(); private static readonly Dictionary Markers = new Dictionary(); private ConfigEntry searchRadius; private ConfigEntry markerHeight; private ConfigEntry lightRange; private ConfigEntry lightIntensity; private ConfigEntry markerColor; private ConfigEntry includePrivateAreas; private ConfigEntry showScreenLabels; private ConfigEntry blinkDuration; private ConfigEntry scanCooldownSeconds; private Rect windowRect = new Rect(0f, 0f, 680f, 620f); private string query = ""; private string status = "Enter an item and press Enter to search."; private bool showWindow; private Vector2 scroll; private readonly List suggestions = new List(); private readonly List nearbyItems = new List(); private readonly List nearbyMatches = new List(); private readonly List nearbyContainers = new List(); private TranslationCatalog translations; private float lastNearbyScanTime = -100f; private Vector3 lastNearbyScanPosition; private GUIStyle windowStyle; private GUIStyle labelStyle; private GUIStyle textFieldStyle; private GUIStyle buttonStyle; private GUIStyle listStyle; private GUIStyle worldLabelStyle; private bool stylesReady; private bool usingFallbackStyles; private Texture2D panelBackgroundTexture; private Texture2D textFieldBackgroundTexture; private Texture2D buttonBackgroundTexture; private Texture2D buttonHoverBackgroundTexture; private Texture2D worldLabelBackgroundTexture; private bool inputLocked; private CursorLockMode previousCursorLock; private bool previousCursorVisible; private Button inventorySearchButton; private bool focusSearchField; private int searchPanelOpenedFrame = -1; private bool logPanelVisualStateOnNextGui; private float nextSuppressedUseLogTime; private readonly List disabledInventoryRaycasters = new List(); public static bool IsSearchWindowOpen { get; private set; } private void Awake() { instance = this; HarmonyPatches.Apply(); translations = new TranslationCatalog(((BaseUnityPlugin)this).Logger); searchRadius = ((BaseUnityPlugin)this).Config.Bind("Search", "Radius", 50f, "Search radius around the local player in meters. Only loaded containers can be scanned."); includePrivateAreas = ((BaseUnityPlugin)this).Config.Bind("Search", "IncludeContainersInWards", true, "Include containers protected by wards. This only reads locally loaded inventory data."); showScreenLabels = ((BaseUnityPlugin)this).Config.Bind("Marker", "ShowScreenLabels", true, "Show item/count labels above matching chests."); markerHeight = ((BaseUnityPlugin)this).Config.Bind("Marker", "Height", 1.6f, "Vertical offset of the marker above the container."); lightRange = ((BaseUnityPlugin)this).Config.Bind("Marker", "LightRange", 5f, "Range of the highlight light."); lightIntensity = ((BaseUnityPlugin)this).Config.Bind("Marker", "LightIntensity", 3.5f, "Intensity of the highlight light."); markerColor = ((BaseUnityPlugin)this).Config.Bind("Marker", "ColorHex", "#FFFFFF", "Highlight color as RGB hex value."); blinkDuration = ((BaseUnityPlugin)this).Config.Bind("Marker", "BlinkDurationSeconds", 10f, "How long matching chests blink."); scanCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind("Performance", "ScanCooldownSeconds", 3f, "Minimum time between nearby container scans."); } private void Update() { translations?.RefreshLoadedItems(); if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible()) { EnsureInventorySearchButton(); } else { if (Object.op_Implicit((Object)(object)inventorySearchButton)) { ((Component)inventorySearchButton).gameObject.SetActive(false); } if (showWindow) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("ChestFinder detected InventoryGui closed at frame " + Time.frameCount + "; closing search window. Opened this frame=" + (searchPanelOpenedFrame == Time.frameCount))); if (searchPanelOpenedFrame != Time.frameCount) { CloseWindowWithoutClearingMarkers(); } } } if (showWindow) { PositionWindow(); } } private void OpenSearchPanel() { ((BaseUnityPlugin)this).Logger.LogDebug((object)("OpenSearchWindow entered. showWindow=" + showWindow + ", IsSearchWindowOpen=" + IsSearchWindowOpen + ", inventoryVisible=" + ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible()))); if (showWindow || (Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible()) { return; } try { showWindow = true; IsSearchWindowOpen = true; searchPanelOpenedFrame = Time.frameCount; ((BaseUnityPlugin)this).Logger.LogDebug((object)("OpenSearchWindow state set. showWindow=" + showWindow + ", IsSearchWindowOpen=" + IsSearchWindowOpen + ", frame=" + searchPanelOpenedFrame)); query = string.Empty; status = L("Suchbegriff eingeben und Enter drücken.", "Enter a search term and press Enter."); focusSearchField = true; PositionWindow(); usingFallbackStyles = false; logPanelVisualStateOnNextGui = true; translations?.RefreshLoadedItems(force: true); RefreshNearbyItems(force: true); ClearMarkers(); SetInputLocked(locked: true); SetInventoryMouseInteraction(enabled: false); ((BaseUnityPlugin)this).Logger.LogDebug((object)"ChestFinder search window opened."); ((BaseUnityPlugin)this).Logger.LogDebug((object)("ChestFinder input block active. TextInput.IsVisible patched=" + HarmonyPatches.TextInputVisibilityPatched + ", Inventory Use call patched=" + HarmonyPatches.InventoryUsePatched)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("ChestFinder could not open the search panel: " + ex)); CloseWindowWithoutClearingMarkers(); } } private void EnsureInventorySearchButton() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown Button val = InventoryGui.instance?.m_takeAllButton; if ((Object)(object)val == (Object)null) { return; } if (!Object.op_Implicit((Object)(object)inventorySearchButton)) { GameObject val2 = Object.Instantiate(((Component)val).gameObject, ((Component)val).transform.parent); ((Object)val2).name = "ChestFinder_SearchButton"; inventorySearchButton = val2.GetComponent