Decompiled source of SonicChestFilters v1.0.1

SonicChestFilters.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SonicChestFilters")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+daeb12fe14336c3cde1064af94634546a47507bc")]
[assembly: AssemblyProduct("SonicChestFilters")]
[assembly: AssemblyTitle("SonicChestFilters")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SonicChestFilters
{
	internal static class ChestFilter
	{
		internal static string Query { get; private set; } = string.Empty;

		internal static bool HasQuery => !string.IsNullOrWhiteSpace(Query);

		internal static void SetQuery(string query)
		{
			Query = query ?? string.Empty;
		}

		internal static void Clear()
		{
			Query = string.Empty;
		}

		internal static bool ItemIsVisible(ItemData item)
		{
			if (!HasQuery)
			{
				return true;
			}
			if (item?.m_shared == null)
			{
				return true;
			}
			string matchedLabel;
			return ItemMatch.ItemMatchesPattern(item, Query.Trim(), out matchedLabel);
		}

		internal static void ApplyToGrid(InventoryGrid grid, Inventory inventory)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)grid == (Object)null || inventory == null || !(AccessTools.Field(typeof(InventoryGrid), "m_elements")?.GetValue(grid) is List<InventoryElement> list))
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				InventoryElement val = list[i];
				if (!((Object)val == (Object)null))
				{
					if (!HasQuery || !val.m_used)
					{
						RestoreClickable(val);
					}
					else if (ItemIsVisible(inventory.GetItemAt(val.Position.x, val.Position.y)))
					{
						RestoreClickable(val);
					}
					else
					{
						HideOccupied(val);
					}
				}
			}
		}

		private static void RestoreClickable(InventoryElement element)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if ((Object)element.m_button != (Object)null)
			{
				((Selectable)element.m_button).interactable = true;
			}
		}

		private static void HideOccupied(InventoryElement element)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			SetGraphicEnabled((Graphic)(object)element.m_icon, enabled: false);
			SetGraphicEnabled((Graphic)(object)element.m_amount, enabled: false);
			SetGraphicEnabled((Graphic)(object)element.m_quality, enabled: false);
			SetGraphicEnabled((Graphic)(object)element.m_equiped, enabled: false);
			SetGraphicEnabled((Graphic)(object)element.m_queued, enabled: false);
			SetGraphicEnabled((Graphic)(object)element.m_noteleport, enabled: false);
			SetGraphicEnabled((Graphic)(object)element.m_food, enabled: false);
			if ((Object)element.m_durability != (Object)null)
			{
				((Component)element.m_durability).gameObject.SetActive(false);
			}
			if ((Object)element.m_tooltip != (Object)null)
			{
				((Behaviour)element.m_tooltip).enabled = false;
			}
			if ((Object)element.m_button != (Object)null)
			{
				((Selectable)element.m_button).interactable = false;
			}
			element.m_canBeDroppedOn = false;
		}

		private static void SetGraphicEnabled(Graphic graphic, bool enabled)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if ((Object)graphic != (Object)null)
			{
				((Behaviour)graphic).enabled = enabled;
			}
		}
	}
	internal static class ChestPanelUi
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction<string> <0>__OnFilterChanged;

			public static UnityAction <1>__OnClearClicked;

			public static UnityAction <2>__OnSortClicked;
		}

		private const string FilterRootName = "SonicChestFilters_Root";

		private const float ToolbarHeight = 44f;

		private static GameObject _root;

		private static Button _clearButton;

		private static InputField _filterInput;

		private static string _lastFilterText = string.Empty;

		private static Container _boundContainer;

		private static bool _expanded;

		private static bool _inputBlocked;

		private static bool FilterFieldFocused
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Expected O, but got Unknown
				if ((Object)_filterInput != (Object)null)
				{
					return _filterInput.isFocused;
				}
				return false;
			}
		}

		internal static void EnsureControls(InventoryGui gui)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_006c: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			if ((Object)gui == (Object)null || (Object)gui.m_container == (Object)null)
			{
				return;
			}
			if (SonicChestFiltersPlugin.Enabled == null || !SonicChestFiltersPlugin.Enabled.Value)
			{
				DestroyControls(gui);
				return;
			}
			Container val = GameAccess.Get<Container>(gui, "m_currentContainer");
			if ((Object)val == (Object)null)
			{
				return;
			}
			if ((Object)_boundContainer != (Object)val)
			{
				RestoreFrame(gui);
				DestroyWidgets();
			}
			if (GUIManager.Instance != null)
			{
				if ((Object)_root == (Object)null)
				{
					CreateToolbar(gui);
					_boundContainer = val;
				}
				ApplyFrameLayout(gui);
				RefreshClearButton();
			}
		}

		internal static void Tick()
		{
			SyncInputBlock(FilterFieldFocused);
			SyncFilterField();
		}

		internal static void ResetFilterText()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			_lastFilterText = string.Empty;
			ChestFilter.Clear();
			if ((Object)_filterInput != (Object)null)
			{
				_filterInput.SetTextWithoutNotify(string.Empty);
			}
			RefreshClearButton();
			RefreshContainerGrid();
		}

		internal static void DestroyControls()
		{
			DestroyControls(InventoryGui.instance);
		}

		internal static void DestroyControls(InventoryGui gui)
		{
			RestoreFrame(gui);
			DestroyWidgets();
			_boundContainer = null;
		}

		private static void CreateToolbar(InventoryGui gui)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Expected O, but got Unknown
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Expected O, but got Unknown
			RectTransform container = gui.m_container;
			_root = new GameObject("SonicChestFilters_Root", new Type[1] { typeof(RectTransform) });
			_root.transform.SetParent((Transform)(object)container, false);
			RectTransform component = _root.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.sizeDelta = new Vector2(0f, 44f);
			float num = 101f;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 0.5f);
			if (SonicChestFiltersPlugin.EnableFilterBox == null || SonicChestFiltersPlugin.EnableFilterBox.Value)
			{
				GameObject val2 = GUIManager.Instance.CreateInputField((Transform)(object)component, val, val, new Vector2(num, 0f), (ContentType)0, ModLocalization.Translate("$sonic_chestfilters_filter", "Filter..."), 16, 170f, 28f);
				if ((Object)val2 != (Object)null)
				{
					((Object)val2).name = "SonicChestFilters_FilterField";
					_filterInput = val2.GetComponent<InputField>();
					if ((Object)_filterInput != (Object)null)
					{
						_filterInput.characterLimit = 64;
						_filterInput.SetTextWithoutNotify(string.Empty);
						((UnityEvent<string>)(object)_filterInput.onValueChanged).AddListener((UnityAction<string>)OnFilterChanged);
						((UnityEvent<string>)(object)_filterInput.onEndEdit).AddListener((UnityAction<string>)OnFilterChanged);
					}
					num += 133f;
				}
				GameObject val3 = GUIManager.Instance.CreateButton(ModLocalization.Translate("$sonic_chestfilters_clear", "Clear"), (Transform)(object)component, val, val, new Vector2(num, 0f), 80f, 28f);
				if ((Object)val3 != (Object)null)
				{
					((Object)val3).name = "SonicChestFilters_Clear";
					_clearButton = val3.GetComponent<Button>();
					if ((Object)_clearButton != (Object)null)
					{
						ButtonClickedEvent onClick = _clearButton.onClick;
						object obj = <>O.<1>__OnClearClicked;
						if (obj == null)
						{
							UnityAction val4 = OnClearClicked;
							<>O.<1>__OnClearClicked = val4;
							obj = (object)val4;
						}
						((UnityEvent)onClick).AddListener((UnityAction)obj);
					}
					num += 88f;
				}
			}
			if (SonicChestFiltersPlugin.EnableSortButton == null || SonicChestFiltersPlugin.EnableSortButton.Value)
			{
				GameObject val5 = GUIManager.Instance.CreateButton(ModLocalization.Translate("$sonic_chestfilters_sort", "Sort"), (Transform)(object)component, val, val, new Vector2(num, 0f), 80f, 28f);
				if ((Object)val5 != (Object)null)
				{
					((Object)val5).name = "SonicChestFilters_Sort";
					Button component2 = val5.GetComponent<Button>();
					if ((Object)component2 != (Object)null)
					{
						ButtonClickedEvent onClick2 = component2.onClick;
						object obj2 = <>O.<2>__OnSortClicked;
						if (obj2 == null)
						{
							UnityAction val6 = OnSortClicked;
							<>O.<2>__OnSortClicked = val6;
							obj2 = (object)val6;
						}
						((UnityEvent)onClick2).AddListener((UnityAction)obj2);
					}
				}
			}
			_lastFilterText = string.Empty;
			ChestFilter.Clear();
			ChestSort.ResetSession();
		}

		private static void ApplyFrameLayout(InventoryGui gui)
		{
			if (!_expanded)
			{
				GrowDown(gui.m_container, 44f);
				GrowDown(FindBackground(gui.m_container), 44f);
				ShiftDown(GetGridShiftTarget(gui), 44f);
				_expanded = true;
			}
			PositionToolbar(gui);
		}

		private static void RestoreFrame(InventoryGui gui)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (!_expanded || (Object)gui == (Object)null || (Object)gui.m_container == (Object)null)
			{
				_expanded = false;
				return;
			}
			GrowDown(gui.m_container, -44f);
			GrowDown(FindBackground(gui.m_container), -44f);
			ShiftDown(GetGridShiftTarget(gui), -44f);
			_expanded = false;
		}

		private static void PositionToolbar(InventoryGui gui)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)_root == (Object)null))
			{
				RectTransform container = gui.m_container;
				RectTransform component = _root.GetComponent<RectTransform>();
				component.anchorMin = new Vector2(0f, 1f);
				component.anchorMax = new Vector2(1f, 1f);
				component.pivot = new Vector2(0.5f, 1f);
				component.offsetMin = new Vector2(10f, component.offsetMin.y);
				component.offsetMax = new Vector2(-10f, component.offsetMax.y);
				float headerBottomLocalY = GetHeaderBottomLocalY(gui, container);
				Vector2 anchoredPosition = component.anchoredPosition;
				anchoredPosition.y = LocalYToTopOffset(container, headerBottomLocalY) - 2f;
				component.anchoredPosition = anchoredPosition;
				Vector2 sizeDelta = component.sizeDelta;
				sizeDelta.y = 44f;
				component.sizeDelta = sizeDelta;
			}
		}

		private static float LocalYToTopOffset(RectTransform container, float localY)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = container.rect;
			float height = ((Rect)(ref rect)).height;
			float y = container.pivot.y;
			float num = (1f - y) * height;
			return localY - num;
		}

		private static float GetHeaderBottomLocalY(InventoryGui gui, RectTransform container)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			float lowest = float.PositiveInfinity;
			ConsiderHeader((Component)(object)gui.m_stackAllButton, container, ref lowest);
			ConsiderHeader((Component)(object)gui.m_takeAllButton, container, ref lowest);
			ConsiderHeader((Component)(object)gui.m_containerName, container, ref lowest);
			if (float.IsPositiveInfinity(lowest))
			{
				Rect rect = container.rect;
				float height = ((Rect)(ref rect)).height;
				return (1f - container.pivot.y) * height - 36f;
			}
			return lowest;
		}

		private static void ConsiderHeader(Component component, RectTransform container, ref float lowest)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)component == (Object)null)
			{
				return;
			}
			RectTransform component2 = component.GetComponent<RectTransform>();
			if (!((Object)component2 == (Object)null) && ((Component)component2).gameObject.activeInHierarchy)
			{
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				component2.GetWorldCorners(array);
				Vector3 val = ((Transform)container).InverseTransformPoint(array[0]);
				if (val.y < lowest)
				{
					lowest = val.y;
				}
			}
		}

		private static RectTransform GetGridShiftTarget(InventoryGui gui)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0047: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_0079: Expected O, but got Unknown
			InventoryGrid val = GameAccess.Get<InventoryGrid>(gui, "m_containerGrid");
			if ((Object)val == (Object)null)
			{
				return null;
			}
			RectTransform component = ((Component)val).GetComponent<RectTransform>();
			if ((Object)component != (Object)null && (Object)component != (Object)gui.m_container)
			{
				return component;
			}
			if ((Object)val.m_gridRoot != (Object)null && (Object)val.m_gridRoot != (Object)gui.m_container)
			{
				return val.m_gridRoot;
			}
			return null;
		}

		private static RectTransform FindBackground(RectTransform container)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0052: Expected O, but got Unknown
			if ((Object)container == (Object)null)
			{
				return null;
			}
			Transform val = ((Transform)container).Find("Bkg");
			if ((Object)val == (Object)null)
			{
				return null;
			}
			RectTransform val2 = (RectTransform)(object)((val is RectTransform) ? val : null);
			if ((Object)val2 == (Object)null || (Object)val2 == (Object)container)
			{
				return null;
			}
			return val2;
		}

		private static void GrowDown(RectTransform rt, float extra)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)rt == (Object)null))
			{
				if (!Mathf.Approximately(rt.anchorMin.y, rt.anchorMax.y))
				{
					Vector2 offsetMin = rt.offsetMin;
					offsetMin.y -= extra;
					rt.offsetMin = offsetMin;
				}
				else
				{
					Rect rect = rt.rect;
					float height = ((Rect)(ref rect)).height;
					rt.SetSizeWithCurrentAnchors((Axis)1, height + extra);
					rt.anchoredPosition += new Vector2(0f, (0f - extra) * (1f - rt.pivot.y));
				}
			}
		}

		private static void ShiftDown(RectTransform rt, float extra)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)rt == (Object)null))
			{
				rt.anchoredPosition += new Vector2(0f, 0f - extra);
			}
		}

		private static void DestroyWidgets()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			SyncInputBlock(shouldBlock: false);
			_filterInput = null;
			_clearButton = null;
			_lastFilterText = string.Empty;
			if ((Object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
				_root = null;
			}
		}

		private static void SyncInputBlock(bool shouldBlock)
		{
			if (_inputBlocked != shouldBlock)
			{
				GUIManager.BlockInput(shouldBlock);
				_inputBlocked = shouldBlock;
			}
		}

		private static void SyncFilterField()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			if (!((Object)_filterInput == (Object)null))
			{
				string text = _filterInput.text ?? string.Empty;
				if (!(text == _lastFilterText))
				{
					OnFilterChanged(text);
				}
			}
		}

		private static void OnFilterChanged(string text)
		{
			string text2 = text ?? string.Empty;
			if (!(text2 == _lastFilterText))
			{
				_lastFilterText = text2;
				ChestFilter.SetQuery(text2);
				RefreshClearButton();
				RefreshContainerGrid();
			}
		}

		private static void OnClearClicked()
		{
			ResetFilterText();
		}

		private static void OnSortClicked()
		{
			ChestSort.SortCurrent(InventoryGui.instance);
			RefreshContainerGrid();
		}

		private static void RefreshClearButton()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			if ((Object)_clearButton != (Object)null)
			{
				((Selectable)_clearButton).interactable = ChestFilter.HasQuery;
			}
		}

		private static void RefreshContainerGrid()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			InventoryGrid val = GameAccess.Get<InventoryGrid>(instance, "m_containerGrid");
			if ((Object)instance == (Object)null || (Object)val == (Object)null)
			{
				return;
			}
			Container val2 = GameAccess.Get<Container>(instance, "m_currentContainer");
			if (!((Object)val2 == (Object)null))
			{
				Inventory inventory = val2.GetInventory();
				if (inventory != null)
				{
					ItemData val3 = GameAccess.Get<ItemData>(instance, "m_dragItem");
					val.UpdateInventory(inventory, Player.m_localPlayer, val3);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
	internal static class InventoryGui_UpdateContainer_Patch
	{
		private static void Postfix(InventoryGui __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (!((Object)__instance == (Object)null) && !((Object)GameAccess.Get<Container>(__instance, "m_currentContainer") == (Object)null))
			{
				ChestPanelUi.EnsureControls(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
	internal static class InventoryGui_CloseContainer_Patch
	{
		private static void Postfix(InventoryGui __instance)
		{
			ChestFilter.Clear();
			ChestSort.ResetSession();
			ChestPanelUi.DestroyControls(__instance);
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateInventory")]
	internal static class InventoryGrid_UpdateInventory_Patch
	{
		private static void Postfix(InventoryGrid __instance, Inventory inventory)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_002f: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			InventoryGrid val = GameAccess.Get<InventoryGrid>(instance, "m_containerGrid");
			if (!((Object)instance == (Object)null) && !((Object)__instance != (Object)val))
			{
				ChestFilter.ApplyToGrid(__instance, inventory);
			}
		}
	}
	internal static class ChestSort
	{
		private static bool _reverse;

		internal static void ResetSession()
		{
			_reverse = false;
		}

		internal static void SortCurrent(InventoryGui gui)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)gui == (Object)null)
			{
				return;
			}
			if (IsDragging(gui))
			{
				Say("Cannot sort while dragging an item.");
				return;
			}
			Container val = GameAccess.Get<Container>(gui, "m_currentContainer");
			if ((Object)val == (Object)null)
			{
				return;
			}
			if (!val.IsOwner())
			{
				Say("Cannot sort: not the chest owner.");
				return;
			}
			Inventory inventory = val.GetInventory();
			if (inventory != null)
			{
				MergeStacks(inventory);
				List<ItemData> list = new List<ItemData>(inventory.GetAllItems());
				list.Sort(CompareItems);
				if (_reverse)
				{
					list.Reverse();
				}
				int width = inventory.GetWidth();
				for (int i = 0; i < list.Count; i++)
				{
					list[i].m_gridPos = new Vector2i(i % width, i / width);
				}
				GameAccess.Call(inventory, "Changed", true, false);
				_reverse = !_reverse;
				if (SonicChestFiltersPlugin.DebugEnabled)
				{
					SonicChestFiltersPlugin.Debug($"Sorted {list.Count} item stacks (reverse={_reverse}).");
				}
			}
		}

		private static int CompareItems(ItemData a, ItemData b)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected I4, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected I4, but got Unknown
			int num = ((int)a.m_shared.m_itemType).CompareTo((int)b.m_shared.m_itemType);
			if (num != 0)
			{
				return num;
			}
			string strA = ItemMatch.GetLocalizedName(a.m_shared.m_name) ?? string.Empty;
			string strB = ItemMatch.GetLocalizedName(b.m_shared.m_name) ?? string.Empty;
			int num2 = string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
			if (num2 != 0)
			{
				return num2;
			}
			int num3 = b.m_quality.CompareTo(a.m_quality);
			if (num3 != 0)
			{
				return num3;
			}
			return string.Compare(a.m_shared.m_name, b.m_shared.m_name, StringComparison.OrdinalIgnoreCase);
		}

		private static void MergeStacks(Inventory inventory)
		{
			bool flag;
			do
			{
				flag = false;
				List<ItemData> allItems = inventory.GetAllItems();
				for (int i = 0; i < allItems.Count; i++)
				{
					if (flag)
					{
						break;
					}
					ItemData val = allItems[i];
					int maxStackSize = val.m_shared.m_maxStackSize;
					if (maxStackSize <= 1 || val.m_stack >= maxStackSize)
					{
						continue;
					}
					for (int j = i + 1; j < allItems.Count; j++)
					{
						ItemData val2 = allItems[j];
						if (!CanStackTogether(val, val2))
						{
							continue;
						}
						int num = maxStackSize - val.m_stack;
						if (num > 0)
						{
							int num2 = Mathf.Min(num, val2.m_stack);
							val.m_stack += num2;
							val2.m_stack -= num2;
							if (val2.m_stack <= 0)
							{
								inventory.RemoveItem(val2);
							}
							flag = true;
						}
						break;
					}
				}
			}
			while (flag);
		}

		private static bool CanStackTogether(ItemData source, ItemData target)
		{
			if (source == null || target == null || source.m_shared == null || target.m_shared == null)
			{
				return false;
			}
			if (source.m_shared.m_name != target.m_shared.m_name || source.m_quality != target.m_quality || source.m_variant != target.m_variant || source.m_worldLevel != target.m_worldLevel)
			{
				return false;
			}
			if (source.m_customData.Count != target.m_customData.Count)
			{
				return false;
			}
			foreach (KeyValuePair<string, string> customDatum in source.m_customData)
			{
				if (!target.m_customData.TryGetValue(customDatum.Key, out var value) || value != customDatum.Value)
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsDragging(InventoryGui gui)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			object obj = AccessToolsField(gui, "m_dragGo");
			Object val = (Object)((obj is Object) ? obj : null);
			if (val != null && val != (Object)null)
			{
				return true;
			}
			return AccessToolsField(gui, "m_dragItem") != null;
		}

		private static object AccessToolsField(object instance, string name)
		{
			return AccessTools.Field(instance.GetType(), name)?.GetValue(instance);
		}

		private static void Say(string message)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if ((Object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
			else if ((Object)Chat.instance != (Object)null)
			{
				((Terminal)Chat.instance).AddString(message);
			}
		}
	}
	internal static class GameAccess
	{
		internal static T Get<T>(object instance, string fieldName) where T : class
		{
			if (instance == null)
			{
				return null;
			}
			return AccessTools.Field(instance.GetType(), fieldName)?.GetValue(instance) as T;
		}

		internal static object Get(object instance, string fieldName)
		{
			if (instance == null)
			{
				return null;
			}
			return AccessTools.Field(instance.GetType(), fieldName)?.GetValue(instance);
		}

		internal static void Call(object instance, string methodName, params object[] args)
		{
			if (instance != null)
			{
				MethodInfo methodInfo = AccessTools.Method(instance.GetType(), methodName, (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					methodInfo.Invoke(instance, BindArguments(methodInfo, args));
				}
			}
		}

		private static object[] BindArguments(MethodInfo method, object[] args)
		{
			ParameterInfo[] parameters = method.GetParameters();
			if (parameters.Length == 0)
			{
				return null;
			}
			object[] array = new object[parameters.Length];
			for (int i = 0; i < parameters.Length; i++)
			{
				if (args != null && i < args.Length)
				{
					array[i] = args[i];
					continue;
				}
				if (parameters[i].HasDefaultValue)
				{
					array[i] = parameters[i].DefaultValue;
					continue;
				}
				Type parameterType = parameters[i].ParameterType;
				array[i] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null);
			}
			return array;
		}
	}
	internal static class ItemLocate
	{
		private sealed class HighlightedChest
		{
			private readonly List<RendererGlow> _renderers = new List<RendererGlow>();

			internal static HighlightedChest TryCreate(Container container)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Expected O, but got Unknown
				Renderer[] componentsInChildren = ((Component)container).GetComponentsInChildren<Renderer>(true);
				if (componentsInChildren == null || componentsInChildren.Length == 0)
				{
					return null;
				}
				HighlightedChest highlightedChest = new HighlightedChest();
				foreach (Renderer val in componentsInChildren)
				{
					if (!((Object)val == (Object)null) && !(val is ParticleSystemRenderer))
					{
						RendererGlow rendererGlow = RendererGlow.TryCreate(val);
						if (rendererGlow != null)
						{
							highlightedChest._renderers.Add(rendererGlow);
						}
					}
				}
				if (highlightedChest._renderers.Count == 0)
				{
					return null;
				}
				return highlightedChest;
			}

			internal void ApplyGlow(Color color)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				for (int i = 0; i < _renderers.Count; i++)
				{
					_renderers[i].Apply(color);
				}
			}

			internal void Restore()
			{
				for (int i = 0; i < _renderers.Count; i++)
				{
					_renderers[i].Restore();
				}
				_renderers.Clear();
			}
		}

		private sealed class RendererGlow
		{
			private readonly Renderer _renderer;

			private readonly bool _usedMaterialInstances;

			private readonly Material[] _originalSharedMaterials;

			private readonly Material[] _instancedMaterials;

			private readonly Color[] _originalEmission;

			private readonly bool[] _hadEmissionKeyword;

			private RendererGlow(Renderer renderer, bool usedMaterialInstances, Material[] originalSharedMaterials, Material[] instancedMaterials, Color[] originalEmission, bool[] hadEmissionKeyword)
			{
				_renderer = renderer;
				_usedMaterialInstances = usedMaterialInstances;
				_originalSharedMaterials = originalSharedMaterials;
				_instancedMaterials = instancedMaterials;
				_originalEmission = originalEmission;
				_hadEmissionKeyword = hadEmissionKeyword;
			}

			internal static RendererGlow TryCreate(Renderer renderer)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Expected O, but got Unknown
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Expected O, but got Unknown
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_011e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0129: Expected O, but got Unknown
				//IL_012f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0138: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: Expected O, but got Unknown
				//IL_0142: Expected O, but got Unknown
				Material[] sharedMaterials = renderer.sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					return null;
				}
				renderer.GetPropertyBlock(PropertyBlock);
				PropertyBlock.SetColor("_EmissionColor", Color.black);
				renderer.SetPropertyBlock(PropertyBlock);
				if (SupportsEmissionViaPropertyBlock(renderer))
				{
					return new RendererGlow(renderer, usedMaterialInstances: false, null, null, null, null);
				}
				Material[] array = (Material[])(object)new Material[sharedMaterials.Length];
				Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length];
				Color[] array3 = (Color[])(object)new Color[sharedMaterials.Length];
				bool[] array4 = new bool[sharedMaterials.Length];
				bool flag = false;
				for (int i = 0; i < sharedMaterials.Length; i++)
				{
					Material val = (array[i] = sharedMaterials[i]);
					if ((Object)val == (Object)null)
					{
						array2[i] = val;
						continue;
					}
					Material val2 = (array2[i] = new Material(val));
					array4[i] = val2.IsKeywordEnabled("_EMISSION");
					if (val2.HasProperty("_EmissionColor"))
					{
						array3[i] = val2.GetColor("_EmissionColor");
						val2.EnableKeyword("_EMISSION");
						flag = true;
					}
					else
					{
						array3[i] = Color.black;
					}
				}
				if (!flag)
				{
					for (int j = 0; j < array2.Length; j++)
					{
						if ((Object)array2[j] != (Object)null && (Object)array2[j] != (Object)array[j])
						{
							Object.Destroy((Object)(object)array2[j]);
						}
					}
					return null;
				}
				renderer.materials = array2;
				return new RendererGlow(renderer, usedMaterialInstances: true, array, array2, array3, array4);
			}

			private static bool SupportsEmissionViaPropertyBlock(Renderer renderer)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Expected O, but got Unknown
				Material[] sharedMaterials = renderer.sharedMaterials;
				foreach (Material val in sharedMaterials)
				{
					if ((Object)val != (Object)null && val.HasProperty("_EmissionColor"))
					{
						return true;
					}
				}
				return false;
			}

			internal void Apply(Color color)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Expected O, but got Unknown
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)_renderer == (Object)null)
				{
					return;
				}
				if (!_usedMaterialInstances)
				{
					_renderer.GetPropertyBlock(PropertyBlock);
					PropertyBlock.SetColor("_EmissionColor", color);
					_renderer.SetPropertyBlock(PropertyBlock);
				}
				else
				{
					if (_instancedMaterials == null)
					{
						return;
					}
					for (int i = 0; i < _instancedMaterials.Length; i++)
					{
						Material val = _instancedMaterials[i];
						if ((Object)val != (Object)null && val.HasProperty("_EmissionColor"))
						{
							val.SetColor("_EmissionColor", color);
						}
					}
				}
			}

			internal void Restore()
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Expected O, but got Unknown
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)_renderer == (Object)null)
				{
					return;
				}
				if (!_usedMaterialInstances)
				{
					_renderer.GetPropertyBlock(PropertyBlock);
					PropertyBlock.SetColor("_EmissionColor", Color.black);
					_renderer.SetPropertyBlock(PropertyBlock);
					return;
				}
				if (_originalSharedMaterials != null)
				{
					_renderer.sharedMaterials = _originalSharedMaterials;
				}
				if (_instancedMaterials == null)
				{
					return;
				}
				for (int i = 0; i < _instancedMaterials.Length; i++)
				{
					Material val = _instancedMaterials[i];
					if (!((Object)val == (Object)null))
					{
						if (_originalEmission != null && val.HasProperty("_EmissionColor"))
						{
							val.SetColor("_EmissionColor", _originalEmission[i]);
						}
						if (_hadEmissionKeyword != null && !_hadEmissionKeyword[i])
						{
							val.DisableKeyword("_EMISSION");
						}
						Object.Destroy((Object)(object)val);
					}
				}
			}
		}

		private const string EmissionColorProperty = "_EmissionColor";

		private static readonly List<HighlightedChest> Active = new List<HighlightedChest>();

		private static readonly MaterialPropertyBlock PropertyBlock = new MaterialPropertyBlock();

		private static bool _commandRegistered;

		private static float _activeUntil = -1f;

		private static Color _baseGlow = new Color(1f, 0.85f, 0.2f, 1f);

		internal static bool IsActive => SonicChestFiltersPlugin.LocateIsActive;

		internal static void RegisterCommand()
		{
			if (!_commandRegistered && IsActive && CommandManager.Instance != null)
			{
				_commandRegistered = true;
				CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new LocateCommand());
			}
		}

		internal static List<string> CommandOptions()
		{
			return new List<string> { "clear" };
		}

		internal static void ClearHighlights()
		{
			for (int i = 0; i < Active.Count; i++)
			{
				Active[i].Restore();
			}
			Active.Clear();
			_activeUntil = -1f;
		}

		internal static void Tick()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActive || Active.Count == 0)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= _activeUntil)
			{
				ClearHighlights();
				return;
			}
			float num = 0.45f + 0.55f * (0.5f + 0.5f * Mathf.Sin(realtimeSinceStartup * 5f));
			Color color = _baseGlow * num;
			color.a = 1f;
			for (int i = 0; i < Active.Count; i++)
			{
				Active[i].ApplyGlow(color);
			}
		}

		internal static void OnCommand(string[] args, Terminal context)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			if (!IsActive)
			{
				Say("Item locate is disabled.", context);
				return;
			}
			if (args != null && args.Length >= 1 && string.Equals(args[0], "clear", StringComparison.OrdinalIgnoreCase))
			{
				ClearHighlights();
				Say("Cleared nearby chest highlights.", context);
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)localPlayer == (Object)null)
			{
				Say("No local player.", context);
				return;
			}
			string pattern;
			string displayName;
			if (args == null || args.Length == 0)
			{
				if (!TryGetHeldItemPattern(localPlayer, out pattern, out displayName))
				{
					Say("Hold an item or use: locate <item name>", context);
					return;
				}
			}
			else
			{
				pattern = string.Join(" ", args).Trim();
				if (pattern.Length == 0)
				{
					Say("Usage: locate [item|*pattern*|clear]", context);
					return;
				}
				displayName = pattern;
			}
			SearchAndHighlight(localPlayer, pattern, displayName, context);
		}

		private static bool TryGetHeldItemPattern(Player player, out string pattern, out string displayName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			pattern = string.Empty;
			displayName = string.Empty;
			Humanoid val = (Humanoid)player;
			ItemData val2 = val.RightItem ?? val.LeftItem;
			if (val2?.m_shared == null)
			{
				return false;
			}
			string text = null;
			if ((Object)val2.m_dropPrefab != (Object)null)
			{
				text = ((Object)val2.m_dropPrefab).name;
			}
			if (!string.IsNullOrEmpty(text))
			{
				pattern = text;
				displayName = text;
				return true;
			}
			pattern = val2.m_shared.m_name;
			displayName = ItemMatch.FormatDisplayName(val2.m_shared.m_name);
			return !string.IsNullOrEmpty(pattern);
		}

		private static void SearchAndHighlight(Player player, string pattern, string displayName, Terminal context)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			ClearHighlights();
			_baseGlow = ParseGlowColor(SonicChestFiltersPlugin.ItemLocateGlowColor?.Value);
			int num = ((SonicChestFiltersPlugin.ItemLocateMaxHighlights != null) ? Mathf.Clamp(SonicChestFiltersPlugin.ItemLocateMaxHighlights.Value, 1, 50) : 10);
			float num2 = ((SonicChestFiltersPlugin.ItemLocateDurationSeconds != null) ? Mathf.Clamp(SonicChestFiltersPlugin.ItemLocateDurationSeconds.Value, 3f, 120f) : 15f);
			List<Container> list = NearbyContainers.Get(player);
			int num3 = 0;
			List<string> list2 = new List<string>();
			for (int i = 0; i < list.Count; i++)
			{
				Container val = list[i];
				if ((Object)val == (Object)null)
				{
					continue;
				}
				Inventory inventory;
				try
				{
					inventory = val.GetInventory();
				}
				catch
				{
					continue;
				}
				if (inventory == null || !InventoryContains(inventory, pattern, list2))
				{
					continue;
				}
				num3++;
				if (Active.Count < num)
				{
					HighlightedChest highlightedChest = HighlightedChest.TryCreate(val);
					if (highlightedChest != null)
					{
						Active.Add(highlightedChest);
					}
				}
			}
			string arg = ((list2.Count > 0) ? string.Join(", ", list2) : ItemMatch.FormatDisplayName(displayName));
			if (num3 == 0)
			{
				Say("No nearby chests contain " + ItemMatch.FormatDisplayName(displayName) + ".", context);
				return;
			}
			_activeUntil = Time.realtimeSinceStartup + num2;
			Tick();
			if (num3 > Active.Count)
			{
				Say($"Found {arg} in {num3} chests (showing nearest {Active.Count}).", context);
			}
			else
			{
				Say($"Found {arg} in {num3} chests.", context);
			}
			if (SonicChestFiltersPlugin.DebugEnabled)
			{
				SonicChestFiltersPlugin.Debug($"Item locate '{pattern}': matches={num3}, glowing={Active.Count}, duration={num2:0.#}s.");
			}
		}

		private static bool InventoryContains(Inventory inventory, string pattern, List<string> matchedLabels)
		{
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null || allItems.Count == 0)
			{
				return false;
			}
			bool result = false;
			for (int i = 0; i < allItems.Count; i++)
			{
				if (ItemMatch.ItemMatchesPattern(allItems[i], pattern, out var matchedLabel))
				{
					result = true;
					AddUniqueLabel(matchedLabels, matchedLabel);
				}
			}
			return result;
		}

		private static void AddUniqueLabel(List<string> labels, string label)
		{
			if (string.IsNullOrEmpty(label))
			{
				return;
			}
			for (int i = 0; i < labels.Count; i++)
			{
				if (string.Equals(labels[i], label, StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			labels.Add(label);
		}

		private static Color ParseGlowColor(string raw)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			((Color)(ref result))..ctor(1f, 0.85f, 0.2f, 1f);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return result;
			}
			string[] array = raw.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length < 3)
			{
				return result;
			}
			if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4))
			{
				return result;
			}
			return new Color(Mathf.Clamp01(result2), Mathf.Clamp01(result3), Mathf.Clamp01(result4), 1f);
		}

		private static void Say(string message, Terminal context)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if ((Object)context != (Object)null)
			{
				context.AddString(message);
			}
			else if ((Object)Chat.instance != (Object)null)
			{
				((Terminal)Chat.instance).AddString(message);
			}
			else if (SonicChestFiltersPlugin.ModLogger != null)
			{
				SonicChestFiltersPlugin.ModLogger.LogInfo((object)message);
			}
		}
	}
	internal sealed class LocateCommand : ConsoleCommand
	{
		public override string Name => "locate";

		public override string Help => "[item|clear] Highlight nearby eligible chests containing an item (or clear). No args uses held item.";

		public override void Run(string[] args, Terminal context)
		{
			ItemLocate.OnCommand(args, context);
		}

		public override List<string> CommandOptionList()
		{
			return ItemLocate.CommandOptions();
		}
	}
	internal static class ItemMatch
	{
		private static Func<string, string> _localizeName;

		private static bool _localizeResolved;

		internal static bool NameMatches(string value, string pattern)
		{
			if (string.IsNullOrEmpty(pattern))
			{
				return false;
			}
			if (pattern.IndexOf('*') < 0)
			{
				return string.Equals(value, pattern, StringComparison.OrdinalIgnoreCase);
			}
			string[] array = pattern.Split('*');
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				if (text.Length == 0)
				{
					continue;
				}
				if (i == 0)
				{
					if (!value.StartsWith(text, StringComparison.OrdinalIgnoreCase))
					{
						return false;
					}
					num = text.Length;
					continue;
				}
				if (i == array.Length - 1 && pattern[pattern.Length - 1] != '*')
				{
					if (!value.EndsWith(text, StringComparison.OrdinalIgnoreCase))
					{
						return false;
					}
					return value.Length - text.Length >= num;
				}
				int num2 = value.IndexOf(text, num, StringComparison.OrdinalIgnoreCase);
				if (num2 < 0)
				{
					return false;
				}
				num = num2 + text.Length;
			}
			return true;
		}

		internal static bool LocateNameMatches(string value, string pattern)
		{
			if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(pattern))
			{
				return false;
			}
			if (NameMatches(value, pattern))
			{
				return true;
			}
			string text = pattern.Replace("*", string.Empty).Trim();
			if (text.Length == 0)
			{
				return false;
			}
			return value.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		internal static bool ItemMatchesPattern(ItemData item, string pattern, out string matchedLabel)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			matchedLabel = string.Empty;
			if (item?.m_shared == null || string.IsNullOrWhiteSpace(pattern))
			{
				return false;
			}
			string name = item.m_shared.m_name;
			string localizedName = GetLocalizedName(name);
			if (!string.IsNullOrEmpty(localizedName) && LocateNameMatches(localizedName, pattern))
			{
				matchedLabel = localizedName;
				return true;
			}
			if (!string.IsNullOrEmpty(name) && LocateNameMatches(name, pattern))
			{
				matchedLabel = ((!string.IsNullOrEmpty(localizedName)) ? localizedName : FormatDisplayName(name));
				return true;
			}
			if (!string.IsNullOrEmpty(name) && name[0] == '$' && LocateNameMatches(name.Substring(1), pattern))
			{
				matchedLabel = ((!string.IsNullOrEmpty(localizedName)) ? localizedName : FormatDisplayName(name));
				return true;
			}
			if ((Object)item.m_dropPrefab != (Object)null)
			{
				string name2 = ((Object)item.m_dropPrefab).name;
				if (!string.IsNullOrEmpty(name2) && LocateNameMatches(name2, pattern))
				{
					matchedLabel = ((!string.IsNullOrEmpty(localizedName)) ? localizedName : name2);
					return true;
				}
			}
			return false;
		}

		internal static string GetLocalizedName(string sharedName)
		{
			if (string.IsNullOrEmpty(sharedName))
			{
				return sharedName;
			}
			EnsureLocalizeResolver();
			if (_localizeName == null)
			{
				return FormatDisplayName(sharedName);
			}
			try
			{
				string text = _localizeName(sharedName);
				if (!string.IsNullOrEmpty(text) && text[0] != '$')
				{
					return text;
				}
			}
			catch
			{
			}
			return FormatDisplayName(sharedName);
		}

		internal static string FormatDisplayName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return name;
			}
			if (name.StartsWith("$item_", StringComparison.OrdinalIgnoreCase) && name.Length > 6)
			{
				string text = name.Substring(6);
				if (text.Length == 0)
				{
					return name;
				}
				return char.ToUpperInvariant(text[0]) + text.Substring(1);
			}
			if (name.StartsWith("$", StringComparison.Ordinal) && name.Length > 1)
			{
				return name.Substring(1);
			}
			return name;
		}

		private static void EnsureLocalizeResolver()
		{
			if (_localizeResolved)
			{
				return;
			}
			_localizeResolved = true;
			try
			{
				Type type = AccessTools.TypeByName("Localization");
				if (type == null)
				{
					return;
				}
				MethodInfo getInstance = AccessTools.PropertyGetter(type, "instance");
				MethodInfo localize = AccessTools.Method(type, "Localize", new Type[1] { typeof(string) }, (Type[])null);
				if (getInstance == null || localize == null)
				{
					localize = AccessTools.Method(type, "Translate", new Type[1] { typeof(string) }, (Type[])null);
				}
				if (!(getInstance == null) && !(localize == null))
				{
					_localizeName = delegate(string token)
					{
						object obj = getInstance.Invoke(null, null);
						return (obj == null) ? token : ((localize.Invoke(obj, new object[1] { token }) as string) ?? token);
					};
				}
			}
			catch (Exception ex)
			{
				SonicChestFiltersPlugin.Debug("Localization resolver failed: " + ex.Message);
			}
		}
	}
	internal static class ModLocalization
	{
		internal const string FilterPlaceholder = "$sonic_chestfilters_filter";

		internal const string Clear = "$sonic_chestfilters_clear";

		internal const string Sort = "$sonic_chestfilters_sort";

		internal static void Register()
		{
			if (LocalizationManager.Instance != null)
			{
				CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
				string text = "$sonic_chestfilters_filter";
				localization.AddTranslation(ref text, "Filter...");
				text = "$sonic_chestfilters_clear";
				localization.AddTranslation(ref text, "Clear");
				text = "$sonic_chestfilters_sort";
				localization.AddTranslation(ref text, "Sort");
			}
		}

		internal static string Translate(string token, string fallback)
		{
			if (LocalizationManager.Instance != null)
			{
				string text = LocalizationManager.Instance.TryTranslate(token);
				if (!string.IsNullOrEmpty(text) && text[0] != '[' && text != token)
				{
					return text;
				}
			}
			if (Localization.instance != null)
			{
				string text2 = Localization.instance.Localize(token);
				if (!string.IsNullOrEmpty(text2) && text2 != token)
				{
					return text2;
				}
			}
			return fallback;
		}
	}
	internal readonly struct ContainerTraits
	{
		internal readonly Container Container;

		internal readonly bool HasPiece;

		internal readonly bool IsMoving;

		internal readonly bool IsIncinerator;

		internal ContainerTraits(Container container, bool hasPiece, bool isMoving, bool isIncinerator)
		{
			Container = container;
			HasPiece = hasPiece;
			IsMoving = isMoving;
			IsIncinerator = isIncinerator;
		}
	}
	internal readonly struct ContainerDistance
	{
		internal readonly Container Container;

		internal readonly float DistanceSq;

		internal ContainerDistance(Container container, float distanceSq)
		{
			Container = container;
			DistanceSq = distanceSq;
		}
	}
	internal static class NearbyContainers
	{
		private static readonly List<Container> CachedContainers = new List<Container>();

		private static readonly List<ContainerDistance> ScanBuffer = new List<ContainerDistance>();

		private static readonly Dictionary<int, ContainerTraits> TraitCache = new Dictionary<int, ContainerTraits>();

		private static Player _cachedPlayer;

		private static Vector3 _cachedPlayerPosition;

		private static float _containerCacheCreatedAt = -1000f;

		private static float _cachedRange = -1f;

		private static bool _cachedRequirePiece;

		private static bool _cachedIgnoreMoving;

		private static bool _cachedIgnoreObliterators;

		private static bool _cachedBalrondCompatibility;

		internal static void InvalidateAll()
		{
			CachedContainers.Clear();
			ScanBuffer.Clear();
			TraitCache.Clear();
			_cachedPlayer = null;
			_containerCacheCreatedAt = -1000f;
			_cachedRange = -1f;
		}

		internal static List<Container> Get(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if ((Object)player == (Object)null)
			{
				return CachedContainers;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (ContainerCacheIsValid(player, realtimeSinceStartup))
			{
				return CachedContainers;
			}
			RefreshContainerCache(player, realtimeSinceStartup);
			return CachedContainers;
		}

		private static bool ContainerCacheIsValid(Player player, float now)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0015: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)_cachedPlayer != (Object)player)
			{
				return false;
			}
			if (now - _containerCacheCreatedAt >= 0.5f)
			{
				return false;
			}
			Vector3 val = ((Component)player).transform.position - _cachedPlayerPosition;
			if (((Vector3)(ref val)).sqrMagnitude >= 1f)
			{
				return false;
			}
			if (SonicChestFiltersPlugin.ContainerRange == null)
			{
				return false;
			}
			if (!Mathf.Approximately(_cachedRange, SonicChestFiltersPlugin.ContainerRange.Value))
			{
				return false;
			}
			if (_cachedRequirePiece != SonicChestFiltersPlugin.RequirePlayerPlacedContainer.Value || _cachedIgnoreMoving != SonicChestFiltersPlugin.IgnoreMovingContainers.Value || _cachedIgnoreObliterators != SonicChestFiltersPlugin.IgnoreObliterators.Value || _cachedBalrondCompatibility != SonicChestFiltersPlugin.BalrondCompatibility.Value)
			{
				return false;
			}
			return true;
		}

		private static void RefreshContainerCache(Player player, float now)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			CachedContainers.Clear();
			ScanBuffer.Clear();
			PruneTraitCache();
			float num = Mathf.Max(0f, SonicChestFiltersPlugin.ContainerRange.Value);
			float num2 = num * num;
			Vector3 position = ((Component)player).transform.position;
			float num3 = (SonicChestFiltersPlugin.DebugEnabled ? Time.realtimeSinceStartup : 0f);
			Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
			Container[] array2 = array;
			foreach (Container val in array2)
			{
				if ((Object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled)
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - position;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (sqrMagnitude > num2)
				{
					continue;
				}
				ContainerTraits traits = GetTraits(val);
				if ((SonicChestFiltersPlugin.IgnoreObliterators.Value && traits.IsIncinerator) || (SonicChestFiltersPlugin.RequirePlayerPlacedContainer.Value && !traits.HasPiece) || ShouldIgnoreMovingContainer(val, traits))
				{
					continue;
				}
				try
				{
					if (val.GetInventory() == null)
					{
						continue;
					}
				}
				catch (Exception)
				{
					continue;
				}
				ScanBuffer.Add(new ContainerDistance(val, sqrMagnitude));
			}
			ScanBuffer.Sort((ContainerDistance a, ContainerDistance b) => a.DistanceSq.CompareTo(b.DistanceSq));
			for (int num4 = 0; num4 < ScanBuffer.Count; num4++)
			{
				CachedContainers.Add(ScanBuffer[num4].Container);
			}
			_cachedPlayer = player;
			_cachedPlayerPosition = position;
			_containerCacheCreatedAt = now;
			_cachedRange = SonicChestFiltersPlugin.ContainerRange.Value;
			_cachedRequirePiece = SonicChestFiltersPlugin.RequirePlayerPlacedContainer.Value;
			_cachedIgnoreMoving = SonicChestFiltersPlugin.IgnoreMovingContainers.Value;
			_cachedIgnoreObliterators = SonicChestFiltersPlugin.IgnoreObliterators.Value;
			_cachedBalrondCompatibility = SonicChestFiltersPlugin.BalrondCompatibility.Value;
			if (SonicChestFiltersPlugin.DebugEnabled)
			{
				float num5 = (Time.realtimeSinceStartup - num3) * 1000f;
				SonicChestFiltersPlugin.Debug($"Container cache refreshed: scanned={array.Length}, eligible={CachedContainers.Count}, time={num5:0.00}ms.");
			}
		}

		private static void PruneTraitCache()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (TraitCache.Count == 0)
			{
				return;
			}
			List<int> list = null;
			foreach (KeyValuePair<int, ContainerTraits> item in TraitCache)
			{
				if ((Object)item.Value.Container == (Object)null)
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(item.Key);
				}
			}
			if (list != null)
			{
				for (int i = 0; i < list.Count; i++)
				{
					TraitCache.Remove(list[i]);
				}
			}
		}

		private static bool ShouldIgnoreMovingContainer(Container container, ContainerTraits traits)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			if (!traits.IsMoving || SonicChestFiltersPlugin.IgnoreMovingContainers == null || !SonicChestFiltersPlugin.IgnoreMovingContainers.Value)
			{
				return false;
			}
			try
			{
				Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(true);
				if ((Object)componentInParent != (Object)null)
				{
					if (componentInParent.InUse() || componentInParent.IsAttached())
					{
						return true;
					}
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static bool HasPlayerPlacedPiece(Container container)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			try
			{
				if ((Object)((Component)container).GetComponentInParent<Piece>() != (Object)null)
				{
					return true;
				}
				if (!SonicChestFiltersPlugin.BalrondCompatibility.Value)
				{
					return false;
				}
				Transform root = ((Component)container).transform.root;
				if ((Object)root == (Object)null)
				{
					return false;
				}
				Piece[] componentsInChildren = ((Component)root).GetComponentsInChildren<Piece>(true);
				return componentsInChildren != null && componentsInChildren.Length != 0;
			}
			catch
			{
				return false;
			}
		}

		private static ContainerTraits GetTraits(Container container)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			int instanceID = ((Object)container).GetInstanceID();
			if (TraitCache.TryGetValue(instanceID, out var value) && (Object)(object)value.Container == (Object)(object)container && (value.HasPiece || !SonicChestFiltersPlugin.BalrondCompatibility.Value))
			{
				return value;
			}
			bool hasPiece = HasPlayerPlacedPiece(container);
			bool flag = false;
			bool flag2 = false;
			try
			{
				if ((Object)((Component)container).GetComponentInParent<Incinerator>(true) != (Object)null)
				{
					flag2 = true;
				}
			}
			catch
			{
			}
			try
			{
				Component[] componentsInParent = ((Component)container).GetComponentsInParent<Component>(true);
				for (int i = 0; i < componentsInParent.Length; i++)
				{
					switch (((object)componentsInParent[i]).GetType().Name)
					{
					case "Ship":
					case "Vagon":
					case "Wagon":
						flag = true;
						break;
					case "Incinerator":
						flag2 = true;
						break;
					}
					if (flag && flag2)
					{
						break;
					}
				}
			}
			catch
			{
			}
			ContainerTraits containerTraits = new ContainerTraits(container, hasPiece, flag, flag2);
			TraitCache[instanceID] = containerTraits;
			return containerTraits;
		}
	}
	[BepInPlugin("com.sonicdm.valheim.sonicchestfilters", "Sonic Chest Filters", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class SonicChestFiltersPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.sonicdm.valheim.sonicchestfilters";

		public const string PluginName = "Sonic Chest Filters";

		public const string PluginVersion = "1.0.1";

		internal const string NearbyCraftingForkedGuid = "com.sonicdm.valheim.nearbycraftingforked";

		internal static ManualLogSource ModLogger;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> AutoReloadConfig;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<float> ContainerRange;

		internal static ConfigEntry<bool> RequirePlayerPlacedContainer;

		internal static ConfigEntry<bool> IgnoreMovingContainers;

		internal static ConfigEntry<bool> IgnoreObliterators;

		internal static ConfigEntry<bool> BalrondCompatibility;

		internal static ConfigEntry<bool> EnableFilterBox;

		internal static ConfigEntry<bool> EnableSortButton;

		internal static ConfigEntry<bool> ItemLocateEnabled;

		internal static ConfigEntry<int> ItemLocateMaxHighlights;

		internal static ConfigEntry<float> ItemLocateDurationSeconds;

		internal static ConfigEntry<string> ItemLocateGlowColor;

		private Harmony _harmony;

		private DateTime _configLastWriteUtc;

		private float _configWatchNextCheck;

		private DateTime _configPendingWriteUtc;

		private float _configPendingSince = -1f;

		private bool _loggedLocateSkip;

		internal static bool NearbyCraftingForkedPresent { get; private set; }

		internal static bool DebugEnabled
		{
			get
			{
				if (DebugLogging != null)
				{
					return DebugLogging.Value;
				}
				return false;
			}
		}

		internal static bool LocateIsActive
		{
			get
			{
				if (NearbyCraftingForkedPresent)
				{
					return false;
				}
				if (Enabled == null || !Enabled.Value)
				{
					return false;
				}
				if (ItemLocateEnabled != null)
				{
					return ItemLocateEnabled.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Expected O, but got Unknown
			ModLogger = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Sonic Chest Filters.");
			AutoReloadConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoReloadConfig", true, "Automatically reload this mod's config when the .cfg file changes on disk.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Write diagnostic information to BepInEx LogOutput.log.");
			ContainerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Containers", "ContainerRange", 20f, new ConfigDescription("Maximum distance in metres from the player when locating chests.", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			RequirePlayerPlacedContainer = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "RequirePlayerPlacedContainer", true, "Only locate containers attached to a Piece (normally player-built storage).");
			IgnoreMovingContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreMovingContainers", true, "Ignore ships, and ignore carts that are currently attached or in use. Parked carts stay eligible for locate.");
			IgnoreObliterators = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreObliterators", true, "Ignore Obliterators (Incinerator) when locating items.");
			BalrondCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "BalrondConstructions", true, "Recognize storage prefabs where Container and Piece are siblings under the same prefab root.");
			EnableFilterBox = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableFilterBox", true, "Show a live Valheim text box on the open chest to filter visible items.");
			EnableSortButton = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableSortButton", true, "Show a Sort button on the open chest.");
			ItemLocateEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Item Locate", "Enabled", true, "Enable the 'locate' console command. Ignored when Nearby Crafting Forked is loaded.");
			ItemLocateMaxHighlights = ((BaseUnityPlugin)this).Config.Bind<int>("Item Locate", "MaxHighlights", 10, new ConfigDescription("Maximum chests to glow (nearest first).", (AcceptableValueBase)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			ItemLocateDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Item Locate", "DurationSeconds", 15f, new ConfigDescription("How long chest glows last before auto-clear.", (AcceptableValueBase)new AcceptableValueRange<float>(3f, 120f), Array.Empty<object>()));
			ItemLocateGlowColor = ((BaseUnityPlugin)this).Config.Bind<string>("Item Locate", "GlowColor", "1,0.85,0.2", "Emission tint for highlighted chests as R,G,B in 0-1 range.");
			ModLocalization.Register();
			DetectNearbyCraftingForked();
			if (LocateIsActive)
			{
				ItemLocate.RegisterCommand();
			}
			ContainerRange.SettingChanged += OnContainerSettingChanged;
			RequirePlayerPlacedContainer.SettingChanged += OnContainerSettingChanged;
			IgnoreMovingContainers.SettingChanged += OnContainerSettingChanged;
			IgnoreObliterators.SettingChanged += OnContainerSettingChanged;
			BalrondCompatibility.SettingChanged += OnContainerSettingChanged;
			Enabled.SettingChanged += OnEnabledChanged;
			_configLastWriteUtc = GetConfigWriteTimeUtc();
			_harmony = new Harmony("com.sonicdm.valheim.sonicchestfilters");
			try
			{
				_harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Sonic Chest Filters 1.0.1 loaded.");
			}
			catch (Exception ex)
			{
				try
				{
					_harmony.UnpatchSelf();
				}
				catch
				{
				}
				Enabled.Value = false;
				((BaseUnityPlugin)this).Logger.LogError((object)"Sonic Chest Filters failed to apply its Harmony patches and has been disabled.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void Start()
		{
			DetectNearbyCraftingForked();
			if (LocateIsActive)
			{
				ItemLocate.RegisterCommand();
			}
		}

		private void DetectNearbyCraftingForked()
		{
			NearbyCraftingForkedPresent = Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("com.sonicdm.valheim.nearbycraftingforked");
			if (NearbyCraftingForkedPresent && !_loggedLocateSkip)
			{
				_loggedLocateSkip = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Item locate disabled: Nearby Crafting Forked is loaded (use nearby / locate).");
			}
		}

		private void Update()
		{
			WatchConfigFileForChanges();
			if (LocateIsActive)
			{
				ItemLocate.Tick();
			}
			ChestPanelUi.Tick();
		}

		private static void OnContainerSettingChanged(object sender, EventArgs e)
		{
			NearbyContainers.InvalidateAll();
			if (DebugEnabled)
			{
				Debug("Container-related configuration changed; caches invalidated.");
			}
		}

		private static void OnEnabledChanged(object sender, EventArgs e)
		{
			ResetRuntimeState();
		}

		internal static void ResetRuntimeState()
		{
			NearbyContainers.InvalidateAll();
			ItemLocate.ClearHighlights();
			ChestFilter.Clear();
			ChestSort.ResetSession();
			ChestPanelUi.ResetFilterText();
		}

		internal static void Debug(string message)
		{
			if (DebugEnabled && ModLogger != null)
			{
				ModLogger.LogInfo((object)("[DEBUG] " + message));
			}
		}

		private void WatchConfigFileForChanges()
		{
			if (AutoReloadConfig == null || !AutoReloadConfig.Value)
			{
				_configPendingSince = -1f;
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _configWatchNextCheck)
			{
				return;
			}
			_configWatchNextCheck = unscaledTime + 1f;
			DateTime configWriteTimeUtc = GetConfigWriteTimeUtc();
			if (!(configWriteTimeUtc == DateTime.MinValue))
			{
				if (configWriteTimeUtc == _configLastWriteUtc)
				{
					_configPendingSince = -1f;
				}
				else if (_configPendingSince < 0f || configWriteTimeUtc != _configPendingWriteUtc)
				{
					_configPendingWriteUtc = configWriteTimeUtc;
					_configPendingSince = unscaledTime;
				}
				else if (!(unscaledTime - _configPendingSince < 0.75f))
				{
					_configLastWriteUtc = configWriteTimeUtc;
					_configPendingSince = -1f;
					ReloadConfigFromDisk();
				}
			}
		}

		private DateTime GetConfigWriteTimeUtc()
		{
			try
			{
				string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
				if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath))
				{
					return DateTime.MinValue;
				}
				return File.GetLastWriteTimeUtc(configFilePath);
			}
			catch
			{
				return DateTime.MinValue;
			}
		}

		private void ReloadConfigFromDisk()
		{
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				_configLastWriteUtc = GetConfigWriteTimeUtc();
				_configPendingSince = -1f;
				ResetRuntimeState();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Sonic Chest Filters config reloaded from disk.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Sonic Chest Filters failed to reload config from disk.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void OnDestroy()
		{
			if (ContainerRange != null)
			{
				ContainerRange.SettingChanged -= OnContainerSettingChanged;
			}
			if (RequirePlayerPlacedContainer != null)
			{
				RequirePlayerPlacedContainer.SettingChanged -= OnContainerSettingChanged;
			}
			if (IgnoreMovingContainers != null)
			{
				IgnoreMovingContainers.SettingChanged -= OnContainerSettingChanged;
			}
			if (IgnoreObliterators != null)
			{
				IgnoreObliterators.SettingChanged -= OnContainerSettingChanged;
			}
			if (BalrondCompatibility != null)
			{
				BalrondCompatibility.SettingChanged -= OnContainerSettingChanged;
			}
			if (Enabled != null)
			{
				Enabled.SettingChanged -= OnEnabledChanged;
			}
			ResetRuntimeState();
			ChestPanelUi.DestroyControls();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}