Decompiled source of Rummage v1.0.0

Rummage.dll

Decompiled 5 days 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.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using PerfectRandom.Sulfur.Core;
using PerfectRandom.Sulfur.Core.Input;
using PerfectRandom.Sulfur.Core.Items;
using PerfectRandom.Sulfur.Core.Stats;
using PerfectRandom.Sulfur.Core.UI;
using PerfectRandom.Sulfur.Core.UI.Inventory;
using PerfectRandom.Sulfur.Core.World;
using Ryuka.Sulfur.Rummage.Config;
using Ryuka.Sulfur.Rummage.Diagnostics;
using Ryuka.Sulfur.Rummage.Filter;
using Ryuka.Sulfur.Rummage.Game;
using Ryuka.Sulfur.Rummage.InputGuard;
using Ryuka.Sulfur.Rummage.Localization;
using Ryuka.Sulfur.Rummage.Search;
using Ryuka.Sulfur.Rummage.Stashes;
using Ryuka.Sulfur.Rummage.UserInterface;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.TextCore;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Ryuka")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4ec07084b37f1edf901e833c815e5ed503dacb6b")]
[assembly: AssemblyProduct("Rummage")]
[assembly: AssemblyTitle("Rummage")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Ryuka.Sulfur.Rummage
{
	[BepInPlugin("ryuka.sulfur.rummage", "Rummage", "1.0.0")]
	public sealed class RummagePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ryuka.sulfur.rummage";

		public const string PluginName = "Rummage";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		private Harmony harmony;

		private PlayerSpawnSource playerSpawnSource;

		private LanguageWatcher languageWatcher;

		private RummageController controller;

		private void Awake()
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			DiagnosticsConfig diagnostics = new DiagnosticsConfig(((BaseUnityPlugin)this).Config);
			StashProbe.Initialize(diagnostics);
			EnchantmentCatalogProbe.Initialize(diagnostics);
			GameTermProbe.Initialize(diagnostics);
			DisplayConfig displayConfig = new DisplayConfig(((BaseUnityPlugin)this).Config);
			InventoryLegend.Initialize(displayConfig.HideInventoryKeyHints);
			controller = new RummageController(diagnostics, displayConfig);
			InventoryStatePatch.StateSet += controller.OnInventoryStateSet;
			InventoryStatePatch.StateSet += GameTermProbe.OnInventoryStateSet;
			playerSpawnSource = new PlayerSpawnSource();
			playerSpawnSource.PlayerSpawned += controller.OnPlayerSpawned;
			playerSpawnSource.PlayerSpawned += StashProbe.OnPlayerSpawned;
			playerSpawnSource.PlayerSpawned += EnchantmentCatalogProbe.OnPlayerSpawned;
			languageWatcher = new LanguageWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location));
			languageWatcher.LanguageChanged += controller.OnLanguageChanged;
			harmony = new Harmony("ryuka.sulfur.rummage");
			int num = 0;
			num += Patch(typeof(InventoryStatePatch), "search bar, item filter and world markers");
			num += Patch(typeof(InventoryLegendPatch), "hiding of the inventory key hints");
			num += Patch(typeof(InventoryKeyGuardPatch), "typing guard for inventory keys");
			num += Patch(typeof(InventoryCancelGuardPatch), "typing guard for the close inventory keys");
			num += Patch(typeof(PlayerStashDoSetupProbePatch), "stash setup probe");
			num += Patch(typeof(PlayerStashEnterProbePatch), "stash open probe");
			num += Patch(typeof(PlayerStashExitProbePatch), "stash close probe");
			num += Patch(typeof(InventoryUISetStateProbePatch), "inventory open/close probe");
			Log.LogInfo((object)("Rummage 1.0.0 loaded" + ((num == 0) ? "." : (" with " + num + " patch failure(s), see above."))));
		}

		private void Update()
		{
			playerSpawnSource?.Tick();
			languageWatcher?.Tick();
			controller?.Tick();
		}

		private void LateUpdate()
		{
			controller?.LateTick();
		}

		private void OnDestroy()
		{
			if (controller != null)
			{
				InventoryStatePatch.StateSet -= controller.OnInventoryStateSet;
			}
			InventoryStatePatch.StateSet -= GameTermProbe.OnInventoryStateSet;
			languageWatcher?.Dispose();
			languageWatcher = null;
			playerSpawnSource?.Dispose();
			playerSpawnSource = null;
			controller?.Dispose();
			controller = null;
			StashProbe.Shutdown();
			InventoryLegend.Shutdown();
			if (harmony != null)
			{
				harmony.UnpatchSelf();
				harmony = null;
			}
		}

		private int Patch(Type patchClass, string capability)
		{
			try
			{
				harmony.CreateClassProcessor(patchClass).Patch();
				return 0;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not install " + patchClass.Name + ", the " + capability + " is disabled. " + ex.GetType().Name + ": " + ex.Message));
				return 1;
			}
		}
	}
}
namespace Ryuka.Sulfur.Rummage.UserInterface
{
	internal static class GameFonts
	{
		public static TMP_FontAsset Current()
		{
			AsyncAssetLoading instance = StaticInstance<AsyncAssetLoading>.Instance;
			TMP_FontAsset[] array = (((Object)(object)instance != (Object)null) ? instance.fontCache : null);
			int num = 0;
			if (array == null || num >= array.Length)
			{
				return null;
			}
			if ((Object)(object)array[num] == (Object)null)
			{
				FontLocalizer.LoadFontCache();
			}
			return array[num];
		}
	}
	internal sealed class HoverTip : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		public Action<bool> Hover;

		public void OnPointerEnter(PointerEventData eventData)
		{
			Hover?.Invoke(obj: true);
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			Hover?.Invoke(obj: false);
		}

