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 Chest Item Finder v1.0.0
plugins\ChestFinder\ChestFinder.dll
Decompiled a day agousing 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<SearchResult> Results = new List<SearchResult>(); private static readonly Dictionary<Container, ChestMarker> Markers = new Dictionary<Container, ChestMarker>(); private ConfigEntry<float> searchRadius; private ConfigEntry<float> markerHeight; private ConfigEntry<float> lightRange; private ConfigEntry<float> lightIntensity; private ConfigEntry<string> markerColor; private ConfigEntry<bool> includePrivateAreas; private ConfigEntry<bool> showScreenLabels; private ConfigEntry<float> blinkDuration; private ConfigEntry<float> 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<ItemSuggestion> suggestions = new List<ItemSuggestion>(); private readonly List<ItemSuggestion> nearbyItems = new List<ItemSuggestion>(); private readonly List<ItemSuggestion> nearbyMatches = new List<ItemSuggestion>(); private readonly List<Container> nearbyContainers = new List<Container>(); 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<GraphicRaycaster> disabledInventoryRaycasters = new List<GraphicRaycaster>(); 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<float>("Search", "Radius", 50f, "Search radius around the local player in meters. Only loaded containers can be scanned."); includePrivateAreas = ((BaseUnityPlugin)this).Config.Bind<bool>("Search", "IncludeContainersInWards", true, "Include containers protected by wards. This only reads locally loaded inventory data."); showScreenLabels = ((BaseUnityPlugin)this).Config.Bind<bool>("Marker", "ShowScreenLabels", true, "Show item/count labels above matching chests."); markerHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Marker", "Height", 1.6f, "Vertical offset of the marker above the container."); lightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Marker", "LightRange", 5f, "Range of the highlight light."); lightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Marker", "LightIntensity", 3.5f, "Intensity of the highlight light."); markerColor = ((BaseUnityPlugin)this).Config.Bind<string>("Marker", "ColorHex", "#FFFFFF", "Highlight color as RGB hex value."); blinkDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Marker", "BlinkDurationSeconds", 10f, "How long matching chests blink."); scanCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("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<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent); ((Object)val2).name = "ChestFinder_SearchButton"; inventorySearchButton = val2.GetComponent<Button>(); ((UnityEventBase)inventorySearchButton.onClick).RemoveAllListeners(); ((UnityEvent)inventorySearchButton.onClick).AddListener((UnityAction)delegate { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Search button clicked. showWindow=" + showWindow + ", IsSearchWindowOpen=" + IsSearchWindowOpen)); OpenSearchPanel(); }); } SetButtonLabel(inventorySearchButton, L("Suchen", "Search")); ((Component)inventorySearchButton).gameObject.SetActive(true); PositionInventorySearchButton(inventorySearchButton, val); } private static void SetButtonLabel(Button button, string label) { if (Object.op_Implicit((Object)(object)button)) { Text[] componentsInChildren = ((Component)button).GetComponentsInChildren<Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = label; } TMP_Text[] componentsInChildren2 = ((Component)button).GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].text = label; } } } private static void PositionInventorySearchButton(Button button, Button template) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) object? obj = typeof(InventoryGui).GetField("m_playerGrid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(InventoryGui.instance); Component val = (Component)((obj is Component) ? obj : null); RectTransform val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<RectTransform>() : null); RectTransform val3 = (Object.op_Implicit((Object)(object)button) ? ((Component)button).GetComponent<RectTransform>() : null); RectTransform val4 = (Object.op_Implicit((Object)(object)template) ? ((Component)template).GetComponent<RectTransform>() : null); if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val4)) { ((Transform)val3).SetParent(((Transform)val2).parent, false); val3.anchorMin = val2.anchorMin; val3.anchorMax = val2.anchorMin; val3.pivot = new Vector2(0.5f, 1f); val3.sizeDelta = new Vector2(Math.Max(val4.sizeDelta.x, 170f), val4.sizeDelta.y); Vector2 anchoredPosition = val2.anchoredPosition; Rect rect = val2.rect; val3.anchoredPosition = anchoredPosition + new Vector2(((Rect)(ref rect)).width + 160f, 150f); } } private void OnGUI() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (showWindow) { GUI.depth = -2000; if ((int)Event.current.type == 0 && !((Rect)(ref windowRect)).Contains(Event.current.mousePosition)) { Event.current.Use(); } DrawSearchWindowSafely(); if (logPanelVisualStateOnNextGui) { LogPanelVisualState(); logPanelVisualStateOnNextGui = false; } } if (showScreenLabels.Value && Results.Count > 0) { EnsureStylesSafely(); DrawLabels(); } } private void DrawWindow(int id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if ((int)current.type == 4 && ((int)current.keyCode == 13 || (int)current.keyCode == 271)) { current.Use(); ExecuteSearchAndClose(); return; } if ((int)current.type == 4 && (int)current.keyCode == 27) { current.Use(); CloseInventoryAndWindow(); return; } GUILayout.Label(L("Item-Suche (50 m Umgebung)", "Item Search (50 m range)"), labelStyle, Array.Empty<GUILayoutOption>()); GUI.SetNextControlName("ChestFinderSearch"); string text = GUILayout.TextField(query ?? "", textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }); if (focusSearchField) { GUI.FocusControl("ChestFinderSearch"); focusSearchField = false; } if (text != query) { query = text; ClearMarkers(); UpdateSuggestions(); } if (GUILayout.Button(L("Suchen", "Search"), buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) })) { ExecuteSearchAndClose(); return; } GUILayout.Space(10f); GUILayout.Label(L("Suchvorschläge", "Search suggestions"), labelStyle, Array.Empty<GUILayoutOption>()); foreach (ItemSuggestion item in suggestions.Take(12)) { if (GUILayout.Button(FormatSuggestion(item.Info), listStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(27f) })) { query = item.Info.CurrentLanguageName; UpdateSuggestions(); GUI.FocusControl("ChestFinderSearch"); } } GUILayout.Space(8f); GUILayout.Label(L("Passendes in der Nähe", "Matching nearby"), labelStyle, Array.Empty<GUILayoutOption>()); foreach (ItemSuggestion item2 in nearbyMatches.Take(12)) { GUILayout.Label(FormatSuggestion(item2.Info), listStyle, Array.Empty<GUILayoutOption>()); } GUILayout.Label(status, Array.Empty<GUILayoutOption>()); scroll = GUILayout.BeginScrollView(scroll, Array.Empty<GUILayoutOption>()); foreach (SearchResult item3 in Results.OrderBy((SearchResult r) => Vector3.Distance(((Component)Player.m_localPlayer).transform.position, ((Component)r.Container).transform.position))) { string containerName = GetContainerName(item3.Container); float num = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Vector3.Distance(((Component)Player.m_localPlayer).transform.position, ((Component)item3.Container).transform.position) : 0f); GUILayout.Label($"{containerName}: {item3.Count}x {item3.DisplayName} ({num:0} m)", listStyle, Array.Empty<GUILayoutOption>()); } GUILayout.EndScrollView(); } private int RunSearch() { //IL_0099: 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_00ce: Unknown result type (might be due to invalid IL or missing references) ClearMarkers(); Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { status = L("Kein lokaler Spieler gefunden.", "No local player found."); return 0; } string text = Normalize(query); if (string.IsNullOrWhiteSpace(text)) { status = L("Bitte zuerst einen Gegenstand eingeben.", "Enter an item name first."); return 0; } RefreshNearbyItems(); foreach (Container item in nearbyContainers.ToList()) { if (!Object.op_Implicit((Object)(object)item) || !((Component)item).gameObject.activeInHierarchy || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)item).transform.position) > searchRadius.Value || (!includePrivateAreas.Value && !PrivateArea.CheckAccess(((Component)item).transform.position, 0f, false, false))) { continue; } Inventory inventory = item.GetInventory(); if (inventory != null) { SearchResult searchResult = FindMatch(item, inventory, text); if (searchResult != null) { Results.Add(searchResult); AddMarker(item); } } } status = ((Results.Count == 1) ? L("1 passende Kiste gefunden.", "Found 1 matching chest.") : (IsGerman() ? $"{Results.Count} passende Kisten gefunden." : $"Found {Results.Count} matching chests.")); return Results.Count; } private SearchResult FindMatch(Container container, Inventory inventory, string needle) { int num = 0; string text = null; foreach (ItemData allItem in inventory.GetAllItems()) { string prefab = (Object.op_Implicit((Object)(object)allItem.m_dropPrefab) ? ((Object)allItem.m_dropPrefab).name : ""); string token = allItem.m_shared?.m_name ?? ""; ItemNameInfo itemInfo = GetItemInfo(token, prefab); if (itemInfo.Matches(needle)) { num += Math.Max(1, allItem.m_stack); text = (string.IsNullOrEmpty(text) ? FormatSuggestion(itemInfo) : text); } } if (num <= 0) { return null; } return new SearchResult(container, text ?? query, num); } private void AddMarker(Container container) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!Markers.ContainsKey(container)) { ChestMarker chestMarker = ((Component)container).gameObject.AddComponent<ChestMarker>(); chestMarker.Setup(ParseColor(markerColor.Value), markerHeight.Value, lightRange.Value, lightIntensity.Value, blinkDuration.Value); Markers[container] = chestMarker; } } private void ClearMarkers() { foreach (ChestMarker item in Markers.Values.Where((ChestMarker marker) => Object.op_Implicit((Object)(object)marker)).ToList()) { Object.Destroy((Object)(object)item); } Markers.Clear(); Results.Clear(); } private void CloseWindowWithoutClearingMarkers() { showWindow = false; IsSearchWindowOpen = false; SetInventoryMouseInteraction(enabled: true); SetInputLocked(locked: false); ResetPanelState(); ((BaseUnityPlugin)this).Logger.LogDebug((object)("ChestFinder search window closed. ResetSearchState executed at frame " + Time.frameCount + ", same frame as open=" + (searchPanelOpenedFrame == Time.frameCount))); } private void ResetPanelState() { //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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) query = string.Empty; status = L("Suchbegriff eingeben und Enter drücken.", "Enter a search term and press Enter."); focusSearchField = false; logPanelVisualStateOnNextGui = false; scroll = Vector2.zero; suggestions.Clear(); nearbyItems.Clear(); nearbyMatches.Clear(); nearbyContainers.Clear(); lastNearbyScanTime = -100f; lastNearbyScanPosition = Vector3.zero; } private void SetInventoryMouseInteraction(bool enabled) { if (!enabled) { disabledInventoryRaycasters.Clear(); if ((Object)(object)InventoryGui.instance == (Object)null) { return; } { foreach (GraphicRaycaster item in ((Component)InventoryGui.instance).GetComponentsInParent<GraphicRaycaster>(true).Concat(((Component)InventoryGui.instance).GetComponentsInChildren<GraphicRaycaster>(true)).Distinct()) { if (Object.op_Implicit((Object)(object)item) && ((Behaviour)item).enabled) { ((Behaviour)item).enabled = false; disabledInventoryRaycasters.Add(item); } } return; } } foreach (GraphicRaycaster disabledInventoryRaycaster in disabledInventoryRaycasters) { if (Object.op_Implicit((Object)(object)disabledInventoryRaycaster)) { ((Behaviour)disabledInventoryRaycaster).enabled = true; } } disabledInventoryRaycasters.Clear(); } private void CloseInventoryAndWindow() { ((BaseUnityPlugin)this).Logger.LogDebug((object)("ChestFinder requested InventoryGui.Hide() at frame " + Time.frameCount + ".")); InventoryGui obj = InventoryGui.instance; if (obj != null) { obj.Hide(); } CloseWindowWithoutClearingMarkers(); } private void ExecuteSearchAndClose() { int num = 0; try { num = RunSearch(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("ChestFinder search failed: " + ex)); } finally { CloseInventoryAndWindow(); } if (num == 0) { ShowGameMessage(L("Nichts Passendes in der Nähe gefunden.", "No matching items found nearby.")); } } private static void ShowGameMessage(string message) { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { ((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null); } } private void DrawLabels() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00fd: 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_011d: Unknown result type (might be due to invalid IL or missing references) Camera mainCamera = Utils.GetMainCamera(); if (!Object.op_Implicit((Object)(object)mainCamera)) { return; } foreach (SearchResult item in Results.ToList()) { if (Object.op_Implicit((Object)(object)item.Container) && Markers.TryGetValue(item.Container, out var value) && value.IsActive) { Vector3 val = ((Component)item.Container).transform.position + Vector3.up * (markerHeight.Value + 0.7f); Vector3 val2 = mainCamera.WorldToScreenPoint(val); if (!(val2.z <= 0f)) { string text = $"{item.Count}x {item.DisplayName}"; Vector2 val3 = worldLabelStyle.CalcSize(new GUIContent(text)); GUI.Box(new Rect(val2.x - val3.x / 2f - 14f, (float)Screen.height - val2.y - 30f, val3.x + 28f, 48f), text, worldLabelStyle); } } } } private static bool Matches(string needle, string value) { if (!string.IsNullOrEmpty(value)) { return Normalize(value).Contains(needle); } return false; } private static string Normalize(string value) { return new string((value ?? string.Empty).Trim().ToLowerInvariant().Replace("$item_", string.Empty) .Where(char.IsLetterOrDigit) .ToArray()); } private static string CleanItemName(string token) { if (string.IsNullOrEmpty(token)) { return ""; } return token.Replace("$item_", "").Replace("$piece_", "").Replace("_", " "); } private string GetLocalizedName(string token) { return TranslationCatalog.Localize(token, CleanItemName(token)); } private static bool IsGerman() { string text = TranslationCatalog.CurrentLanguage(); if (text.IndexOf("German", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("Deutsch", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static string L(string german, string english) { if (!IsGerman()) { return english; } return german; } private void RefreshNearbyItems(bool force = false) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_00c9: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } if (!force && Time.unscaledTime - lastNearbyScanTime < Mathf.Max(1f, scanCooldownSeconds.Value) && Vector3.Distance(lastNearbyScanPosition, ((Component)localPlayer).transform.position) < 4f) { UpdateSuggestions(); return; } lastNearbyScanTime = Time.unscaledTime; lastNearbyScanPosition = ((Component)localPlayer).transform.position; nearbyItems.Clear(); nearbyContainers.Clear(); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array) { if (!Object.op_Implicit((Object)(object)val) || !((Component)val).gameObject.activeInHierarchy || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)val).transform.position) > searchRadius.Value) { continue; } Inventory inventory = val.GetInventory(); if (inventory == null) { continue; } nearbyContainers.Add(val); foreach (ItemData allItem in inventory.GetAllItems()) { string token = allItem.m_shared?.m_name ?? ""; string prefab = (Object.op_Implicit((Object)(object)allItem.m_dropPrefab) ? ((Object)allItem.m_dropPrefab).name : ""); ItemNameInfo info = GetItemInfo(token, prefab); if (!nearbyItems.Any((ItemSuggestion x) => x.Info.LocalizationToken == info.LocalizationToken && x.Info.PrefabName == info.PrefabName)) { nearbyItems.Add(new ItemSuggestion(info)); } } } UpdateSuggestions(); } private void UpdateSuggestions() { suggestions.Clear(); nearbyMatches.Clear(); string needle = Normalize(query); if (!string.IsNullOrWhiteSpace(needle)) { suggestions.AddRange((from item in nearbyItems where item.Info.Matches(needle) orderby MatchPosition(needle, item), item.Info.LocalizedName select item).Take(12)); nearbyMatches.AddRange(suggestions); } } private int MatchPosition(string needle, ItemSuggestion item) { return (from term in item.Info.SearchValues select Normalize(term).IndexOf(needle, StringComparison.Ordinal) into index where index >= 0 select index).DefaultIfEmpty(int.MaxValue).Min(); } private void PositionWindow() { ((Rect)(ref windowRect)).width = Mathf.Clamp((float)Screen.width * 0.44f, 680f, 900f); ((Rect)(ref windowRect)).height = Mathf.Clamp((float)Screen.height * 0.72f, 620f, 920f); ((Rect)(ref windowRect)).x = ((float)Screen.width - ((Rect)(ref windowRect)).width) * 0.5f; ((Rect)(ref windowRect)).y = ((float)Screen.height - ((Rect)(ref windowRect)).height) * 0.5f; } private void EnsureStylesSafely() { try { EnsureStylesCore(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("ChestFinder style or texture initialization failed; opening with fallback style: " + ex)); BuildFallbackStyles(); } } private void EnsureStylesCore() { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00c3: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_016a: 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_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: 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_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_022a: 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_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Expected O, but got Unknown //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Expected O, but got Unknown //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Expected O, but got Unknown if (!usingFallbackStyles && (!stylesReady || !HasStablePanelVisuals())) { ReleasePanelTextures(); Color color = default(Color); ((Color)(ref color))..ctor(0.105f, 0.075f, 0.065f, 1f); Color color2 = default(Color); ((Color)(ref color2))..ctor(0.22f, 0.12f, 0.06f, 1f); Color color3 = default(Color); ((Color)(ref color3))..ctor(0.38f, 0.2f, 0.08f, 1f); Color textColor = default(Color); ((Color)(ref textColor))..ctor(1f, 0.91f, 0.7f, 1f); windowStyle = new GUIStyle(GUI.skin.window) { fontSize = 20, alignment = (TextAnchor)1, padding = new RectOffset(14, 14, 38, 14) }; panelBackgroundTexture = MakeTexture(color); SetStyleState(windowStyle.normal, panelBackgroundTexture, textColor); SetStyleState(windowStyle.hover, panelBackgroundTexture, textColor); SetStyleState(windowStyle.active, panelBackgroundTexture, textColor); SetStyleState(windowStyle.focused, panelBackgroundTexture, textColor); SetStyleState(windowStyle.onNormal, panelBackgroundTexture, textColor); SetStyleState(windowStyle.onHover, panelBackgroundTexture, textColor); SetStyleState(windowStyle.onActive, panelBackgroundTexture, textColor); SetStyleState(windowStyle.onFocused, panelBackgroundTexture, textColor); GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 18 }; val.normal.textColor = textColor; labelStyle = val; textFieldBackgroundTexture = MakeTexture(new Color(0.07f, 0.05f, 0.035f, 1f)); buttonBackgroundTexture = MakeTexture(color2); buttonHoverBackgroundTexture = MakeTexture(color3); GUIStyle val2 = new GUIStyle(GUI.skin.textField) { fontSize = 19 }; val2.normal.textColor = Color.white; val2.normal.background = textFieldBackgroundTexture; textFieldStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.button) { fontSize = 18, fontStyle = (FontStyle)1 }; val3.normal.textColor = textColor; val3.normal.background = buttonBackgroundTexture; val3.hover.textColor = Color.white; val3.hover.background = buttonHoverBackgroundTexture; buttonStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = 17 }; val4.normal.textColor = Color.white; listStyle = val4; worldLabelBackgroundTexture = MakeTexture(new Color(0.08f, 0.05f, 0.03f, 0.9f)); GUIStyle val5 = new GUIStyle(GUI.skin.box) { fontSize = 32, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val5.normal.textColor = new Color(1f, 0.82f, 0.12f, 1f); val5.normal.background = worldLabelBackgroundTexture; worldLabelStyle = val5; stylesReady = true; usingFallbackStyles = false; } } private void BuildFallbackStyles() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_009b: 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) //IL_00b0: Expected O, but got Unknown //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_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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_00fe: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown try { ReleasePanelTextures(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("ChestFinder could not release invalid panel textures: " + ex)); } GUIStyle val = new GUIStyle { fontSize = 20, alignment = (TextAnchor)1, padding = new RectOffset(14, 14, 38, 14) }; val.normal.textColor = Color.white; windowStyle = val; GUIStyle val2 = new GUIStyle { fontSize = 18 }; val2.normal.textColor = Color.white; labelStyle = val2; GUIStyle val3 = new GUIStyle { fontSize = 19 }; val3.normal.textColor = Color.white; textFieldStyle = val3; GUIStyle val4 = new GUIStyle { fontSize = 18, fontStyle = (FontStyle)1 }; val4.normal.textColor = Color.white; buttonStyle = val4; GUIStyle val5 = new GUIStyle { fontSize = 17 }; val5.normal.textColor = Color.white; listStyle = val5; GUIStyle val6 = new GUIStyle { fontSize = 32, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val6.normal.textColor = new Color(1f, 0.82f, 0.12f, 1f); worldLabelStyle = val6; stylesReady = true; usingFallbackStyles = true; } private void DrawSearchWindowSafely() { //IL_000d: 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_0038: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) try { EnsureStylesSafely(); windowRect = GUI.Window(735881, windowRect, new WindowFunction(DrawWindow), L("Kisten-/Gegenstandssuche", "Chest/Item Finder"), windowStyle); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("ChestFinder GUI.Window failed; retrying with fallback style: " + ex)); BuildFallbackStyles(); try { windowRect = GUI.Window(735881, windowRect, new WindowFunction(DrawWindow), L("Kisten-/Gegenstandssuche", "Chest/Item Finder"), windowStyle); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("ChestFinder fallback GUI.Window failed: " + ex2)); } } } private bool HasStablePanelVisuals() { if (windowStyle != null && Object.op_Implicit((Object)(object)panelBackgroundTexture) && Object.op_Implicit((Object)(object)textFieldBackgroundTexture) && Object.op_Implicit((Object)(object)buttonBackgroundTexture) && Object.op_Implicit((Object)(object)buttonHoverBackgroundTexture) && Object.op_Implicit((Object)(object)worldLabelBackgroundTexture) && (Object)(object)windowStyle.normal.background == (Object)(object)panelBackgroundTexture && textFieldStyle != null && (Object)(object)textFieldStyle.normal.background == (Object)(object)textFieldBackgroundTexture && buttonStyle != null) { return (Object)(object)buttonStyle.normal.background == (Object)(object)buttonBackgroundTexture; } return false; } private void LogPanelVisualState() { bool flag = showWindow; bool flag2 = Object.op_Implicit((Object)(object)panelBackgroundTexture) && windowStyle != null && (Object)(object)windowStyle.normal.background == (Object)(object)panelBackgroundTexture; bool flag3 = (Object)(object)((Component)this).gameObject != (Object)null && ((Component)this).gameObject.activeInHierarchy; ((BaseUnityPlugin)this).Logger.LogDebug((object)("ChestFinder panel diagnostics: mainPanelActive=" + flag + ", backgroundImageComponentActive=n/a (IMGUI window), backgroundSpriteSet=n/a (own Texture2D), backgroundTextureAssigned=" + flag2 + ", parentActiveInHierarchy=" + flag3)); } private void ReleasePanelTextures() { Texture2D[] array = (Texture2D[])(object)new Texture2D[5] { panelBackgroundTexture, textFieldBackgroundTexture, buttonBackgroundTexture, buttonHoverBackgroundTexture, worldLabelBackgroundTexture }; foreach (Texture2D val in array) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } panelBackgroundTexture = null; textFieldBackgroundTexture = null; buttonBackgroundTexture = null; buttonHoverBackgroundTexture = null; worldLabelBackgroundTexture = null; stylesReady = false; } private static void SetStyleState(GUIStyleState state, Texture2D background, Color textColor) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) state.background = background; state.textColor = textColor; } private static Texture2D MakeTexture(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_001f: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1) { hideFlags = (HideFlags)32 }; val.SetPixel(0, 0, color); val.Apply(); return val; } private ItemNameInfo GetItemInfo(string token, string prefab) { string localizedName = GetLocalizedName(token); return translations?.GetItemInfo(token, prefab, localizedName) ?? new ItemNameInfo(prefab, token, CleanItemName(token), localizedName, new string[0], new string[0]); } private static string FormatSuggestion(ItemNameInfo info) { if (info == null) { return string.Empty; } if (string.IsNullOrWhiteSpace(info.EnglishName) || Normalize(info.EnglishName) == Normalize(info.LocalizedName)) { return info.LocalizedName; } return info.LocalizedName + " – " + info.EnglishName; } private void SetInputLocked(bool locked) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (inputLocked == locked) { if (!locked) { TrySetOptionalGuiInputBlock(blocked: false); } return; } inputLocked = locked; TrySetOptionalGuiInputBlock(locked); if (locked) { previousCursorLock = Cursor.lockState; previousCursorVisible = Cursor.visible; Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } else { Cursor.lockState = previousCursorLock; Cursor.visible = previousCursorVisible; } ((BaseUnityPlugin)this).Logger.LogDebug((object)("ChestFinder input block " + (locked ? "active." : "disabled."))); } private static void TrySetOptionalGuiInputBlock(bool blocked) { try { Type type = (from assembly in AppDomain.CurrentDomain.GetAssemblies() select assembly.GetType("GUIManager", throwOnError: false)).FirstOrDefault((Type type2) => type2 != null); if (!(type == null)) { object obj = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null) ?? type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null); MethodInfo method = type.GetMethod("BlockInput", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null); if (obj != null && method != null) { method.Invoke(obj, new object[1] { blocked }); } } } catch { } } private void OnDisable() { CloseWindowWithoutClearingMarkers(); } private void OnDestroy() { CloseWindowWithoutClearingMarkers(); ClearMarkers(); ReleasePanelTextures(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } internal static void LogSuppressedInventoryUse() { if (!((Object)(object)instance == (Object)null) && !(Time.unscaledTime < instance.nextSuppressedUseLogTime)) { instance.nextSuppressedUseLogTime = Time.unscaledTime + 1f; ((BaseUnityPlugin)instance).Logger.LogDebug((object)"ChestFinder suppressed InventoryGui Use action"); } } internal static void LogInventoryUsePatchWarning() { ChestFinderPlugin chestFinderPlugin = instance; if (chestFinderPlugin != null) { ((BaseUnityPlugin)chestFinderPlugin).Logger.LogWarning((object)"ChestFinder could not find the InventoryGui Use call to replace; E will not be intercepted."); } } private static void CloseSingleton(string typeName, string methodName) { try { Type type = typeof(Container).Assembly.GetType(typeName); object obj = type?.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null) ?? type?.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null); type?.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public)?.Invoke(obj, null); } catch { } } private static string GetContainerName(Container container) { Piece component = ((Component)container).GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)component) && !string.IsNullOrEmpty(component.m_name)) { string text = TranslationCatalog.Localize(component.m_name, string.Empty); if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("$", StringComparison.Ordinal)) { return text; } } try { string hoverName = container.GetHoverName(); if (!string.IsNullOrWhiteSpace(hoverName) && !hoverName.StartsWith("$", StringComparison.Ordinal)) { return hoverName; } } catch { } if (!IsGerman()) { return "Chest"; } return "Kiste"; } private static Color ParseColor(string value) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); if (!string.IsNullOrWhiteSpace(value) && ColorUtility.TryParseHtmlString(value.Trim(), ref result)) { return result; } return new Color(0.2f, 0.85f, 1f, 1f); } } public sealed class ChestMarker : MonoBehaviour { private sealed class MaterialState { public readonly Material Material; public readonly Color OriginalEmission; public readonly Color OriginalColor; public readonly bool HadEmissionKeyword; public readonly bool HasEmission; public readonly bool HasColor; public MaterialState(Material material, Color originalEmission, Color originalColor, bool hadEmissionKeyword, bool hasEmission, bool hasColor) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Material = material; OriginalEmission = originalEmission; OriginalColor = originalColor; HadEmissionKeyword = hadEmissionKeyword; HasEmission = hasEmission; HasColor = hasColor; } } private readonly List<MaterialState> materials = new List<MaterialState>(); private float expiresAt; private float startedAt; private bool active; public bool IsActive { get { if (active) { return Time.unscaledTime < expiresAt; } return false; } } public void Setup(Color color, float markerHeight, float range, float intensity, float duration) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00b7: Unknown result type (might be due to invalid IL or missing references) Piece componentInParent = ((Component)this).GetComponentInParent<Piece>(); Rigidbody componentInParent2 = ((Component)this).GetComponentInParent<Rigidbody>(); Renderer[] componentsInChildren = ((Component)(Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).transform : (Object.op_Implicit((Object)(object)componentInParent2) ? ((Component)componentInParent2).transform : ((Component)this).transform))).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] array = componentsInChildren[i].materials; foreach (Material val in array) { if (Object.op_Implicit((Object)(object)val) && (val.HasProperty("_EmissionColor") || val.HasProperty("_Color"))) { MaterialState materialState = new MaterialState(val, val.HasProperty("_EmissionColor") ? val.GetColor("_EmissionColor") : Color.black, val.HasProperty("_Color") ? val.GetColor("_Color") : Color.white, val.IsKeywordEnabled("_EMISSION"), val.HasProperty("_EmissionColor"), val.HasProperty("_Color")); materials.Add(materialState); if (materialState.HasEmission) { val.EnableKeyword("_EMISSION"); } } } } startedAt = Time.unscaledTime; expiresAt = startedAt + Mathf.Max(1f, duration); active = true; ApplyBlink(on: true); } private void Update() { if (active) { if (Time.unscaledTime >= expiresAt) { RestoreMaterials(); active = false; } else { bool flag = Mathf.FloorToInt(Time.unscaledTime - startedAt) % 2 == 0; ApplyBlink(flag); } } } private void ApplyBlink(bool on) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) foreach (MaterialState material in materials) { if (Object.op_Implicit((Object)(object)material.Material)) { if (material.HasEmission) { material.Material.SetColor("_EmissionColor", on ? (Color.white * 3.5f) : material.OriginalEmission); } if (material.HasColor) { material.Material.SetColor("_Color", on ? Color.Lerp(material.OriginalColor, Color.white, 0.82f) : material.OriginalColor); } } } } private void OnDestroy() { RestoreMaterials(); } private void RestoreMaterials() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) foreach (MaterialState material in materials) { if (!Object.op_Implicit((Object)(object)material.Material)) { continue; } if (material.HasEmission) { material.Material.SetColor("_EmissionColor", material.OriginalEmission); if (!material.HadEmissionKeyword) { material.Material.DisableKeyword("_EMISSION"); } } if (material.HasColor) { material.Material.SetColor("_Color", material.OriginalColor); } } materials.Clear(); } } internal static class HarmonyPatches { private static Harmony harmony; private static MethodInfo zInputGetButtonDown; private static Func<string, bool> originalGetButtonDown; private static bool inventoryUseCallReplaced; internal static bool TextInputVisibilityPatched { get; private set; } internal static bool InventoryUsePatched { get; private set; } public static void Apply() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown harmony = new Harmony("LEGIOmods.ChestFinder"); TextInputVisibilityPatched = PatchPrefix(typeof(TextInput), "IsVisible", typeof(HarmonyPatches).GetMethod("ExtendTextInputVisibility", BindingFlags.Static | BindingFlags.NonPublic)); InventoryUsePatched = PatchInventoryUseCall(); } private static bool PatchPrefix(Type type, string methodName, MethodInfo prefix) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (methodInfo == null || prefix == null) { return false; } try { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(prefix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch { return false; } } private static bool PatchInventoryUseCall() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown try { zInputGetButtonDown = AccessTools.Method(AccessTools.TypeByName("ZInput"), "GetButtonDown", new Type[1] { typeof(string) }, (Type[])null); MethodInfo method = typeof(HarmonyPatches).GetMethod("InventoryGuiUseButtonDown", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method2 = typeof(HarmonyPatches).GetMethod("ReplaceInventoryGuiUseCall", BindingFlags.Static | BindingFlags.NonPublic); if (zInputGetButtonDown == null || method == null || method2 == null) { return false; } originalGetButtonDown = (Func<string, bool>)Delegate.CreateDelegate(typeof(Func<string, bool>), zInputGetButtonDown); inventoryUseCallReplaced = false; harmony.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null); return inventoryUseCallReplaced; } catch { return false; } } private static bool ExtendTextInputVisibility(ref bool __result) { if (!ChestFinderPlugin.IsSearchWindowOpen) { return true; } __result = true; return false; } private static bool InventoryGuiUseButtonDown(string action) { if (ChestFinderPlugin.IsSearchWindowOpen && string.Equals(action, "Use", StringComparison.Ordinal)) { ChestFinderPlugin.LogSuppressedInventoryUse(); return false; } if (originalGetButtonDown != null) { return originalGetButtonDown(action); } return false; } private static IEnumerable<CodeInstruction> ReplaceInventoryGuiUseCall(IEnumerable<CodeInstruction> instructions) { bool useLiteralPending = false; bool replaced = false; MethodInfo wrapper = typeof(HarmonyPatches).GetMethod("InventoryGuiUseButtonDown", BindingFlags.Static | BindingFlags.NonPublic); foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr) { useLiteralPending = string.Equals(instruction.operand as string, "Use", StringComparison.Ordinal); yield return instruction; continue; } if (!replaced && useLiteralPending && instruction.opcode == OpCodes.Call && object.Equals(instruction.operand, zInputGetButtonDown)) { instruction.opcode = OpCodes.Call; instruction.operand = wrapper; replaced = true; inventoryUseCallReplaced = true; } useLiteralPending = false; yield return instruction; } if (!replaced) { ChestFinderPlugin.LogInventoryUsePatchWarning(); } } } internal sealed class ItemNameInfo { public readonly string PrefabName; public readonly string LocalizationToken; public readonly string EnglishName; public readonly string CurrentLanguageName; public readonly string[] EnglishAliases; public readonly string[] CurrentLanguageAliases; public readonly string[] SearchValues; public string LocalizedName => CurrentLanguageName; public ItemNameInfo(string prefabName, string localizationToken, string englishName, string currentLanguageName, IEnumerable<string> englishAliases, IEnumerable<string> currentLanguageAliases) { PrefabName = prefabName ?? string.Empty; LocalizationToken = localizationToken ?? string.Empty; EnglishName = englishName ?? string.Empty; CurrentLanguageName = currentLanguageName ?? string.Empty; EnglishAliases = Clean(englishAliases); CurrentLanguageAliases = Clean(currentLanguageAliases); SearchValues = Clean(new string[4] { PrefabName, LocalizationToken, EnglishName, CurrentLanguageName }.Concat(EnglishAliases).Concat(CurrentLanguageAliases)); } public bool Matches(string normalizedNeedle) { if (!string.IsNullOrWhiteSpace(normalizedNeedle)) { return SearchValues.Any((string value) => Normalize(value).Contains(normalizedNeedle)); } return false; } private static string[] Clean(IEnumerable<string> values) { return (from value in values ?? Enumerable.Empty<string>() where !string.IsNullOrWhiteSpace(value) select value.Trim()).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray(); } internal static string Normalize(string value) { return new string((value ?? string.Empty).Trim().ToLowerInvariant().Where(char.IsLetterOrDigit) .ToArray()); } } internal sealed class TranslationCatalog { private sealed class TranslationRow { private readonly Dictionary<string, string> values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public string Get(string column) { if (!values.TryGetValue(column ?? string.Empty, out var value)) { return string.Empty; } return value; } public void Set(string column, string value) { if (!string.IsNullOrWhiteSpace(column)) { values[column] = value ?? string.Empty; } } } private sealed class AliasRow { public List<string> EnglishAliases = new List<string>(); public List<string> GermanAliases = new List<string>(); public IEnumerable<string> GetAliases(string language) { if (!language.Equals("German", StringComparison.OrdinalIgnoreCase) && !language.Equals("Deutsch", StringComparison.OrdinalIgnoreCase)) { return Enumerable.Empty<string>(); } return GermanAliases; } } private const string TranslationResourceName = "ChestFinder.ItemTranslations.csv"; private const string AliasResourceName = "ChestFinder.ItemAliases.csv"; private const string TranslationFileName = "ChestFinder.ItemTranslations.csv"; private const string AliasFileName = "ChestFinder.ItemAliases.csv"; private readonly Dictionary<string, TranslationRow> translations = new Dictionary<string, TranslationRow>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, AliasRow> aliases = new Dictionary<string, AliasRow>(StringComparer.OrdinalIgnoreCase); private readonly List<string> translationColumns = new List<string>(); private readonly ManualLogSource log; private readonly string translationFilePath; private readonly string aliasFilePath; private float nextRefresh; private int lastObjectDbCount = -1; public string TranslationFilePath => translationFilePath; public string AliasFilePath => aliasFilePath; public TranslationCatalog(ManualLogSource logger) { log = logger; translationFilePath = Path.Combine(Paths.ConfigPath, "ChestFinder.ItemTranslations.csv"); aliasFilePath = Path.Combine(Paths.ConfigPath, "ChestFinder.ItemAliases.csv"); LoadEmbeddedTranslations(); LoadEditableTranslations(); LoadEmbeddedAliases(); LoadEditableAliases(); } public void RefreshLoadedItems(bool force = false) { if (!force && Time.unscaledTime < nextRefresh) { return; } nextRefresh = Time.unscaledTime + 10f; if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items == null) { return; } string text = CurrentLanguage(); EnsureTranslationColumn("Token"); EnsureTranslationColumn("Prefab"); EnsureTranslationColumn("English"); EnsureTranslationColumn("German"); EnsureTranslationColumn("Aliases"); EnsureTranslationColumn(text); bool changed = ObjectDB.instance.m_items.Count != lastObjectDbCount; lastObjectDbCount = ObjectDB.instance.m_items.Count; foreach (GameObject item in ObjectDB.instance.m_items) { string text2 = (Object.op_Implicit((Object)(object)item) ? item.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrWhiteSpace(text2)) { TranslationRow orCreateTranslation = GetOrCreateTranslation(text2, ((Object)item).name, ref changed); string value = Localize(text2, PrettyEnglish(text2, ((Object)item).name)); changed |= SetIfEmpty(orCreateTranslation, "Token", text2); changed |= SetIfEmpty(orCreateTranslation, "Prefab", ((Object)item).name); changed |= SetIfEmpty(orCreateTranslation, text, value); if (text.Equals("English", StringComparison.OrdinalIgnoreCase)) { changed |= SetIfEmpty(orCreateTranslation, "English", value); } } } if (changed) { SaveTranslations(); } } public ItemNameInfo GetItemInfo(string token, string prefabName, string localizedFallback) { TranslationRow translationRow = FindTranslation(token, prefabName); string text = CurrentLanguage(); string text2 = Localize(token, localizedFallback); string text3 = translationRow?.Get("English"); if (string.IsNullOrWhiteSpace(text3)) { text3 = (text.Equals("English", StringComparison.OrdinalIgnoreCase) ? text2 : PrettyEnglish(token, prefabName)); } if (string.IsNullOrWhiteSpace(text2)) { text2 = text3; } AliasRow value = null; if (!string.IsNullOrWhiteSpace(prefabName)) { aliases.TryGetValue(prefabName, out value); } IEnumerable<string> first = SplitAliases(translationRow?.Get("Aliases")); IEnumerable<string> enumerable = value?.EnglishAliases; IEnumerable<string> englishAliases = first.Concat(enumerable ?? Enumerable.Empty<string>()); IEnumerable<string> currentLanguageAliases = value?.GetAliases(text) ?? Enumerable.Empty<string>(); return new ItemNameInfo(prefabName, token, text3, text2, englishAliases, currentLanguageAliases); } public static string CurrentLanguage() { try { Localization instance = Localization.instance; string text = ((instance != null) ? instance.GetSelectedLanguage() : null); return string.IsNullOrWhiteSpace(text) ? "English" : text; } catch { return "English"; } } public static string Localize(string token, string fallback) { try { Localization instance = Localization.instance; string text = ((instance != null) ? instance.Localize(token ?? string.Empty) : null); if (!string.IsNullOrWhiteSpace(text) && !text.Equals(token, StringComparison.Ordinal)) { return StripRichText(text); } } catch { } return StripRichText(string.IsNullOrWhiteSpace(fallback) ? PrettyEnglish(token, string.Empty) : fallback); } private TranslationRow GetOrCreateTranslation(string token, string prefabName, ref bool changed) { string key = TranslationKey(token, prefabName); if (translations.TryGetValue(key, out var value)) { return value; } value = new TranslationRow(); translations[key] = value; changed = true; return value; } private TranslationRow FindTranslation(string token, string prefabName) { if (translations.TryGetValue(TranslationKey(token, prefabName), out var value)) { return value; } return translations.Values.FirstOrDefault((TranslationRow row) => row.Get("Token").Equals(token ?? string.Empty, StringComparison.OrdinalIgnoreCase)); } private void LoadEmbeddedTranslations() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ChestFinder.ItemTranslations.csv"); using StreamReader streamReader = ((stream == null) ? null : new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true)); if (streamReader != null) { MergeTranslations(streamReader.ReadToEnd(), overwrite: false); } } private void LoadEditableTranslations() { try { if (File.Exists(translationFilePath)) { MergeTranslations(File.ReadAllText(translationFilePath, Encoding.UTF8), overwrite: true); } else { SaveTranslations(); } } catch (Exception ex) { log.LogWarning((object)("ChestFinder translation CSV could not be loaded: " + ex.Message)); } } private void LoadEmbeddedAliases() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ChestFinder.ItemAliases.csv"); using StreamReader streamReader = ((stream == null) ? null : new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true)); if (streamReader != null) { MergeAliases(streamReader.ReadToEnd(), overwrite: false); } } private void LoadEditableAliases() { try { if (File.Exists(aliasFilePath)) { MergeAliases(File.ReadAllText(aliasFilePath, Encoding.UTF8), overwrite: true); } else { CopyDefaultAliases(); } } catch (Exception ex) { log.LogWarning((object)("ChestFinder alias CSV could not be loaded: " + ex.Message)); } } private void MergeTranslations(string csv, bool overwrite) { List<List<string>> list = ParseCsv(csv); if (list.Count == 0) { return; } foreach (string item in list[0]) { EnsureTranslationColumn(item); } int num = ColumnIndex(list[0], "Token"); int index = ColumnIndex(list[0], "Prefab"); if (num < 0) { return; } for (int i = 1; i < list.Count; i++) { List<string> values = list[i]; string text = Cell(values, num); if (string.IsNullOrWhiteSpace(text)) { continue; } string prefab = Cell(values, index); string key = TranslationKey(text, prefab); if (!translations.TryGetValue(key, out var value)) { value = (translations[key] = new TranslationRow()); } for (int j = 0; j < list[0].Count; j++) { string column = list[0][j]; string value2 = Cell(values, j); if (overwrite || string.IsNullOrWhiteSpace(value.Get(column))) { value.Set(column, value2); } } } } private void MergeAliases(string csv, bool overwrite) { List<List<string>> list = ParseCsv(csv); if (list.Count == 0) { return; } int num = ColumnIndex(list[0], "PrefabName"); int index = ColumnIndex(list[0], "EnglishAliases"); int index2 = ColumnIndex(list[0], "GermanAliases"); if (num < 0) { return; } for (int i = 1; i < list.Count; i++) { string text = Cell(list[i], num); if (!string.IsNullOrWhiteSpace(text)) { if (!aliases.TryGetValue(text, out var value)) { value = (aliases[text] = new AliasRow()); } if (overwrite || value.EnglishAliases.Count == 0) { value.EnglishAliases = SplitAliases(Cell(list[i], index)).ToList(); } if (overwrite || value.GermanAliases.Count == 0) { value.GermanAliases = SplitAliases(Cell(list[i], index2)).ToList(); } } } } private void CopyDefaultAliases() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ChestFinder.ItemAliases.csv"); using StreamReader streamReader = ((stream == null) ? null : new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true)); if (streamReader != null) { Directory.CreateDirectory(Path.GetDirectoryName(aliasFilePath)); File.WriteAllText(aliasFilePath, streamReader.ReadToEnd(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)); } } private void SaveTranslations() { try { Directory.CreateDirectory(Path.GetDirectoryName(translationFilePath)); using StreamWriter streamWriter = new StreamWriter(translationFilePath, append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)); streamWriter.WriteLine(string.Join(",", translationColumns.Select(EscapeCsv))); foreach (TranslationRow row in translations.Values.OrderBy<TranslationRow, string>((TranslationRow value) => value.Get("Token"), StringComparer.OrdinalIgnoreCase).ThenBy<TranslationRow, string>((TranslationRow value) => value.Get("Prefab"), StringComparer.OrdinalIgnoreCase)) { streamWriter.WriteLine(string.Join(",", translationColumns.Select((string column) => EscapeCsv(row.Get(column))))); } } catch (Exception ex) { log.LogWarning((object)("ChestFinder translation CSV could not be saved: " + ex.Message)); } } private void EnsureTranslationColumn(string column) { if (!string.IsNullOrWhiteSpace(column) && !translationColumns.Any((string existing) => existing.Equals(column, StringComparison.OrdinalIgnoreCase))) { translationColumns.Add(column); } } private static bool SetIfEmpty(TranslationRow row, string column, string value) { if (string.IsNullOrWhiteSpace(value) || !string.IsNullOrWhiteSpace(row.Get(column))) { return false; } row.Set(column, value); return true; } private static int ColumnIndex(List<string> columns, string name) { return columns.FindIndex((string column) => column.Equals(name, StringComparison.OrdinalIgnoreCase)); } private static string Cell(List<string> values, int index) { if (index < 0 || index >= values.Count) { return string.Empty; } return values[index]; } private static string TranslationKey(string token, string prefab) { return (token ?? string.Empty) + "\u001f" + (prefab ?? string.Empty); } private static string PrettyEnglish(string token, string prefab) { string text = (token ?? string.Empty).Replace("$item_", string.Empty).Replace('_', ' '); if (string.IsNullOrWhiteSpace(text)) { text = prefab ?? string.Empty; } return Regex.Replace(text, "([a-z])([A-Z])", "$1 $2").Trim(); } private static string StripRichText(string value) { return Regex.Replace(value ?? string.Empty, "<.*?>", string.Empty).Trim(); } private static IEnumerable<string> SplitAliases(string value) { return from alias in (value ?? string.Empty).Split(new char[2] { ';', '|' }, StringSplitOptions.RemoveEmptyEntries) select alias.Trim() into alias where alias.Length > 0 select alias; } private static string EscapeCsv(string value) { return "\"" + (value ?? string.Empty).Replace("\"", "\"\"") + "\""; } private static List<List<string>> ParseCsv(string csv) { List<List<string>> list = new List<List<string>>(); List<string> list2 = new List<string>(); StringBuilder stringBuilder = new StringBuilder(); bool flag = false; for (int i = 0; i < (csv ?? string.Empty).Length; i++) { char c = csv[i]; switch (c) { case '"': if (flag && i + 1 < csv.Length && csv[i + 1] == '"') { stringBuilder.Append('"'); i++; } else { flag = !flag; } continue; case ',': if (!flag) { list2.Add(stringBuilder.ToString()); stringBuilder.Length = 0; continue; } break; } if ((c == '\r' || c == '\n') && !flag) { if (c == '\r' && i + 1 < csv.Length && csv[i + 1] == '\n') { i++; } list2.Add(stringBuilder.ToString()); stringBuilder.Length = 0; if (list2.Any((string value) => value.Length > 0)) { list.Add(list2); } list2 = new List<string>(); } else { stringBuilder.Append(c); } } list2.Add(stringBuilder.ToString()); if (list2.Any((string value) => value.Length > 0)) { list.Add(list2); } if (list.Count > 0 && list[0].Count > 0) { list[0][0] = list[0][0].TrimStart(new char[1] { '\ufeff' }); } return list; } } }