Decompiled source of Chest Item Finder v1.0.0

plugins\ChestFinder\ChestFinder.dll

Decompiled a day ago
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<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;
		}
	}
}