		private void OnDisable()
		{
			Hover?.Invoke(obj: false);
		}
	}
	internal sealed class SearchBar : IDisposable
	{
		private sealed class CategoryButton
		{
			public ItemCategory Category;

			public RectTransform Rect;

			public Image Background;

			public TextMeshProUGUI Label;
		}

		private const float RowHeight = 32f;

		private const float InputAreaPadding = 1f;

		private const float InputFontSize = 18f;

		private const float MinimumInputFontSize = 12f;

		private const float ButtonRowHeight = 26f;

		private const float Gap = 4f;

		private const float MarginAboveGrid = 6f;

		private const float ClearButtonWidth = 72f;

		private const float CheckboxIconInset = 3f;

		private const float CheckboxFallbackInset = 7f;

		private const float CheckboxIconOffAlpha = 0.45f;

		private const float TooltipFontSize = 14f;

		private const float MinimumWidth = 360f;

		private const int CharacterLimit = 64;

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];

		private readonly InventoryFilter filter;

		private readonly DiagnosticsConfig diagnostics;

		private readonly DisplayConfig display;

		private readonly SearchResultsPanel results = new SearchResultsPanel();

		private readonly List<CategoryButton> categoryButtons = new List<CategoryButton>();

		private readonly List<TextMeshProUGUI> texts = new List<TextMeshProUGUI>();

		private GameObject root;

		private RectTransform rootRect;

		private TMP_InputField input;

		private RectTransform inputRect;

		private RectTransform clearRect;

		private TextMeshProUGUI placeholder;

		private TextMeshProUGUI clearLabel;

		private RectTransform checkboxRect;

		private Image checkboxBackground;

		private Image checkboxIcon;

		private RectTransform tooltipRect;

		private TextMeshProUGUI tooltipText;

		private float barWidth;

		private RectTransform placedFor;

		private Rect placedForRect;

		private Vector3 placedForPosition;

		private bool fontStale;

		private bool buildFailed;

		public bool IsFocused
		{
			get
			{
				if ((Object)(object)input != (Object)null)
				{
					return input.isFocused;
				}
				return false;
			}
		}

		public bool IsVisible
		{
			get
			{
				if ((Object)(object)root != (Object)null && root.activeInHierarchy)
				{
					return (Object)(object)input != (Object)null;
				}
				return false;
			}
		}

		public SearchBar(InventoryFilter filter, DiagnosticsConfig diagnostics, DisplayConfig display)
		{
			this.filter = filter;
			this.diagnostics = diagnostics;
			this.display = display;
			filter.Changed += RefreshSelection;
			display.ResultsPlacement.SettingChanged += OnResultsPlacementChanged;
		}

		private void OnResultsPlacementChanged(object sender, EventArgs e)
		{
			placedFor = null;
		}

		public void FocusInput()
		{
			if (IsVisible)
			{
				EventSystem current = EventSystem.current;
				if ((Object)(object)current != (Object)null)
				{
					current.SetSelectedGameObject(((Component)input).gameObject);
				}
				input.ActivateInputField();
			}
		}

		public void Tick(InventoryUI ui)
		{
			ItemGrid playerBackpackGrid = ui.PlayerBackpackGrid;
			if ((Object)(object)playerBackpackGrid == (Object)null)
			{
				return;
			}
			RectTransform val = (((Object)(object)playerBackpackGrid.RectTransform != (Object)null) ? playerBackpackGrid.RectTransform : ((Component)playerBackpackGrid).GetComponent<RectTransform>());
			if ((Object)(object)val == (Object)null || !(((Transform)val).parent is RectTransform) || ((Object)(object)root == (Object)null && !TryBuild(ui, val)))
			{
				return;
			}
			if (!root.activeSelf)
			{
				root.SetActive(true);
			}
			results.SetShown(value: true);
			if (fontStale)
			{
				TMP_FontAsset val2 = SampleFont(ui);
				if ((Object)(object)val2 != (Object)null)
				{
					fontStale = false;
					ApplyFont(val2);
					LogFont(val2);
				}
			}
			Place(val);
		}

		public void SetSummary(List<LocationCount> counts)
		{
			results.SetCounts(counts);
		}

		public void OnInventoryHidden()
		{
			Unfocus();
			if ((Object)(object)root != (Object)null)
			{
				root.SetActive(false);
			}
			results.SetShown(value: false);
			ShowTooltip(show: false);
		}

		public void Unfocus()
		{
			if (!((Object)(object)input == (Object)null))
			{
				if (input.isFocused)
				{
					input.DeactivateInputField(false);
				}
				EventSystem current = EventSystem.current;
				if ((Object)(object)current != (Object)null && (Object)(object)current.currentSelectedGameObject == (Object)(object)((Component)input).gameObject)
				{
					current.SetSelectedGameObject((GameObject)null);
				}
			}
		}

		public void RefreshTexts()
		{
			fontStale = true;
			results.SetFontStale();
			results.RefreshTexts();
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			((TMP_Text)placeholder).text = RummageText.Get("search.placeholder", "Search name, oil or effect");
			((TMP_Text)clearLabel).text = RummageText.Get("search.clear", "Clear");
			((TMP_Text)tooltipText).text = RummageText.Get("search.appliedOils.tooltip", "Also find weapons by the oils applied to them");
			foreach (CategoryButton categoryButton in categoryButtons)
			{
				((TMP_Text)categoryButton.Label).text = CategoryLabel(categoryButton.Category);
			}
		}

		public void Dispose()
		{
			filter.Changed -= RefreshSelection;
			display.ResultsPlacement.SettingChanged -= OnResultsPlacementChanged;
			results.Destroy();
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
			root = null;
		}

		private bool TryBuild(InventoryUI ui, RectTransform gridRect)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Expected O, but got Unknown
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Expected O, but got Unknown
			if (buildFailed)
			{
				return false;
			}
			try
			{
				categoryButtons.Clear();
				texts.Clear();
				root = new GameObject("Rummage_SearchBar", new Type[2]
				{
					typeof(RectTransform),
					typeof(LayoutElement)
				});
				root.GetComponent<LayoutElement>().ignoreLayout = true;
				rootRect = root.GetComponent<RectTransform>();
				((Transform)rootRect).SetParent(((Transform)gridRect).parent, false);
				rootRect.anchorMin = new Vector2(0.5f, 0.5f);
				rootRect.anchorMax = new Vector2(0.5f, 0.5f);
				rootRect.pivot = Vector2.zero;
				TMP_FontAsset val = SampleFont(ui);
				if ((Object)(object)val == (Object)null)
				{
					RummagePlugin.Log.LogWarning((object)"No game font found to sample for the search bar; its text uses the TextMeshPro default font and may not render.");
				}
				LogFont(val);
				input = CreateInput(rootRect, val);
				inputRect = ((Component)input).GetComponent<RectTransform>();
				Button val2 = UiParts.CreateButton(rootRect, "Clear", val, texts, out clearLabel);
				clearRect = ((Component)val2).GetComponent<RectTransform>();
				((UnityEvent)val2.onClick).AddListener(new UnityAction(OnClearClicked));
				BuildCheckbox(val);
				BuildTooltip(val);
				ItemCategory[] selectable = ItemCategories.Selectable;
				for (int i = 0; i < selectable.Length; i++)
				{
					ItemCategory itemCategory = selectable[i];
					TextMeshProUGUI label;
					Button val3 = UiParts.CreateButton(rootRect, "Category_" + itemCategory, val, texts, out label);
					ItemCategory captured = itemCategory;
					((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
					{
						OnCategoryClicked(captured);
					});
					categoryButtons.Add(new CategoryButton
					{
						Category = itemCategory,
						Rect = ((Component)val3).GetComponent<RectTransform>(),
						Background = ((Component)val3).GetComponent<Image>(),
						Label = label
					});
				}
				results.Destroy();
				results.Build((RectTransform)((Transform)gridRect).parent, val);
				input.SetTextWithoutNotify(filter.Text);
				placedFor = null;
				RefreshTexts();
				fontStale = false;
				results.ApplyFont(val);
				RefreshSelection();
				return true;
			}
			catch (Exception ex)
			{
				buildFailed = true;
				RummagePlugin.Log.LogError((object)("Could not build the search bar; searching and category buttons are unavailable this session. " + ex));
				results.Destroy();
				if ((Object)(object)root != (Object)null)
				{
					Object.Destroy((Object)(object)root);
				}
				root = null;
				return false;
			}
		}

		private void Place(RectTransform gridRect)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_009e: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//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)
			RectTransform val = (RectTransform)((Transform)gridRect).parent;
			if ((Object)(object)((Transform)rootRect).parent != (Object)(object)val)
			{
				((Transform)rootRect).SetParent((Transform)(object)val, false);
				placedFor = null;
			}
			if (!((Object)(object)placedFor == (Object)(object)gridRect) || !(placedForRect == gridRect.rect) || !(placedForPosition == ((Transform)gridRect).localPosition))
			{
				placedFor = gridRect;
				placedForRect = gridRect.rect;
				placedForPosition = ((Transform)gridRect).localPosition;
				gridRect.GetWorldCorners(Corners);
				Vector3 val2 = ((Transform)val).InverseTransformPoint(Corners[1]);
				Vector3 val3 = ((Transform)val).InverseTransformPoint(Corners[2]);
				float num = Mathf.Max(360f, val3.x - val2.x);
				float num2 = 62f;
				rootRect.sizeDelta = new Vector2(num, num2);
				((Transform)rootRect).localPosition = new Vector3(val2.x, val2.y + 6f, 0f);
				((Transform)rootRect).SetAsLastSibling();
				Layout(num);
				float num3 = val2.y + 6f;
				results.Place(val2.x, num3, num3 + num2, num, display.ResultsPlacement.Value);
				if (diagnostics.LogSearchFilter.Value)
				{
					ManualLogSource log = RummagePlugin.Log;
					string[] obj = new string[12]
					{
						"[SearchBar] placed in '",
						((Object)val).name,
						"' above backpack grid ",
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null
					};
					Rect rect = gridRect.rect;
					obj[3] = ((Rect)(ref rect)).width.ToString("0");
					obj[4] = "x";
					rect = gridRect.rect;
					obj[5] = ((Rect)(ref rect)).height.ToString("0");
					obj[6] = " at (";
					obj[7] = val2.x.ToString("0");
					obj[8] = ", ";
					obj[9] = val2.y.ToString("0");
					obj[10] = "), bar width ";
					obj[11] = num.ToString("0");
					log.LogInfo((object)string.Concat(obj));
				}
			}
		}

		private void Layout(float width)
		{
			barWidth = width;
			UiParts.SetTopLeft(inputRect, 0f, 0f, width - 72f - 4f - 32f - 4f, 32f);
			UiParts.SetTopLeft(checkboxRect, width - 72f - 4f - 32f, 0f, 32f, 32f);
			UiParts.SetTopLeft(clearRect, width - 72f, 0f, 72f, 32f);
			int count = categoryButtons.Count;
			float num = (width - 4f * (float)(count - 1)) / (float)count;
			for (int i = 0; i < count; i++)
			{
				UiParts.SetTopLeft(categoryButtons[i].Rect, (float)i * (num + 4f), 36f, num, 26f);
			}
		}

		private void RefreshSelection()
		{
			//IL_0039: 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_0052: 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_009f: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			foreach (CategoryButton categoryButton in categoryButtons)
			{
				bool flag = categoryButton.Category == filter.Category;
				((Graphic)categoryButton.Background).color = (flag ? UiTheme.ButtonSelected : UiTheme.Button);
				((Graphic)categoryButton.Label).color = (flag ? UiTheme.Text : UiTheme.TextMuted);
			}
			if ((Object)(object)checkboxIcon != (Object)null)
			{
				bool includeAppliedEnchantments = filter.IncludeAppliedEnchantments;
				((Graphic)checkboxBackground).color = (includeAppliedEnchantments ? UiTheme.CheckboxFilled : UiTheme.Button);
				if ((Object)(object)checkboxIcon.sprite != (Object)null)
				{
					((Graphic)checkboxIcon).color = new Color(1f, 1f, 1f, includeAppliedEnchantments ? 1f : 0.45f);
				}
				else
				{
					((Behaviour)checkboxIcon).enabled = false;
				}
			}
			if ((Object)(object)input != (Object)null && input.text != filter.Text)
			{
				input.SetTextWithoutNotify(filter.Text);
			}
		}

		private void BuildCheckbox(TMP_FontAsset font)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			TextMeshProUGUI label;
			Button val = UiParts.CreateButton(rootRect, "IncludeAppliedOils", font, texts, out label);
			((TMP_Text)label).text = string.Empty;
			checkboxRect = ((Component)val).GetComponent<RectTransform>();
			checkboxBackground = ((Component)val).GetComponent<Image>();
			Sprite appliedOilsGun = UiIcons.AppliedOilsGun;
			float num = (((Object)(object)appliedOilsGun != (Object)null) ? 3f : 7f);
			GameObject val2 = new GameObject("Icon", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			RectTransform component = val2.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)checkboxRect, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = new Vector2(num, num);
			component.offsetMax = new Vector2(0f - num, 0f - num);
			checkboxIcon = val2.GetComponent<Image>();
			checkboxIcon.sprite = appliedOilsGun;
			checkboxIcon.preserveAspect = true;
			((Graphic)checkboxIcon).raycastTarget = false;
			((UnityEvent)val.onClick).AddListener(new UnityAction(OnIncludeAppliedClicked));
			((Component)val).gameObject.AddComponent<HoverTip>().Hover = ShowTooltip;
		}

		private void BuildTooltip(TMP_FontAsset font)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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)
			GameObject val = new GameObject("Tooltip", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			tooltipRect = val.GetComponent<RectTransform>();
			((Transform)tooltipRect).SetParent((Transform)(object)rootRect, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = UiTheme.Panel;
			((Graphic)component).raycastTarget = false;
			tooltipText = UiParts.CreateText(tooltipRect, "Text", font, 14f, UiTheme.Text, (TextAlignmentOptions)4097, texts, (TextOverflowModes)0);
			((TMP_Text)tooltipText).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)tooltipText).rectTransform.offsetMin = new Vector2(8f, 4f);
			((TMP_Text)tooltipText).rectTransform.offsetMax = new Vector2(-8f, -4f);
			val.SetActive(false);
		}

		private void ShowTooltip(bool show)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)tooltipRect == (Object)null))
			{
				if (!show || fontStale || string.IsNullOrEmpty(((TMP_Text)tooltipText).text))
				{
					((Component)tooltipRect).gameObject.SetActive(false);
					return;
				}
				Vector2 preferredValues = ((TMP_Text)tooltipText).GetPreferredValues(((TMP_Text)tooltipText).text, float.PositiveInfinity, 0f);
				float num = preferredValues.x + 16f;
				float height = preferredValues.y + 8f;
				float num2 = barWidth - 72f - 4f;
				UiParts.SetTopLeft(tooltipRect, Mathf.Max(0f, num2 - num), 34f, num, height);
				((Transform)tooltipRect).SetAsLastSibling();
				((Component)tooltipRect).gameObject.SetActive(true);
			}
		}

		private void OnIncludeAppliedClicked()
		{
			filter.SetIncludeAppliedEnchantments(!filter.IncludeAppliedEnchantments);
			UiParts.ClearSelection();
		}

		private void OnClearClicked()
		{
			filter.Clear();
			Unfocus();
			UiParts.ClearSelection();
		}

		private void OnCategoryClicked(ItemCategory category)
		{
			filter.SetCategory((category != filter.Category) ? category : ItemCategory.All);
			UiParts.ClearSelection();
		}

		private static string CategoryLabel(ItemCategory category)
		{
			return category switch
			{
				ItemCategory.Oils => RummageText.Get("category.oils", "Oils"), 
				ItemCategory.Scrolls => RummageText.Get("category.scrolls", "Scrolls"), 
				ItemCategory.Weapons => RummageText.Get("category.weapons", "Weapons"), 
				ItemCategory.Attachments => GameTerms.Get("ItemDescriptions/Label_Attachments") ?? RummageText.Get("category.attachments", "Attachments"), 
				ItemCategory.Consumables => GameTerms.Get("ItemDescriptions/UseType_Consumable") ?? RummageText.Get("category.consumables", "Consumables"), 
				_ => RummageText.Get("category.all", "All"), 
			};
		}

		private static TMP_FontAsset SampleFont(InventoryUI ui)
		{
			TMP_FontAsset val = GameFonts.Current();
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			TextMeshProUGUI sacrificeFeedbackText = ui.sacrificeFeedbackText;
			if (!((Object)(object)sacrificeFeedbackText != (Object)null))
			{
				return null;
			}
			return ((TMP_Text)sacrificeFeedbackText).font;
		}

		private void LogFont(TMP_FontAsset font)
		{
			if (diagnostics.LogSearchFilter.Value)
			{
				RummagePlugin.Log.LogInfo((object)("[SearchBar] font: " + (((Object)(object)font != (Object)null) ? ((Object)font).name : "<none>")));
			}
		}

		private void ApplyFont(TMP_FontAsset font)
		{
			if ((Object)(object)font == (Object)null)
			{
				return;
			}
			foreach (TextMeshProUGUI text in texts)
			{
				if ((Object)(object)text != (Object)null)
				{
					((TMP_Text)text).font = font;
				}
			}
			if ((Object)(object)input != (Object)null)
			{
				float pointSize = FitInputFontSize(font);
				input.fontAsset = font;
				input.pointSize = pointSize;
			}
			results.ApplyFont(font);
		}

		private TMP_InputField CreateInput(RectTransform parent, TMP_FontAsset font)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SearchInput", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)parent, false);
			val.SetActive(false);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = UiTheme.Field;
			((Graphic)component2).raycastTarget = true;
			SearchInputField searchInputField = val.AddComponent<SearchInputField>();
			((Selectable)searchInputField).targetGraphic = (Graphic)(object)component2;
			((TMP_InputField)searchInputField).lineType = (LineType)0;
			((TMP_InputField)searchInputField).characterLimit = 64;
			((TMP_InputField)searchInputField).shouldHideMobileInput = true;
			((TMP_InputField)searchInputField).shouldHideSoftKeyboard = true;
			((TMP_InputField)searchInputField).onFocusSelectAll = false;
			((TMP_InputField)searchInputField).resetOnDeActivation = false;
			((TMP_InputField)searchInputField).restoreOriginalTextOnEscape = false;
			((TMP_InputField)searchInputField).customCaretColor = true;
			((TMP_InputField)searchInputField).caretColor = UiTheme.Text;
			((TMP_InputField)searchInputField).caretWidth = 2;
			((TMP_InputField)searchInputField).selectionColor = new Color(UiTheme.Text.r, UiTheme.Text.g, UiTheme.Text.b, 0.25f);
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)searchInputField).navigation = navigation;
			RectTransform component3 = new GameObject("TextArea", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			}).GetComponent<RectTransform>();
			((Transform)component3).SetParent((Transform)(object)component, false);
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = new Vector2(8f, 1f);
			component3.offsetMax = new Vector2(-8f, -1f);
			float num = FitInputFontSize(font);
			TextMeshProUGUI textComponent = UiParts.CreateText(component3, "Text", font, num, UiTheme.Text, (TextAlignmentOptions)4097, texts, (TextOverflowModes)0);
			placeholder = UiParts.CreateText(component3, "Placeholder", font, num, UiTheme.TextMuted, (TextAlignmentOptions)4097, texts, (TextOverflowModes)0);
			((TMP_InputField)searchInputField).textViewport = component3;
			((TMP_InputField)searchInputField).textComponent = (TMP_Text)(object)textComponent;
			((TMP_InputField)searchInputField).placeholder = (Graphic)(object)placeholder;
			((TMP_InputField)searchInputField).pointSize = num;
			((UnityEvent<string>)(object)((TMP_InputField)searchInputField).onValueChanged).AddListener((UnityAction<string>)filter.SetText);
			val.SetActive(true);
			return (TMP_InputField)(object)searchInputField;
		}

		private static float FitInputFontSize(TMP_FontAsset font)
		{
			//IL_0010: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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)
			//IL_0045: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			float num = 30f;
			if (!((Object)(object)font == (Object)null))
			{
				FaceInfo faceInfo = ((TMP_Asset)font).faceInfo;
				if (!(((FaceInfo)(ref faceInfo)).pointSize <= 0f))
				{
					faceInfo = ((TMP_Asset)font).faceInfo;
					if (!(((FaceInfo)(ref faceInfo)).lineHeight <= 0f))
					{
						faceInfo = ((TMP_Asset)font).faceInfo;
						float lineHeight = ((FaceInfo)(ref faceInfo)).lineHeight;
						faceInfo = ((TMP_Asset)font).faceInfo;
						float num2 = lineHeight / ((FaceInfo)(ref faceInfo)).pointSize;
						return Mathf.Clamp(Mathf.Floor(num / num2), 12f, 18f);
					}
				}
			}
			return 18f;
		}
	}
	internal sealed class SearchInputField : TMP_InputField
	{
		public override void OnCancel(BaseEventData eventData)
		{
			Keyboard current = Keyboard.current;
			if (current == null || !((ButtonControl)current.backspaceKey).isPressed)
			{
				((TMP_InputField)this).OnCancel(eventData);
			}
		}
	}
	internal sealed class SearchResultsPanel
	{
		private const float Gap = 4f;

		private const float ToggleSize = 24f;

		private const float SummaryMinimumHeight = 30f;

		private const float SummaryMaximumHeight = 64f;

		private const float SummaryFontSize = 14f;

		private const float DetailFontSize = 14f;

		private const float DetailPadding = 6f;

		private const float DetailMinimumHeight = 40f;

		private const float AboveDetailMaximumHeight = 320f;

		private const float ScreenMargin = 8f;

		private const string Separator = "  ·  ";

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];

		private readonly List<TextMeshProUGUI> texts = new List<TextMeshProUGUI>();

		private GameObject root;

		private RectTransform rootRect;

		private RectTransform summaryRow;

		private TextMeshProUGUI summaryText;

		private RectTransform toggleRect;

		private TextMeshProUGUI toggleLabel;

		private RectTransform detailPanel;

		private RectTransform detailContent;

		private TextMeshProUGUI detailText;

		private ScrollRect detailScroll;

		private List<LocationCount> counts;

		private bool expanded;

		private bool shown;

		private bool fontReady = true;

		private bool placed;

		private float left;

		private float barBottom;

		private float barTop;

		private float width;

		private ResultsPosition position;

		public bool IsBuilt => (Object)(object)root != (Object)null;

		public void Build(RectTransform parent, TMP_FontAsset font)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			texts.Clear();
			placed = false;
			fontReady = true;
			root = new GameObject("Rummage_SearchResults", new Type[2]
			{
				typeof(RectTransform),
				typeof(LayoutElement)
			});
			root.GetComponent<LayoutElement>().ignoreLayout = true;
			rootRect = root.GetComponent<RectTransform>();
			((Transform)rootRect).SetParent((Transform)(object)parent, false);
			rootRect.anchorMin = new Vector2(0.5f, 0.5f);
			rootRect.anchorMax = new Vector2(0.5f, 0.5f);
			rootRect.pivot = Vector2.zero;
			BuildSummaryRow(font);
			BuildDetailPanel(font);
			Render();
			UpdateVisibility();
		}

		public void Place(float barLeft, float barBottomY, float barTopY, float barWidth, ResultsPosition resultsPosition)
		{
			left = barLeft;
			barBottom = barBottomY;
			barTop = barTopY;
			width = barWidth;
			position = resultsPosition;
			placed = true;
			if ((Object)(object)root != (Object)null)
			{
				((Transform)rootRect).SetAsLastSibling();
				Layout();
			}
		}

		public void SetCounts(List<LocationCount> value)
		{
			counts = value;
			Render();
			UpdateVisibility();
		}

		public void SetShown(bool value)
		{
			shown = value;
			UpdateVisibility();
		}

		public void RefreshTexts()
		{
			Render();
		}

		public void SetFontStale()
		{
			fontReady = false;
		}

		public void ApplyFont(TMP_FontAsset font)
		{
			if ((Object)(object)font != (Object)null)
			{
				foreach (TextMeshProUGUI text in texts)
				{
					if ((Object)(object)text != (Object)null)
					{
						((TMP_Text)text).font = font;
					}
				}
			}
			fontReady = true;
			Layout();
		}

		public void Destroy()
		{
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
			root = null;
		}

		private void BuildSummaryRow(TMP_FontAsset font)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_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_015d: Expected O, but got Unknown
			GameObject val = new GameObject("Summary", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			summaryRow = val.GetComponent<RectTransform>();
			((Transform)summaryRow).SetParent((Transform)(object)rootRect, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = UiTheme.Field;
			((Graphic)component).raycastTarget = false;
			summaryText = UiParts.CreateText(summaryRow, "Text", font, 14f, UiTheme.Text, (TextAlignmentOptions)4097, texts, (TextOverflowModes)0);
			((TMP_Text)summaryText).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)summaryText).rectTransform.offsetMin = new Vector2(8f, 2f);
			((TMP_Text)summaryText).rectTransform.offsetMax = new Vector2(-36f, -2f);
			Button val2 = UiParts.CreateButton(summaryRow, "Expand", font, texts, out toggleLabel);
			toggleRect = ((Component)val2).GetComponent<RectTransform>();
			((TMP_Text)toggleLabel).enableAutoSizing = false;
			((TMP_Text)toggleLabel).fontSize = 18f;
			((TMP_Text)toggleLabel).overflowMode = (TextOverflowModes)0;
			((Graphic)toggleLabel).color = UiTheme.Text;
			((UnityEvent)val2.onClick).AddListener(new UnityAction(OnToggleClicked));
		}

		private void BuildDetailPanel(TMP_FontAsset font)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Details", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			detailPanel = val.GetComponent<RectTransform>();
			((Transform)detailPanel).SetParent((Transform)(object)rootRect, false);
			((Graphic)val.GetComponent<Image>()).color = UiTheme.Panel;
			RectTransform component = new GameObject("Viewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			}).GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)detailPanel, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = new Vector2(6f, 6f);
			component.offsetMax = new Vector2(-6f, -6f);
			GameObject val2 = new GameObject("Content", new Type[1] { typeof(RectTransform) });
			detailContent = val2.GetComponent<RectTransform>();
			((Transform)detailContent).SetParent((Transform)(object)component, false);
			detailContent.anchorMin = new Vector2(0f, 1f);
			detailContent.anchorMax = new Vector2(1f, 1f);
			detailContent.pivot = new Vector2(0.5f, 1f);
			detailContent.sizeDelta = Vector2.zero;
			detailContent.anchoredPosition = Vector2.zero;
			detailText = UiParts.CreateText(detailContent, "Text", font, 14f, UiTheme.TextMuted, (TextAlignmentOptions)257, texts, (TextOverflowModes)0);
			((TMP_Text)detailText).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)detailText).richText = true;
			detailScroll = val.AddComponent<ScrollRect>();
			detailScroll.viewport = component;
			detailScroll.content = detailContent;
			detailScroll.horizontal = false;
			detailScroll.vertical = true;
			detailScroll.movementType = (MovementType)2;
			detailScroll.inertia = false;
			detailScroll.scrollSensitivity = 28f;
			val.SetActive(false);
		}

		private void OnToggleClicked()
		{
			expanded = !expanded;
			Render();
			UiParts.ClearSelection();
		}

		private void Render()
		{
			if (!((Object)(object)root == (Object)null))
			{
				bool flag = counts != null && counts.Count > 0;
				((TMP_Text)summaryText).text = ((counts == null) ? string.Empty : (flag ? SummaryLine(counts) : RummageText.Get("summary.none", "No matches")));
				((Component)toggleRect).gameObject.SetActive(flag);
				((TMP_Text)toggleLabel).text = (expanded ? "-" : "+");
				((TMP_Text)detailText).text = ((flag && expanded) ? DetailLines(counts) : string.Empty);
				Layout();
			}
		}

		private void Layout()
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: 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)
			if ((Object)(object)root == (Object)null || !placed || !fontReady)
			{
				return;
			}
			bool flag = position == ResultsPosition.BelowSearchBar;
			float num = Mathf.Max(40f, width - 24f - 20f);
			float num2 = Mathf.Clamp(PreferredHeight(summaryText, num) + 8f, 30f, 64f);
			bool flag2 = expanded && counts != null && counts.Count > 0;
			if (((Component)detailPanel).gameObject.activeSelf != flag2)
			{
				((Component)detailPanel).gameObject.SetActive(flag2);
			}
			float num3 = 0f;
			if (flag2)
			{
				float num4 = Mathf.Max(40f, width - 12f);
				float num5 = PreferredHeight(detailText, num4);
				detailContent.sizeDelta = new Vector2(0f, num5);
				float num6 = (flag ? RoomBelow(barBottom - 4f - num2 - 4f) : Mathf.Min(320f, RoomAbove(barTop + 4f + num2 + 4f)));
				float num7 = Mathf.Max(40f, num6);
				num3 = Mathf.Clamp(num5 + 12f, 40f, num7);
			}
			float num8 = num2 + (flag2 ? (4f + num3) : 0f);
			if (flag)
			{
				UiParts.SetBottomLeft(summaryRow, 0f, flag2 ? (num3 + 4f) : 0f, width, num2);
				if (flag2)
				{
					UiParts.SetBottomLeft(detailPanel, 0f, 0f, width, num3);
				}
				((Transform)rootRect).localPosition = new Vector3(left, barBottom - 4f - num8, 0f);
			}
			else
			{
				UiParts.SetBottomLeft(summaryRow, 0f, 0f, width, num2);
				if (flag2)
				{
					UiParts.SetBottomLeft(detailPanel, 0f, num2 + 4f, width, num3);
				}
				((Transform)rootRect).localPosition = new Vector3(left, barTop + 4f, 0f);
			}
			UiParts.SetBottomLeft(toggleRect, width - 24f - 4f, (num2 - 24f) * 0.5f, 24f, 24f);
			rootRect.sizeDelta = new Vector2(width, num8);
		}

		private void UpdateVisibility()
		{
			if (!((Object)(object)root == (Object)null))
			{
				bool flag = shown && counts != null;
				if (root.activeSelf != flag)
				{
					root.SetActive(flag);
				}
			}
		}

		private static string SummaryLine(List<LocationCount> locations)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (LocationCount location in locations)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append("  ·  ");
				}
				stringBuilder.Append(location.Label).Append(" ×").Append(location.Quantity);
			}
			return stringBuilder.ToString();
		}

		private static string DetailLines(List<LocationCount> locations)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (LocationCount location in locations)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append("<color=").Append("#F4C46A").Append('>')
					.Append(NoParse(location.Label))
					.Append(" ×")
					.Append(location.Quantity)
					.Append("</color>\n");
				for (int i = 0; i < location.Items.Count; i++)
				{
					if (i > 0)
					{
						stringBuilder.Append("  ·  ");
					}
					stringBuilder.Append(NoParse(location.Items[i].Name)).Append(" ×").Append(location.Items[i].Quantity);
				}
			}
			return stringBuilder.ToString();
		}

		private static string NoParse(string value)
		{
			if (!string.IsNullOrEmpty(value) && value.IndexOf('<') >= 0)
			{
				return "<noparse>" + value + "</noparse>";
			}
			return value;
		}

		private static float PreferredHeight(TextMeshProUGUI text, float width)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(((TMP_Text)text).text))
			{
				return ((TMP_Text)text).GetPreferredValues(((TMP_Text)text).text, width, 0f).y;
			}
			return 0f;
		}

		private float RoomAbove(float localY)
		{
			if (!TryScreenEdge(1, out var y))
			{
				return 320f;
			}
			return y - localY - 8f;
		}

		private float RoomBelow(float localY)
		{
			if (!TryScreenEdge(0, out var y))
			{
				return 320f;
			}
			return localY - y - 8f;
		}

		private bool TryScreenEdge(int corner, out float y)
		{
			//IL_0068: 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)
			y = 0f;
			Canvas componentInParent = ((Component)rootRect).GetComponentInParent<Canvas>();
			Transform parent = ((Transform)rootRect).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			RectTransform val2 = (RectTransform)(((Object)(object)componentInParent != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val == (Object)null)
			{
				return false;
			}
			val2.GetWorldCorners(Corners);
			y = ((Transform)val).InverseTransformPoint(Corners[corner]).y;
			return true;
		}
	}
	internal static class UiIcons
	{
		private const string AppliedOilsGunResource = "Ryuka.Sulfur.Rummage.UserInterface.Icons.AppliedOilsGun.png";

		private static Sprite appliedOilsGun;

		private static bool appliedOilsGunLoaded;

		public static Sprite AppliedOilsGun
		{
			get
			{
				if (!appliedOilsGunLoaded)
				{
					appliedOilsGunLoaded = true;
					appliedOilsGun = Load("Ryuka.Sulfur.Rummage.UserInterface.Icons.AppliedOilsGun.png", "the applied-oils checkbox shows without its gun icon");
				}
				return appliedOilsGun;
			}
		}

		private static bool LoadImage(Texture2D texture, byte[] bytes)
		{
			Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
			MethodInfo methodInfo = ((type != null) ? type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, null) : null);
			if (methodInfo == null)
			{
				RummagePlugin.Log.LogWarning((object)"UnityEngine.ImageConversion.LoadImage(Texture2D, byte[]) was not found; embedded icons cannot be decoded.");
				return false;
			}
			object obj = methodInfo.Invoke(null, new object[2] { texture, bytes });
			if (obj is bool)
			{
				return (bool)obj;
			}
			return false;
		}

		private static Sprite Load(string resource, string consequence)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				byte[] bytes;
				using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
				{
					if (stream == null)
					{
						RummagePlugin.Log.LogWarning((object)("Embedded image " + resource + " is missing from this build; " + consequence + "."));
						return null;
					}
					using MemoryStream memoryStream = new MemoryStream();
					stream.CopyTo(memoryStream);
					bytes = memoryStream.ToArray();
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!LoadImage(val, bytes))
				{
					RummagePlugin.Log.LogWarning((object)("Embedded image " + resource + " could not be decoded; " + consequence + "."));
					return null;
				}
				((Object)val).name = resource;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)1;
				Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)obj).name = resource;
				return obj;
			}
			catch (Exception ex)
			{
				RummagePlugin.Log.LogWarning((object)("Loading embedded image " + resource + " failed; " + consequence + ". " + ex.Message));
				return null;
			}
		}
	}
	internal static class UiTheme
	{
		public static readonly Color Field = new Color(0.07f, 0.05f, 0.03f, 0.9f);

		public static readonly Color Panel = new Color(0.03f, 0.02f, 0.01f, 0.92f);

		public static readonly Color Button = new Color(0.13f, 0.08f, 0.03f, 0.91f);

		public static readonly Color ButtonSelected = new Color(0.29f, 0.19f, 0.07f, 0.95f);

		public static readonly Color Text = new Color(0.96f, 0.77f, 0.42f, 1f);

		public static readonly Color TextMuted = new Color(0.72f, 0.52f, 0.21f, 0.9f);

		public static readonly Color CheckboxFilled = new Color(0.9f, 0.63f, 0.18f, 1f);

		public const string TextHex = "#F4C46A";
	}
	internal static class UiParts
	{
		public static TextMeshProUGUI CreateText(RectTransform parent, string name, TMP_FontAsset font, float size, Color color, TextAlignmentOptions alignment, List<TextMeshProUGUI> registry, TextOverflowModes overflow = (TextOverflowModes)1)
		{
			//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_0042: 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_0058: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(TextMeshProUGUI)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)parent, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)component2).font = font;
			}
			((TMP_Text)component2).fontSize = size;
			((Graphic)component2).color = color;
			((TMP_Text)component2).alignment = alignment;
			((Graphic)component2).raycastTarget = false;
			((TMP_Text)component2).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)component2).overflowMode = overflow;
			registry.Add(component2);
			return component2;
		}

		public static Button CreateButton(RectTransform parent, string name, TMP_FontAsset font, List<TextMeshProUGUI> registry, out TextMeshProUGUI label)
		{
			//IL_003b: 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)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_007e: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)parent, false);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = UiTheme.Button;
			Button component3 = val.GetComponent<Button>();
			((Selectable)component3).targetGraphic = (Graphic)(object)component2;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)component3).navigation = navigation;
			ColorBlock colors = ((Selectable)component3).colors;
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 0.92f, 0.8f, 1f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.75f, 0.7f, 0.62f, 1f);
			((ColorBlock)(ref colors)).selectedColor = Color.white;
			((Selectable)component3).colors = colors;
			label = CreateText(component, "Label", font, 15f, UiTheme.TextMuted, (TextAlignmentOptions)514, registry, (TextOverflowModes)1);
			((TMP_Text)label).enableAutoSizing = true;
			((TMP_Text)label).fontSizeMin = 9f;
			((TMP_Text)label).fontSizeMax = 15f;
			((TMP_Text)label).rectTransform.offsetMin = new Vector2(3f, 1f);
			((TMP_Text)label).rectTransform.offsetMax = new Vector2(-3f, -1f);
			return component3;
		}

		public static void SetTopLeft(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, 1f);
			rect.anchorMax = new Vector2(0f, 1f);
			rect.pivot = new Vector2(0f, 1f);
			rect.sizeDelta = new Vector2(width, height);
			rect.anchoredPosition = new Vector2(x, 0f - y);
		}

		public static void SetBottomLeft(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			//IL_0025: 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)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.zero;
			rect.pivot = Vector2.zero;
			rect.sizeDelta = new Vector2(width, height);
			rect.anchoredPosition = new Vector2(x, y);
		}

		public static void ClearSelection()
		{
			EventSystem current = EventSystem.current;
			if ((Object)(object)current != (Object)null)
			{
				current.SetSelectedGameObject((GameObject)null);
			}
		}
	}
	internal sealed class WorldMarkers : IDisposable
	{
		private sealed class Marker
		{
			public GameObject Root;

			public RectTransform Rect;

			public RectTransform Background;

			public TextMeshProUGUI Text;

			public string Shown;
		}

		private const float HeightAboveAnchor = 0.9f;

		private const float WorldUnitsPerPixel = 0.004f;

		private const float ReferenceDistance = 5f;

		private const float MaximumDistanceScale = 3f;

		private const float FontSize = 36f;

		private const float PaddingX = 18f;

		private const float PaddingY = 8f;

		private const int SortingOrder = 500;

		private readonly StorageIndex index;

		private readonly Dictionary<string, Marker> markers = new Dictionary<string, Marker>(StringComparer.Ordinal);

		private readonly HashSet<string> shownThisFrame = new HashSet<string>(StringComparer.Ordinal);

		private GameObject root;

		private List<LocationCount> counts;

		private TMP_FontAsset font;

		private bool fontStale = true;

		private bool failureReported;

		public WorldMarkers(DiagnosticsConfig diagnostics)
		{
			index = new StorageIndex(diagnostics);
		}

		public void SetCounts(List<LocationCount> value)
		{
			counts = value;
		}

		public void OnPlayerSpawned()
		{
			index.Invalidate();
		}

		public void OnLanguageChanged()
		{
			fontStale = true;
		}

		public void LateTick()
		{
			try
			{
				Update();
			}
			catch (Exception ex)
			{
				if (!failureReported)
				{
					failureReported = true;
					RummagePlugin.Log.LogError((object)("Updating world markers failed; further failures are not logged. " + ex));
				}
				HideAll();
			}
		}

		public void Dispose()
		{
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
			root = null;
			markers.Clear();
		}

		private void Update()
		{
			//IL_00c8: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			if (counts == null || counts.Count == 0)
			{
				HideAll();
				return;
			}
			GameManager instance = StaticInstance<GameManager>.Instance;
			GameObject val = (((Object)(object)instance != (Object)null) ? instance.PlayerObject : null);
			Camera val2 = PlayerCamera(instance);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				HideAll();
				return;
			}
			if (fontStale)
			{
				TMP_FontAsset val3 = GameFonts.Current();
				if ((Object)(object)val3 == (Object)null)
				{
					HideAll();
					return;
				}
				font = val3;
				fontStale = false;
				foreach (Marker value in markers.Values)
				{
					ApplyFont(value);
				}
			}
			Vector3 position = val.transform.position;
			Vector3 position2 = ((Component)val2).transform.position;
			shownThisFrame.Clear();
			foreach (LocationCount count in counts)
			{
				if (count.Identifier != null)
				{
					StorageIndex.Entry entry = index.Nearest(count.Identifier, position);
					if (entry != null)
					{
						Marker orCreate = GetOrCreate(count.Identifier);
						Place(orCreate, entry, count, position2);
						shownThisFrame.Add(count.Identifier);
					}
				}
			}
			foreach (KeyValuePair<string, Marker> marker in markers)
			{
				if (!shownThisFrame.Contains(marker.Key) && marker.Value.Root.activeSelf)
				{
					marker.Value.Root.SetActive(false);
				}
			}
		}

		private static Camera PlayerCamera(GameManager gameManager)
		{
			if ((Object)(object)gameManager != (Object)null && (Object)(object)gameManager.PlayerScript != (Object)null && (Object)(object)gameManager.PlayerScript.playerCamera != (Object)null)
			{
				return gameManager.PlayerScript.playerCamera;
			}
			return Camera.main;
		}

		private void Place(Marker marker, StorageIndex.Entry target, LocationCount count, Vector3 cameraPosition)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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)
			//IL_00cb: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_011a: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (!marker.Root.activeSelf)
			{
				marker.Root.SetActive(true);
			}
			string text = count.Label + " ×" + count.Quantity;
			if (marker.Shown != text)
			{
				marker.Shown = text;
				((TMP_Text)marker.Text).text = text;
				Vector2 preferredValues = ((TMP_Text)marker.Text).GetPreferredValues(text);
				marker.Rect.sizeDelta = new Vector2(preferredValues.x + 36f, preferredValues.y + 16f);
			}
			Transform transform = marker.Root.transform;
			transform.position = target.Anchor.position + Vector3.up * 0.9f;
			Vector3 val = transform.position - cameraPosition;
			if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				transform.rotation = Quaternion.LookRotation(val, Vector3.up);
			}
			float num = Mathf.Clamp(((Vector3)(ref val)).magnitude / 5f, 1f, 3f);
			transform.localScale = Vector3.one * (0.004f * num);
			if (marker.Root.layer != target.Owner.layer)
			{
				SetLayer(marker.Root, target.Owner.layer);
			}
		}

		private Marker GetOrCreate(string identifier)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			//IL_0169: 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_003e: Expected O, but got Unknown
			if (markers.TryGetValue(identifier, out var value) && (Object)(object)value.Root != (Object)null)
			{
				return value;
			}
			if ((Object)(object)root == (Object)null)
			{
				root = new GameObject("Rummage_WorldMarkers");
			}
			GameObject val = new GameObject("Marker_" + identifier, new Type[2]
			{
				typeof(RectTransform),
				typeof(Canvas)
			});
			val.transform.SetParent(root.transform, false);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)2;
			component.sortingOrder = 500;
			RectTransform component2 = val.GetComponent<RectTransform>();
			component2.pivot = new Vector2(0.5f, 0f);
			GameObject val2 = new GameObject("Background", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			RectTransform component3 = val2.GetComponent<RectTransform>();
			((Transform)component3).SetParent((Transform)(object)component2, false);
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = Vector2.zero;
			component3.offsetMax = Vector2.zero;
			Image component4 = val2.GetComponent<Image>();
			((Graphic)component4).color = UiTheme.Panel;
			((Graphic)component4).raycastTarget = false;
			((Graphic)component4).material = OnTop(new Material(Canvas.GetDefaultCanvasMaterial()));
			List<TextMeshProUGUI> registry = new List<TextMeshProUGUI>();
			TextMeshProUGUI text = UiParts.CreateText(component2, "Text", null, 36f, UiTheme.Text, (TextAlignmentOptions)514, registry, (TextOverflowModes)0);
			value = new Marker
			{
				Root = val,
				Rect = component2,
				Background = component3,
				Text = text
			};
			ApplyFont(value);
			markers[identifier] = value;
			return value;
		}

		private void ApplyFont(Marker marker)
		{
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)marker.Text).font = font;
			}
			OnTop(((TMP_Text)marker.Text).fontMaterial);
			marker.Shown = null;
		}

		private static Material OnTop(Material material)
		{
			if ((Object)(object)material != (Object)null)
			{
				material.SetInt("unity_GUIZTestMode", 8);
			}
			return material;
		}

		private void HideAll()
		{
			foreach (Marker value in markers.Values)
			{
				if ((Object)(object)value.Root != (Object)null && value.Root.activeSelf)
				{
					value.Root.SetActive(false);
				}
			}
		}

		private static void SetLayer(GameObject go, int layer)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			go.layer = layer;
			foreach (Transform item in go.transform)
			{
				SetLayer(((Component)item).gameObject, layer);
			}
		}
	}
}
namespace Ryuka.Sulfur.Rummage.Stashes
{
	internal enum StashKind
	{
		Main,
		Wardrobe,
		Suitcase,
		Safe,
		Sideboard,
		Fridge,
		SnakeBasket,
		GunCabinet,
		WeaponRack,
		Coffin,
		Toilet,
		ItemFrame,
		WallMount,
		Unknown
	}
	internal readonly struct StashName
	{
		public StashKind Kind { get; }

		public int Number { get; }

		public StashName(StashKind kind, int number)
		{
			Kind = kind;
			Number = number;
		}
	}
	internal static class StashNaming
	{
		public static StashName Resolve(string identifier)
		{
			switch (identifier ?? string.Empty)
			{
			case "":
				return new StashName(StashKind.Main, 0);
			case "Wardrobe":
				return new StashName(StashKind.Wardrobe, 0);
			case "Suitcase":
				return new StashName(StashKind.Suitcase, 0);
			case "Safe":
				return new StashName(StashKind.Safe, 0);
			case "Sideboard":
				return new StashName(StashKind.Sideboard, 0);
			case "Fridge":
				return new StashName(StashKind.Fridge, 0);
			case "SnakeBasket":
				return new StashName(StashKind.SnakeBasket, 0);
			case "GunCabinet":
				return new StashName(StashKind.GunCabinet, 0);
			case "Coffin":
				return new StashName(StashKind.Coffin, 0);
			case "Toilet":
				return new StashName(StashKind.Toilet, 0);
			default:
			{
				if (TryNumberedSuffix(identifier, "WeaponRack", out var number))
				{
					return new StashName(StashKind.WeaponRack, number + 1);
				}
				if (TryNumberedSuffix(identifier, "WallMount", out number))
				{
					return new StashName(StashKind.WallMount, number + 1);
				}
				if (TryNumberedSuffix(identifier, "ItemFrame", out number) && number > 0)
				{
					return new StashName(StashKind.ItemFrame, number);
				}
				return new StashName(StashKind.Unknown, 0);
			}
			}
		}

		private static bool TryNumberedSuffix(string identifier, string prefix, out int number)
		{
			number = 0;
			if (identifier == null || identifier.Length <= prefix.Length || !identifier.StartsWith(prefix, StringComparison.Ordinal))
			{
				return false;
			}
			for (int i = prefix.Length; i < identifier.Length; i++)
			{
				char c = identifier[i];
				if (c < '0' || c > '9')
				{
					return false;
				}
				number = number * 10 + (c - 48);
				if (number > 9999)
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class StashSaveKey
	{
		public const string Prefix = "Stash";

		private const char Separator = '_';

		public static string FromIdentifier(string identifier)
		{
			if (!string.IsNullOrEmpty(identifier))
			{
				return "Stash_" + identifier;
			}
			return "Stash";
		}

		public static bool TryGetIdentifier(string key, out string identifier)
		{
			identifier = null;
			if (key == null || !key.StartsWith("Stash", StringComparison.Ordinal))
			{
				return false;
			}
			if (key.Length == "Stash".Length)
			{
				identifier = string.Empty;
				return true;
			}
			if (key["Stash".Length] != '_' || key.Length == "Stash".Length + 1)
			{
				return false;
			}
			identifier = key.Substring("Stash".Length + 1);
			return true;
		}
	}
}
namespace Ryuka.Sulfur.Rummage.Search
{
	internal enum ItemCategory
	{
		All,
		Oils,
		Scrolls,
		Weapons,
		Attachments,
		Consumables,
		Other
	}
	internal static class ItemCategories
	{
		public static readonly ItemCategory[] Selectable = new ItemCategory[6]
		{
			ItemCategory.All,
			ItemCategory.Oils,
			ItemCategory.Scrolls,
			ItemCategory.Weapons,
			ItemCategory.Attachments,
			ItemCategory.Consumables
		};

		public static ItemCategory Next(ItemCategory current)
		{
			int num = Array.IndexOf(Selectable, current);
			return Selectable[(num + 1) % Selectable.Length];
		}
	}
	internal sealed class PinyinName
	{
		private const int MaxLength = 64;

		private readonly string text;

		private readonly string[][] readings;

		private PinyinName(string text, string[][] readings)
		{
			this.text = text;
			this.readings = readings;
		}

		internal static PinyinName Create(string text)
		{
			if (string.IsNullOrEmpty(text) || !PinyinTable.IsAvailable)
			{
				return null;
			}
			if (text.Length > 64)
			{
				text = text.Substring(0, 64);
			}
			string[][] array = null;
			for (int i = 0; i < text.Length; i++)
			{
				string[] array2 = PinyinTable.GetReadings(text[i]);
				if (array2.Length != 0)
				{
					if (array == null)
					{
						array = new string[text.Length][];
					}
					array[i] = array2;
				}
			}
			if (array != null)
			{
				return new PinyinName(text, array);
			}
			return null;
		}

		internal bool Matches(string query)
		{
			if (string.IsNullOrEmpty(query))
			{
				return true;
			}
			for (int i = 0; i < text.Length; i++)
			{
				if (MatchFrom(i, query, 0))
				{
					return true;
				}
			}
			return false;
		}

		private bool MatchFrom(int index, string query, int queryIndex)
		{
			if (queryIndex >= query.Length)
			{
				return true;
			}
			if (index >= this.text.Length)
			{
				return false;
			}
			string[] array = readings[index];
			if (array == null)
			{
				char c = this.text[index];
				if (c == query[queryIndex] && MatchFrom(index + 1, query, queryIndex + 1))
				{
					return true;
				}
				if (!char.IsLetterOrDigit(c))
				{
					return MatchFrom(index + 1, query, queryIndex);
				}
				return false;
			}
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				bool flag = i == 0;
				int j;
				for (j = 0; j < text.Length && queryIndex + j < query.Length && text[j] == query[queryIndex + j]; j++)
				{
				}
				if (j == 0)
				{
					continue;
				}
				if (queryIndex + j >= query.Length)
				{
					if (flag || j == text.Length)
					{
						return true;
					}
					continue;
				}
				if (j == text.Length && MatchFrom(index + 1, query, queryIndex + j))
				{
					return true;
				}
				if (flag)
				{
					if (MatchFrom(index + 1, query, queryIndex + 1))
					{
						return true;
					}
					if (j >= 2 && IsRetroflex(text) && MatchFrom(index + 1, query, queryIndex + 2))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsRetroflex(string reading)
		{
			if (reading.Length < 2 || reading[1] != 'h')
			{
				return false;
			}
			char c = reading[0];
			if (c != 'z' && c != 'c')
			{
				return c == 's';
			}
			return true;
		}
	}
	internal static class PinyinTable
	{
		private const string ResourceName = "Ryuka.Sulfur.Rummage.Search.PinyinTable.bin";

		private static readonly string[] Empty = new string[0];

		private static readonly Dictionary<char, string[]> Cache = new Dictionary<char, string[]>();

		private static string[] syllables;

		private static ushort[] starts;

		private static ushort[] readingIds;

		private static char rangeStart;

		private static char rangeEnd;

		private static bool loaded;

		internal static bool IsAvailable
		{
			get
			{
				Load();
				return syllables != null;
			}
		}

		internal static int CoveredCharacters
		{
			get
			{
				Load();
				if (readingIds != null)
				{
					return readingIds.Length;
				}
				return 0;
			}
		}

		internal static bool IsHan(char character)
		{
			Load();
			if (syllables != null && character >= rangeStart)
			{
				return character <= rangeEnd;
			}
			return false;
		}

		internal static string[] GetReadings(char character)
		{
			if (!IsHan(character))
			{
				return Empty;
			}
			if (Cache.TryGetValue(character, out var value))
			{
				return value;
			}
			int num = character - rangeStart;
			int num2 = starts[num];
			int num3 = starts[num + 1] - num2;
			string[] array = Empty;
			if (num3 > 0)
			{
				array = new string[num3];
				for (int i = 0; i < num3; i++)
				{
					array[i] = syllables[readingIds[num2 + i]];
				}
			}
			Cache[character] = array;
			return array;
		}

		private static void Load()
		{
			if (loaded)
			{
				return;
			}
			loaded = true;
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Ryuka.Sulfur.Rummage.Search.PinyinTable.bin");
				if (stream == null)
				{
					RummagePlugin.Log.LogWarning((object)"The pinyin table is missing from this build; pinyin search is off.");
				}
				else
				{
					Read(stream);
				}
			}
			catch (Exception ex)
			{
				syllables = null;
				starts = null;
				readingIds = null;
				RummagePlugin.Log.LogWarning((object)("Could not read the pinyin table: " + ex.Message + " Pinyin search is off."));
			}
		}

		private static void Read(Stream stream)
		{
			using BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8);
			int num = binaryReader.ReadUInt16();
			int count = (int)binaryReader.ReadUInt32();
			syllables = Encoding.UTF8.GetString(binaryReader.ReadBytes(count)).Split(new char[1] { '\n' });
			if (syllables.Length != num)
			{
				throw new InvalidDataException("expected " + num + " syllables but found " + syllables.Length);
			}
			rangeStart = (char)binaryReader.ReadUInt16();
			rangeEnd = (char)binaryReader.ReadUInt16();
			int num2 = rangeEnd - rangeStart + 1;
			starts = new ushort[num2 + 1];
			List<ushort> list = new List<ushort>(num2 + num2 / 2);
			for (int i = 0; i < num2; i++)
			{
				starts[i] = (ushort)list.Count;
				int num3 = binaryReader.ReadByte();
				for (int j = 0; j < num3; j++)
				{
					list.Add(binaryReader.ReadUInt16());
				}
			}
			starts[num2] = (ushort)list.Count;
			readingIds = list.ToArray();
		}
	}
	internal sealed class SearchQuery
	{
		public static readonly SearchQuery Empty = new SearchQuery(new string[0]);

		private readonly string[] terms;

		private readonly bool[] latinOnly;

		public bool IsEmpty => terms.Length == 0;

		public int TermCount => terms.Length;

		private SearchQuery(string[] terms)
		{
			this.terms = terms;
			latinOnly = new bool[terms.Length];
			for (int i = 0; i < terms.Length; i++)
			{
				latinOnly[i] = IsLatin(terms[i]);
			}
		}

		public static SearchQuery Parse(string text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return Empty;
			}
			string[] array = text.ToLowerInvariant().Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length != 0)
			{
				return new SearchQuery(array);
			}
			return Empty;
		}

		public bool Matches(SearchableText searchable)
		{
			return Matches(searchable, null);
		}

		public bool Matches(SearchableText searchable, IReadOnlyList<SearchableText> more)
		{
			for (int i = 0; i < terms.Length; i++)
			{
				bool flag = searchable?.Contains(terms[i], latinOnly[i]) ?? false;
				if (!flag && more != null)
				{
					for (int j = 0; j < more.Count; j++)
					{
						if (flag)
						{
							break;
						}
						flag = more[j] != null && more[j].Contains(terms[i], latinOnly[i]);
					}
				}
				if (!flag)
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsLatin(string term)
		{
			for (int i = 0; i < term.Length; i++)
			{
				if (term[i] < 'a' || term[i] > 'z')
				{
					return false;
				}
			}
			return term.Length > 0;
		}
	}
	internal sealed class SearchableText
	{
		private static readonly PinyinName[] NoSpokenNames = new PinyinName[0];

		private readonly string[] texts;

		private readonly PinyinName[] spokenNames;

		private SearchableText(string[] texts, PinyinName[] spokenNames)
		{
			this.texts = texts;
			this.spokenNames = spokenNames;
		}

		public static SearchableText Create(IEnumerable<string> sources)
		{
			List<string> list = new List<string>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (sources != null)
			{
				foreach (string source in sources)
				{
					if (!string.IsNullOrWhiteSpace(source))
					{
						string item = source.Trim().ToLowerInvariant();
						if (hashSet.Add(item))
						{
							list.Add(item);
						}
					}
				}
			}
			List<PinyinName> list2 = null;
			foreach (string item2 in list)
			{
				PinyinName pinyinName = PinyinName.Create(item2);
				if (pinyinName != null)
				{
					(list2 ?? (list2 = new List<PinyinName>())).Add(pinyinName);
				}
			}
			return new SearchableText(list.ToArray(), (list2 == null) ? NoSpokenNames : list2.ToArray());
		}

		internal bool Contains(string term, bool latinOnly)
		{
			for (int i = 0; i < texts.Length; i++)
			{
				if (texts[i].IndexOf(term, StringComparison.Ordinal) >= 0)
				{
					return true;
				}
			}
			if (!latinOnly)
			{
				return false;
			}
			for (int j = 0; j < spokenNames.Length; j++)
			{
				if (spokenNames[j].Matches(term))
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace Ryuka.Sulfur.Rummage.Localization
{
	internal static class GameLanguage
	{
		public const string FallbackCode = "en";

		private static readonly string[] ShippedCodes = new string[14]
		{
			"en", "sv", "fr", "it", "de", "es", "pt", "ru", "pl", "ja",
			"ko", "zh-CN", "tr", "ar"
		};

		public static string CurrentCode()
		{
			try
			{
				string currentLanguageCode = LocalizationManager.CurrentLanguageCode;
				return string.IsNullOrEmpty(currentLanguageCode) ? null : currentLanguageCode;
			}
			catch (Exception)
			{
				return null;
			}
		}

		public static bool IsRightToLeft()
		{
			try
			{
				return LocalizationManager.IsRight2Left;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static string FixRightToLeft(string text)
		{
			try
			{
				return LocalizationManager.FixRTL_IfNeeded(text, 0, false);
			}
			catch (Exception)
			{
				return text;
			}
		}

		public static string ResolveCode(string languageCode)
		{
			if (string.IsNullOrEmpty(languageCode))
			{
				return "en";
			}
			string[] shippedCodes = ShippedCodes;
			foreach (string text in shippedCodes)
			{
				if (string.Equals(text, languageCode, StringComparison.OrdinalIgnoreCase))
				{
					return text;
				}
			}
			string b = LanguageOf(languageCode);
			shippedCodes = ShippedCodes;
			foreach (string text2 in shippedCodes)
			{
				if (string.Equals(LanguageOf(text2), b, StringComparison.OrdinalIgnoreCase))
				{
					return text2;
				}
			}
			return "en";
		}

		private static string LanguageOf(string languageCode)
		{
			int num = languageCode.IndexOf('-');
			if (num <= 0)
			{
				return languageCode;
			}
			return languageCode.Substring(0, num);
		}
	}
	internal static class GameTerms
	{
		public const string Consumable = "ItemDescriptions/UseType_Consumable";

		public const string Attachments = "ItemDescriptions/Label_Attachments";

		public static string Get(string term)
		{
			try
			{
				string text = default(string);
				return (LocalizationManager.TryGetTranslation(term, ref text, true, 0, true, false, (GameObject)null, (string)null, true) && !string.IsNullOrWhiteSpace(text)) ? text : null;
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
	internal sealed class LanguageWatcher : IDisposable
	{
		private const float RetrySeconds = 1f;

		private readonly string pluginDirectory;

		private readonly OnLanguageChange handler;

		private AsyncAssetLoading subscribedTo;

		private bool gameLanguageKnown;

		private float nextAttempt;

		public event Action LanguageChanged;

		public LanguageWatcher(string pluginDirectory)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			this.pluginDirectory = pluginDirectory;
			handler = new OnLanguageChange(OnGameLanguageChanged);
		}

		public void Tick()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			AsyncAssetLoading instance = StaticInstance<AsyncAssetLoading>.Instance;
			if (instance != subscribedTo)
			{
				Unsubscribe();
				if ((Object)(object)instance != (Object)null)
				{
					instance.onLanguageChange = (OnLanguageChange)Delegate.Combine((Delegate?)(object)instance.onLanguageChange, (Delegate?)(object)handler);
					subscribedTo = instance;
				}
			}
			if (!gameLanguageKnown && Time.unscaledTime >= nextAttempt)
			{
				nextAttempt = Time.unscaledTime + 1f;
				Load(fromGameEvent: false);
			}
		}

		public void Dispose()
		{
			Unsubscribe();
			this.LanguageChanged = null;
		}

		private void OnGameLanguageChanged()
		{
			Load(fromGameEvent: true);
		}

		private void Load(bool fromGameEvent)
		{
			bool flag = RummageText.Reload(pluginDirectory);
			gameLanguageKnown = RummageText.GameCode != null;
			if (flag)
			{
				string text = "Language: " + RummageText.LoadedCode + " (game language code: " + (RummageText.GameCode ?? "<not loaded yet>") + ") - " + RummageText.LoadedCount + " strings from " + (RummageText.LoadedFrom ?? "<nowhere>");
				if (RummageText.LoadedCount == 0 || RummageText.LastLoadNote != null)
				{
					RummagePlugin.Log.LogWarning((object)(text + " | " + (RummageText.LastLoadNote ?? "no strings")));
				}
				else
				{
					RummagePlugin.Log.LogInfo((object)text);
				}
			}
			if (flag || fromGameEvent)
			{
				Raise();
			}
		}

		private void Raise()
		{
			Action action = this.LanguageChanged;
			if (action == null)
			{
				return;
			}
			Delegate[] invocationList = action.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((Action)obj)();
				}
				catch (Exception ex)
				{
					RummagePlugin.Log.LogError((object)("Language change listener failed: " + ex));
				}
			}
		}

		private void Unsubscribe()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			if (subscribedTo != null)
			{
				AsyncAssetLoading obj = subscribedTo;
				obj.onLanguageChange = (OnLanguageChange)Delegate.Remove((Delegate?)(object)obj.onLanguageChange, (Delegate?)(object)handler);
				subscribedTo = null;
			}
		}
	}
	internal static class RummageText
	{
		[DataContract]
		private sealed class LangEntry
		{
			[DataMember(Name = "key")]
			public string Key;

			[DataMember(Name = "value")]
			public string Value;
		}

		[DataContract]
		private sealed class LangFile
		{
			[DataMember(Name = "entries")]
			public LangEntry[] Entries;
		}

		private static readonly Dictionary<string, string> Strings = new Dictionary<string, string>(StringComparer.Ordinal);

		public static string LoadedCode { get; private set; }

		public static string GameCode { get; private set; }

		public static int LoadedCount => Strings.Count;

		public static string LastLoadNote { get; private set; }

		public static string LoadedFrom { get; private set; }

		public static bool Reload(string pluginDirectory)
		{
			string text = GameLanguage.CurrentCode();
			string text2 = GameLanguage.ResolveCode(text);
			if (LoadedCode == text2 && GameCode == text)
			{
				return false;
			}
			Strings.Clear();
			LastLoadNote = null;
			LoadedFrom = null;
			if (text2 != "en")
			{
				LoadFirstMatch(pluginDirectory, "en");
			}
			LoadFirstMatch(pluginDirectory, text2);
			LoadedCode = text2;
			GameCode = text;
			return true;
		}

		public static string Get(string key, string englishFallback)
		{
			if (!Strings.TryGetValue(key, out var value) || string.IsNullOrEmpty(value))
			{
				return englishFallback;
			}
			return value;
		}

		private static IEnumerable<string> CandidateDirectories(string pluginDirectory)
		{
			if (!string.IsNullOrEmpty(pluginDirectory))
			{
				yield return Path.Combine(pluginDirectory, "lang");
				yield return pluginDirectory;
				string text;
				try
				{
					text = Directory.GetParent(pluginDirectory)?.FullName;
				}
				catch (Exception)
				{
					text = null;
				}
				if (!string.IsNullOrEmpty(text))
				{
					yield return Path.Combine(text, "lang");
				}
			}
		}

		private static void LoadFirstMatch(string pluginDirectory, string code)
		{
			foreach (string item in CandidateDirectories(pluginDirectory))
			{
				if (LoadInto(item, code))
				{
					LoadedFrom = item;
					return;
				}
			}
			LastLoadNote = LastLoadNote ?? ("no readable " + code + ".json under " + (pluginDirectory ?? "<unknown>"));
		}

		private static bool LoadInto(string directory, string code)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(directory, code + ".json");
			if (!File.Exists(text))
			{
				return false;
			}
			try
			{
				LangFile langFile;
				using (MemoryStream memoryStream = new MemoryStream(File.ReadAllBytes(text)))
				{
					langFile = ((XmlObjectSerializer)new DataContractJsonSerializer(typeof(LangFile))).ReadObject((Stream)memoryStream) as LangFile;
				}
				if (langFile == null || langFile.Entries == null)
				{
					LastLoadNote = "no entries in " + text;
					return false;
				}
				bool flag = GameLanguage.IsRightToLeft();
				int num = 0;
				LangEntry[] entries = langFile.Entries;
				foreach (LangEntry langEntry in entries)
				{
					if (langEntry != null && !string.IsNullOrEmpty(langEntry.Key) && langEntry.Value != null)
					{
						Strings[langEntry.Key] = (flag ? GameLanguage.FixRightToLeft(langEntry.Value) : langEntry.Value);
						num++;
					}
				}
				return num > 0;
			}
			catch (Exception ex)
			{
				LastLoadNote = ex.GetType().Name + " reading " + text;
				return false;
			}
		}
	}
}
namespace Ryuka.Sulfur.Rummage.InputGuard
{
	internal static class SearchInputGuard
	{
		public static Func<bool> IsTyping;

		public static Action StopTyping;

		internal static bool Typing()
		{
			try
			{
				return IsTyping != null && IsTyping();
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	[HarmonyPatch]
	internal static class InventoryKeyGuardPatch
	{
		private static readonly string[] Handlers = new string[6] { "InventoryRotateCurrentItem", "InventorySortCurrentGrid", "InventoryUse", "InventoryDrop", "InventorySubmit", "NavigateInventory" };

		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] handlers = Handlers;
			foreach (string text in handlers)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(InputReader), text, new Type[1] { typeof(CallbackContext) }, (Type[])null);
				if (methodInfo == null)
				{
					RummagePlugin.Log.LogWarning((object)("InputReader." + text + " was not found; its key may act on the inventory while typing in the search box."));
				}
				else
				{
					yield return methodInfo;
				}
			}
		}

		private static bool Prefix()
		{
			return !SearchInputGuard.Typing();
		}
	}
	[HarmonyPatch(typeof(InputReader), "InventoryCancel")]
	internal static class InventoryCancelGuardPatch
	{
		private static bool Prefix(CallbackContext context)
		{
			if (!SearchInputGuard.Typing())
			{
				return true;
			}
			Keyboard current = Keyboard.current;
			if (current != null && (object)((CallbackContext)(ref context)).control == current.escapeKey)
			{
				SearchInputGuard.StopTyping?.Invoke();
			}
			return false;
		}
	}
}
namespace Ryuka.Sulfur.Rummage.Game
{
	internal static class InventoryLegend
	{
		private static ConfigEntry<bool> hide;

		private static FieldRef<InventoryUI, GameObject> keyboardRow;

		private static FieldRef<InventoryUI, GameObject> gamepadRow;

		private static bool lastGamepadState;

		private static bool hasLastState;

		public static void Initialize(ConfigEntry<bool> hideSetting)
		{
			hide = hideSetting;
			try
			{
				keyboardRow = AccessTools.FieldRefAccess<InventoryUI, GameObject>("LegendKeyboard");
				gamepadRow = AccessTools.FieldRefAccess<InventoryUI, GameObject>("LegendGamepad");
			}
			catch (Exception ex)
			{
				keyboardRow = null;
				gamepadRow = null;
				RummagePlugin.Log.LogWarning((object)("InventoryUI.LegendKeyboard / LegendGamepad were not found; the inventory key hints cannot be hidden. " + ex.Message));
			}
			hide.SettingChanged += OnSettingChanged;
		}

		public static void Shutdown()
		{
			if (hide != null)
			{
				hide.SettingChanged -= OnSettingChanged;
			}
		}

		public static void AfterToggle(InventoryUI ui, bool gamepadState)
		{
			lastGamepadState = gamepadState;
			hasLastState = true;
			if (hide != null && hide.Value)
			{
				HideRows(ui);
			}
		}

		private static void OnSettingChanged(object sender, EventArgs e)
		{
			UIManager instance = StaticInstance<UIManager>.Instance;
			InventoryUI val = (((Object)(object)instance != (Object)null) ? instance.InventoryUI : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				if (hide.Value)
				{
					HideRows(val);
				}
				else if (hasLastState)
				{
					val.ToggleGamepadLegend(lastGamepadState);
				}
			}
			catch (Exception ex)
			{
				RummagePlugin.Log.LogWarning((object)("Applying the key hint setting failed: " + ex.Message));
			}
		}

		private static void HideRows(InventoryUI ui)
		{
			if (keyboardRow != null && gamepadRow != null && !((Object)(object)ui == (Object)null))
			{
				GameObject val = keyboardRow.Invoke(ui);
				GameObject val2 = gamepadRow.Invoke(ui);
				if ((Object)(object)val != (Object)null && val.activeSelf)
				{
					val.SetActive(false);
				}
				if ((Object)(object)val2 != (Object)null && val2.activeSelf)
				{
					val2.SetActive(false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryUI), "ToggleGamepadLegend")]
	internal static class InventoryLegendPatch
	{
		private static void Postfix(InventoryUI __instance, bool state)
		{
			try
			{
				InventoryLegend.AfterToggle(__instance, state);
			}
			catch (Exception ex)
			{
				RummagePlugin.Log.LogWarning((object)("Hiding the inventory key hints failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(InventoryUI), "SetState")]
	internal static class InventoryStatePatch
	{
		internal static event Action<InventoryUI, UIState> StateSet;

		private static void Postfix(InventoryUI __instance, UIState state)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Action<InventoryUI, UIState> stateSet = InventoryStatePatch.StateSet;
			if (stateSet == null)
			{
				return;
			}
			try
			{
				stateSet(__instance, state);
			}
			catch (Exception ex)
			{
				RummagePlugin.Log.LogError((object)("Inventory open/close handling failed: " + ex));
			}
		}
	}
	internal static class ItemMatcher
	{
		private static readonly List<SearchableText> Applied = new List<SearchableText>();

		public static bool Matches(InventoryItem item, InventoryFilter filter)
		{
			ItemSearchCatalog.Entry entry = ItemSearchCatalog.Get(item.itemDefinition);
			Applied.Clear();
			if (UsesApplied(filter) && item.enchantments != null)
			{
				foreach (EnchantmentDefinition enchantment in item.enchantments)
				{
					SearchableText applied = ItemSearchCatalog.GetApplied(enchantment);
					if (applied != null)
					{
						Applied.Add(applied);
					}
				}
			}
			return filter.Accepts(entry.Category, entry.Text, Applied);
		}

		public static bool Matches(InventoryData data, ItemDefinition definition, InventoryFilter filter)
		{
			//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_0040: Unknown result type (might be due to invalid IL or missing references)
			ItemSearchCatalog.Entry entry = ItemSearchCatalog.Get(definition);
			Applied.Clear();
			if (UsesApplied(filter) && data.enchantmentIds != null)
			{
				ItemId[] enchantmentIds = data.enchantmentIds;
				for (int i = 0; i < enchantmentIds.Length; i++)
				{
					ItemId val = enchantmentIds[i];
					ItemDefinition val2 = (((ItemId)(ref val)).IsValid ? AssetAccess.GetAsset(val) : null);
					if ((Object)(object)val2 != (Object)null)
					{
						Applied.Add(ItemSearchCatalog.Get(val2).Text);
					}
				}
			}
			return filter.Accepts(entry.Category, entry.Text, Applied);
		}

		private static bool UsesApplied(InventoryFilter filter)
		{
			if (filter.IncludeAppliedEnchantments)
			{
				return !filter.Query.IsEmpty;
			}
			return false;
		}
	}
	internal static class ItemSearchCatalog
	{
		internal sealed class Entry
		{
			public ItemCategory Category { get; }

			public SearchableText Text { get; }

			public Entry(ItemCategory category, SearchableText text)
			{
				Category = category;
				Text = text;
			}
		}

		private static readonly Dictionary<ItemDefinition, Entry> Entries = new Dictionary<ItemDefinition, Entry>();

		private static readonly Entry Unindexed = new Entry(ItemCategory.Other, SearchableText.Create(null));

		private static bool indexFailureReported;

		private static readonly Dictionary<EnchantmentDefinition, SearchableText> EnchantmentTexts = new Dictionary<EnchantmentDefinition, SearchableText>();

		private static readonly string[] Placeholders = new string[5] { "VALUE_X", "DURATION_X", "AMOUNT_X", "STATUS_X", "ATTRIBUTE_X" };

		public static void Invalidate()
		{
			Entries.Clear();
			EnchantmentTexts.Clear();
		}

		public static SearchableText GetApplied(EnchantmentDefinition enchantment)
		{
			if ((Object)(object)enchantment == (Object)null)
			{
				return null;
			}
			if ((Object)(object)enchantment.ItemThatAppliedThis != (Object)null)
			{
				return Get(enchantment.ItemThatAppliedThis).Text;
			}
			if (!EnchantmentTexts.TryGetValue(enchantment, out var value))
			{
				List<string> list = new List<string>();
				try
				{
					list.Add(Translate("EnchantmentDefinitions/" + ((Object)enchantment).name, enchantment.enchantmentName));
					list.Add(enchantment.enchantmentName);
					AddModifierTexts(enchantment.modifiersApplied, onlyShownInDescription: true, list);
				}
				catch (Exception)
				{
				}
				value = SearchableText.Create(list);
				EnchantmentTexts[enchantment] = value;
			}
			return value;
		}

		public static Entry Get(ItemDefinition item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return Unindexed;
			}
			if (!Entries.TryGetValue(item, out var value))
			{
				value = Build(item);
				Entries[item] = value;
			}
			return value;
		}

		private static Entry Build(ItemDefinition item)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<string> list = new List<string>();
				list.Add(Translate("Items/" + ((Object)item).name, item.displayName));
				list.Add(item.displayName);
				EnchantmentDefinition val = (((EnchantmentId)(ref item.appliesEnchantment)).IsValid ? AssetAccess.GetAsset(item.appliesEnchantment) : null);
				if ((Object)(object)val != (Object)null)
				{
					list.Add(Translate("EnchantmentDefinitions/" + ((Object)val).name, val.enchantmentName));
					list.Add(val.enchantmentName);
					AddModifierTexts(val.modifiersApplied, onlyShownInDescription: true, list);
				}
				AddModifierTexts(item.modifiersOnAttachToItem, onlyShownInDescription: false, list);
				AddDescriptionTexts(item, list);
				return new Entry(Classify(item, val), SearchableText.Create(list));
			}
			catch (Exception ex)
			{
				if (!indexFailureReported)
				{
					indexFailureReported = true;
					RummagePlugin.Log.LogWarning((object)("Could not index item '" + ((Object)item).name + "' for search; it will not match any search or category. Further indexing failures are not logged. " + ex));
				}
				return Unindexed;
			}
		}

		private static void AddModifierTexts(List<ItemModifierContainer> modifiers, bool onlyShownInDescription, List<string> sources)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (modifiers == null)
			{
				return;
			}
			foreach (ItemModifierContainer modifier in modifiers)
			{
				if (modifier == null || (int)modifier.attribute == 0)
				{
					continue;
				}
				ItemAttribute asset = AssetAccess.GetAsset(modifier.attribute);
				if (!((Object)(object)asset == (Object)null) && (!onlyShownInDescription || asset.showInItemDescription))
				{
					string text = "ItemAttributes/" + ((object)Unsafe.As<ItemAttributes, ItemAttributes>(ref modifier.attribute)/*cast due to .constrained prefix*/).ToString();
					if (asset.simplifiedModAmount)
					{
						sources.Add((modifier.value > 0f) ? Translate(text + "_simplifiedIncrease", asset.simplifiedIncreaseString) : Translate(text + "_simplifiedDecrease", asset.simplifiedDecreaseString));
					}
					else
					{
						sources.Add(Translate(text + "_itemDescription", asset.itemDescriptionName));
					}
				}
			}
		}

		private static void AddDescriptionTexts(ItemDefinition item, List<string> sources)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			//IL_00b2: 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_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Invalid comparison between Unknown and I4
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Invalid comparison between Unknown and I4
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Invalid comparison between Unknown and I4
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			if (item.hasCustomDescription)
			{
				sources.Add(Translate("Items/" + ((Object)item).name + "_description", null));
			}
			if (item.valueChangeOnItemConsume != null)
			{
				foreach (ItemConsumeContainer item2 in item.valueChangeOnItemCo