Decompiled source of Workstation Search v0.6.13

BepInEx/plugins/WorkstationSearch/WorkstationSearch.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.TextCore;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("WorkstationSearch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.6.13.0")]
[assembly: AssemblyInformationalVersion("0.6.13+4ffcaab1e4f98228d20a3ecb8f71f43710e21361")]
[assembly: AssemblyProduct("WorkstationSearch")]
[assembly: AssemblyTitle("WorkstationSearch")]
[assembly: AssemblyVersion("0.6.13.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WorkstationSearch
{
	public sealed class CategoryEditor : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Func<ItemCategory, string> <0>__Friendly;

			public static UnityAction <1>__Close;
		}

		private static CategoryEditor current;

		private static readonly FieldInfo CraftTimer = AccessTools.Field(typeof(InventoryGui), "m_craftTimer");

		private InventoryGui gui;

		private SpellingEntry item;

		private CategoryOverride draft;

		private TMP_InputField terms;

		private TMP_Text status;

		private readonly Dictionary<ItemCategory, Toggle> toggles = new Dictionary<ItemCategory, Toggle>();

		private Sprite checkSprite;

		private Texture2D checkTexture;

		private readonly Dictionary<ItemCategory, TMP_Text> labels = new Dictionary<ItemCategory, TMP_Text>();

		internal static bool IsOpen => Object.op_Implicit((Object)(object)current);

		internal static void Open(InventoryGui owner, SpellingEntry entry)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)owner) || entry == null || string.IsNullOrEmpty(entry.Prefab) || (float)CraftTimer.GetValue(owner) >= 0f)
			{
				return;
			}
			Canvas componentInParent = ((Component)owner.m_recipeListRoot).GetComponentInParent<Canvas>();
			if (Object.op_Implicit((Object)(object)componentInParent))
			{
				Close();
				if (Object.op_Implicit((Object)(object)EventSystem.current))
				{
					EventSystem.current.SetSelectedGameObject((GameObject)null);
				}
				GameObject val = new GameObject("WorkstationSearchCategories", new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(CategoryEditor)
				});
				RectTransform val2 = (RectTransform)val.transform;
				((Transform)val2).SetParent(((Component)componentInParent).transform, false);
				val2.anchorMin = Vector2.zero;
				val2.anchorMax = Vector2.one;
				Vector2 offsetMin = (val2.offsetMax = Vector2.zero);
				val2.offsetMin = offsetMin;
				((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.8f);
				current = val.GetComponent<CategoryEditor>();
				current.gui = owner;
				current.item = entry;
				current.draft = Plugin.Overrides.Get(entry.Prefab);
				current.Build(componentInParent);
				SearchPanel.SuppressInputFrame();
			}
		}

		internal static void Close()
		{
			if (Object.op_Implicit((Object)(object)current))
			{
				CategoryEditor categoryEditor = current;
				current = null;
				((Component)categoryEditor).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)categoryEditor).gameObject);
				if (Object.op_Implicit((Object)(object)EventSystem.current))
				{
					EventSystem.current.SetSelectedGameObject((GameObject)null);
				}
				SearchPanel.SuppressInputFrame();
			}
		}

		private void Build(Canvas canvas)
		{
			//IL_0039: 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_0042: 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_004a: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_00ab: 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_00e4: 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_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f3: Expected O, but got Unknown
			//IL_0652: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Expected O, but got Unknown
			//IL_061f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0624: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Expected O, but got Unknown
			RectTransform val = Rect("Editor", ((Component)this).transform, 0f, 0f, 760f, 670f);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = Vector2.zero;
			Rect rect = ((RectTransform)((Component)canvas).transform).rect;
			Vector2 size = ((Rect)(ref rect)).size;
			float num = Mathf.Min(1f, Mathf.Min((size.x - 24f) / 760f, (size.y - 24f) / 670f));
			((Transform)val).localScale = Vector3.one * Mathf.Max(0.2f, num);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(0.12f, 0.105f, 0.085f, 1f);
			Text((Transform)(object)val, "Search categories", 20f, 14f, 720f, 32f, 24f);
			Text((Transform)(object)val, item.Name, 20f, 49f, 720f, 30f, 20f).overflowMode = (TextOverflowModes)1;
			Text((Transform)(object)val, "Check categories to enable them. Categories marked auto were detected.\nChanges apply to this item type in Craft and Upgrade.", 20f, 86f, 720f, 48f, 16f);
			RectTransform val4 = Rect("Categories", (Transform)(object)val, 20f, 144f, 704f, 292f);
			((Graphic)((Component)val4).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.2f);
			((Component)val4).gameObject.AddComponent<RectMask2D>();
			RectTransform val5 = Rect("Content", (Transform)(object)val4, 0f, 0f, 704f, 0f);
			ScrollRect val6 = ((Component)val4).gameObject.AddComponent<ScrollRect>();
			val6.viewport = val4;
			val6.content = val5;
			val6.horizontal = false;
			val6.movementType = (MovementType)2;
			val6.scrollSensitivity = 350f;
			ItemCategory[] array = Enum.GetValues(typeof(ItemCategory)).Cast<ItemCategory>().OrderBy(Friendly)
				.ToArray();
			val5.sizeDelta = new Vector2(704f, (float)((array.Length + 2) / 3 * 42));
			for (int i = 0; i < array.Length; i++)
			{
				ItemCategory category = array[i];
				AddCategoryToggle((Transform)(object)val5, category, i % 3 * 235, i / 3 * 42);
			}
			RectTransform val7 = Rect("Scrollbar", (Transform)(object)val, 730f, 144f, 10f, 292f);
			((Graphic)((Component)val7).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f);
			RectTransform val8 = Rect("Sliding Area", (Transform)(object)val7, 0f, 0f, 10f, 292f);
			SearchPanel.Stretch(val8);
			RectTransform val9 = Rect("Handle", (Transform)(object)val8, 0f, 0f, 0f, 0f);
			SearchPanel.Stretch(val9);
			Image val10 = ((Component)val9).gameObject.AddComponent<Image>();
			((Graphic)val10).color = new Color(0.8f, 0.58f, 0.25f);
			Scrollbar val11 = ((Component)val7).gameObject.AddComponent<Scrollbar>();
			val11.handleRect = val9;
			((Selectable)val11).targetGraphic = (Graphic)(object)val10;
			val11.direction = (Direction)2;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)val11).navigation = navigation;
			val6.verticalScrollbar = val11;
			val6.verticalNormalizedPosition = 1f;
			Text((Transform)(object)val, "Custom search words", 20f, 449f, 720f, 24f, 18f);
			RectTransform val12 = Rect("CustomWords", (Transform)(object)val, 20f, 480f, 720f, 36f);
			Image val13 = ((Component)val12).gameObject.AddComponent<Image>();
			((Graphic)val13).color = new Color(0.25f, 0.23f, 0.2f);
			RectTransform val14 = Rect("Text Area", (Transform)(object)val12, 10f, 0f, 700f, 36f);
			((Component)val14).gameObject.AddComponent<RectMask2D>();
			TMP_Text textComponent = Text((Transform)(object)val14, "", 0f, 0f, 700f, 36f, 18f);
			TMP_Text val15 = Text((Transform)(object)val14, "Example: dragon, winter, sailing", 0f, 0f, 700f, 36f, 18f);
			((Graphic)val15).color = new Color(0.65f, 0.62f, 0.57f);
			terms = ((Component)val12).gameObject.AddComponent<TMP_InputField>();
			terms.textViewport = val14;
			terms.textComponent = textComponent;
			terms.placeholder = (Graphic)(object)val15;
			((Selectable)terms).targetGraphic = (Graphic)(object)val13;
			terms.lineType = (LineType)0;
			string text = string.Join(", ", draft.Terms);
			terms.characterLimit = Mathf.Max(512, text.Length);
			terms.text = text;
			Text((Transform)(object)val, "Separate words with spaces or commas. Names remain searchable when categories are disabled.\nSettings stay saved even if the item's mod is removed.", 20f, 525f, 720f, 42f, 15f);
			status = Text((Transform)(object)val, "", 20f, 574f, 720f, 30f, 15f);
			Button((Transform)(object)val, "Reset to automatic", 20f, 620f, 240f, 34f, (UnityAction)delegate
			{
				draft = new CategoryOverride();
				terms.text = "";
				status.text = "Automatic settings restored. Save to apply.";
				RefreshLabels();
			});
			object obj = <>O.<1>__Close;
			if (obj == null)
			{
				UnityAction val16 = Close;
				<>O.<1>__Close = val16;
				obj = (object)val16;
			}
			Button((Transform)(object)val, "Cancel", 490f, 620f, 115f, 34f, (UnityAction)obj);
			Button((Transform)(object)val, "Save", 625f, 620f, 115f, 34f, new UnityAction(Save));
			RefreshLabels();
		}

		private void Save()
		{
			if (Object.op_Implicit((Object)(object)gui) && !((float)CraftTimer.GetValue(gui) >= 0f))
			{
				draft.Terms = CategoryOverride.ParseTerms(terms.text);
				if (!Plugin.SaveOverride(item.Prefab, draft))
				{
					status.text = "Could not save. See the BepInEx log; existing settings were kept.";
					return;
				}
				FavoriteRows.RefreshOverrides(item.Prefab);
				Close();
			}
		}

		private void RefreshLabels()
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			HashSet<ItemCategory> hashSet = new HashSet<ItemCategory>(draft.Apply(item.Categories));
			foreach (KeyValuePair<ItemCategory, TMP_Text> label in labels)
			{
				bool flag = hashSet.Contains(label.Key);
				toggles[label.Key].SetIsOnWithoutNotify(flag);
				label.Value.text = Friendly(label.Key) + (item.Categories.Contains(label.Key) ? " (auto)" : "");
				((Graphic)label.Value).color = (flag ? new Color(1f, 0.8f, 0.35f) : new Color(0.68f, 0.66f, 0.62f));
			}
		}

		private void AddCategoryToggle(Transform parent, ItemCategory category, float x, float y)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = Rect(category.ToString(), parent, x, y, 228f, 38f);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.18f);
			Toggle val2 = ((Component)val).gameObject.AddComponent<Toggle>();
			RectTransform val3 = Rect("Checkbox", (Transform)(object)val, 5f, 8f, 22f, 22f);
			((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = new Color(0.7f, 0.56f, 0.32f);
			Image val4 = ((Component)Rect("Background", (Transform)(object)val3, 2f, 2f, 18f, 18f)).gameObject.AddComponent<Image>();
			((Graphic)val4).color = new Color(0.18f, 0.16f, 0.12f);
			Image val5 = ((Component)Rect("Checkmark", (Transform)(object)val3, 1f, 1f, 20f, 20f)).gameObject.AddComponent<Image>();
			if (!Object.op_Implicit((Object)(object)checkSprite))
			{
				CreateCheckmark();
			}
			val5.sprite = checkSprite;
			((Graphic)val5).color = new Color(1f, 0.8f, 0.35f);
			((Graphic)val5).raycastTarget = false;
			SearchPanel.CopySelectable((Selectable)(object)gui.m_craftCancelButton, (Selectable)(object)val2);
			((Selectable)val2).targetGraphic = (Graphic)(object)val4;
			val2.graphic = (Graphic)(object)val5;
			val2.toggleTransition = (ToggleTransition)0;
			labels.Add(category, Text((Transform)(object)val, "", 34f, 0f, 190f, 38f, 14f));
			toggles.Add(category, val2);
			((UnityEvent<bool>)(object)val2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool enabled)
			{
				if (draft.Apply(item.Categories).Contains(category) != enabled)
				{
					draft.Toggle(category, item.Categories);
				}
				RefreshLabels();
			});
		}

		private void CreateCheckmark()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0112: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			checkTexture = new Texture2D(32, 32, (TextureFormat)4, false);
			((Object)checkTexture).name = "WorkstationSearchCheckmark";
			((Texture)checkTexture).wrapMode = (TextureWrapMode)1;
			((Texture)checkTexture).filterMode = (FilterMode)1;
			Vector2 a = default(Vector2);
			((Vector2)(ref a))..ctor(5f, 16f);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(13f, 8f);
			Vector2 b = default(Vector2);
			((Vector2)(ref b))..ctor(27f, 25f);
			Vector2 point = default(Vector2);
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					((Vector2)(ref point))..ctor((float)j + 0.5f, (float)i + 0.5f);
					float num = Mathf.Min(SegmentDistance(point, a, val), SegmentDistance(point, val, b));
					checkTexture.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(2.6f - num)));
				}
			}
			checkTexture.Apply(false, true);
			checkSprite = Sprite.Create(checkTexture, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f);
		}

		private static float SegmentDistance(Vector2 point, Vector2 a, Vector2 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = b - a;
			float num = Mathf.Clamp01(Vector2.Dot(point - a, val) / ((Vector2)(ref val)).sqrMagnitude);
			return Vector2.Distance(point, a + val * num);
		}

		private static string Friendly(ItemCategory category)
		{
			return Regex.Replace(category.ToString(), "([a-z])([A-Z])", "$1 $2");
		}

		private TMP_Text Button(Transform parent, string title, float x, float y, float width, float height, UnityAction action)
		{
			RectTransform val = Rect((title.Length == 0) ? "Category" : title, parent, x, y, width, height);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			Button val3 = ((Component)val).gameObject.AddComponent<Button>();
			Graphic targetGraphic = ((Selectable)gui.m_craftCancelButton).targetGraphic;
			SearchPanel.CopyImage((Image)(object)((targetGraphic is Image) ? targetGraphic : null), val2);
			SearchPanel.CopySelectable((Selectable)(object)gui.m_craftCancelButton, (Selectable)(object)val3);
			((Selectable)val3).targetGraphic = (Graphic)(object)val2;
			((UnityEvent)val3.onClick).AddListener(action);
			TMP_Text obj = Text((Transform)(object)val, title, 5f, 0f, width - 10f, height, 16f);
			obj.alignment = (TextAlignmentOptions)514;
			return obj;
		}

		private TMP_Text Text(Transform parent, string value, float x, float y, float width, float height, float size)
		{
			TextMeshProUGUI obj = SearchPanel.Label("Label", parent, gui.m_recipeName, value);
			Position(((TMP_Text)obj).rectTransform, x, y, width, height);
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).richText = false;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
			return (TMP_Text)(object)obj;
		}

		private static RectTransform Rect(string name, Transform parent, float x, float y, float width, float height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0038: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
			((Transform)val).SetParent(parent, false);
			Position(val, x, y, width, height);
			return val;
		}

		private static void Position(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			rect.pivot = val;
			Vector2 anchorMin = (rect.anchorMax = val);
			rect.anchorMin = anchorMin;
			rect.anchoredPosition = new Vector2(x, 0f - y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private void Update()
		{
			if (!Object.op_Implicit((Object)(object)gui) || !InventoryGui.IsVisible() || (float)CraftTimer.GetValue(gui) >= 0f || Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)current == (Object)(object)this)
			{
				current = null;
			}
			if (Object.op_Implicit((Object)(object)checkSprite))
			{
				Object.Destroy((Object)(object)checkSprite);
			}
			if (Object.op_Implicit((Object)(object)checkTexture))
			{
				Object.Destroy((Object)(object)checkTexture);
			}
		}
	}
	internal sealed class CategoryOverride
	{
		internal readonly HashSet<string> Added = new HashSet<string>(StringComparer.Ordinal);

		internal readonly HashSet<string> Disabled = new HashSet<string>(StringComparer.Ordinal);

		internal string[] Terms = new string[0];

		internal bool IsEmpty
		{
			get
			{
				if (Added.Count == 0 && Disabled.Count == 0)
				{
					return Terms.Length == 0;
				}
				return false;
			}
		}

		internal CategoryOverride Copy()
		{
			CategoryOverride categoryOverride = new CategoryOverride();
			categoryOverride.Terms = (string[])Terms.Clone();
			categoryOverride.Added.UnionWith(Added);
			categoryOverride.Disabled.UnionWith(Disabled);
			return categoryOverride;
		}

		internal ItemCategory[] Apply(IEnumerable<ItemCategory> detected)
		{
			IEnumerable<ItemCategory> second = from ItemCategory c in Enum.GetValues(typeof(ItemCategory))
				where Added.Contains(c.ToString())
				select c;
			return (from c in CategoryHierarchy.Expand(detected.Concat(second))
				where !Disabled.Contains(c.ToString())
				select c).ToArray();
		}

		internal void Toggle(ItemCategory category, ItemCategory[] detected)
		{
			string item = category.ToString();
			if (Apply(detected).Contains(category))
			{
				Added.Remove(item);
				Disabled.Add(item);
				return;
			}
			Disabled.Remove(item);
			if (!Apply(detected).Contains(category))
			{
				Added.Add(item);
			}
		}

		internal static string[] ParseTerms(string text)
		{
			return (text ?? "").Split(new char[5] { ' ', ',', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
		}
	}
	internal sealed class CategoryOverrides
	{
		private readonly Dictionary<string, CategoryOverride> items = new Dictionary<string, CategoryOverride>(StringComparer.Ordinal);

		internal CategoryOverride Get(string prefab)
		{
			if (!items.TryGetValue(prefab, out var value))
			{
				return new CategoryOverride();
			}
			return value.Copy();
		}

		internal void Set(string prefab, CategoryOverride value)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				throw new ArgumentException("Missing item prefab ID.", "prefab");
			}
			if (value.IsEmpty)
			{
				items.Remove(prefab);
			}
			else
			{
				items[prefab] = value.Copy();
			}
		}

		internal SpellingEntry Apply(SpellingEntry entry)
		{
			if (entry == null || !items.TryGetValue(entry.Prefab, out var value))
			{
				return entry;
			}
			return entry.WithSearchCategories(value.Apply(entry.Categories), value.Terms);
		}

		internal string Save()
		{
			return "1:" + string.Join(";", from p in items.OrderBy<KeyValuePair<string, CategoryOverride>, string>((KeyValuePair<string, CategoryOverride> p) => p.Key, StringComparer.Ordinal)
				select Encode(p.Key) + "|" + Join(p.Value.Added.OrderBy<string, string>((string x) => x, StringComparer.Ordinal)) + "|" + Join(p.Value.Disabled.OrderBy<string, string>((string x) => x, StringComparer.Ordinal)) + "|" + Join(p.Value.Terms));
		}

		internal static CategoryOverrides Load(string text)
		{
			CategoryOverrides categoryOverrides = new CategoryOverrides();
			if (string.IsNullOrEmpty(text))
			{
				return categoryOverrides;
			}
			if (!text.StartsWith("1:", StringComparison.Ordinal))
			{
				throw new FormatException("Unsupported category override format.");
			}
			string[] array = text.Substring(2).Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				if (array2.Length != 4)
				{
					throw new FormatException("Invalid category override record.");
				}
				CategoryOverride categoryOverride = new CategoryOverride
				{
					Terms = Split(array2[3])
				};
				categoryOverride.Added.UnionWith(Split(array2[1]));
				categoryOverride.Disabled.UnionWith(Split(array2[2]));
				categoryOverrides.Set(Uri.UnescapeDataString(array2[0]), categoryOverride);
			}
			return categoryOverrides;
		}

		private static string Encode(string value)
		{
			return Uri.EscapeDataString(value);
		}

		private static string Join(IEnumerable<string> values)
		{
			return string.Join(",", values.Select(Encode));
		}

		private static string[] Split(string text)
		{
			return text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(Uri.UnescapeDataString).ToArray();
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
	internal static class CraftRowReuse
	{
		private static InventoryGui owner;

		private static readonly RebuildPool<Recipe, GameObject> pool = new RebuildPool<Recipe, GameObject>();

		internal static bool ReleaseHookReady;

		internal static bool CreationHookReady;

		private static readonly Dictionary<UnityEvent, CraftRowIdentity> clicks = new Dictionary<UnityEvent, CraftRowIdentity>();

		internal static void Begin(InventoryGui __instance, IEnumerable<GameObject> rows)
		{
			Finish();
			if (!ReleaseHookReady || !CreationHookReady || !__instance.InCraftTab())
			{
				return;
			}
			owner = __instance;
			foreach (GameObject row in rows)
			{
				CraftRowIdentity craftRowIdentity = (Object.op_Implicit((Object)(object)row) ? row.GetComponent<CraftRowIdentity>() : null);
				if (Object.op_Implicit((Object)(object)craftRowIdentity) && Object.op_Implicit((Object)(object)craftRowIdentity.Recipe) && !((Object)(object)craftRowIdentity.Prefab != (Object)(object)__instance.m_recipeElementPrefab))
				{
					pool.Add(craftRowIdentity.Recipe, row);
				}
			}
		}

		private static void Finalizer()
		{
			Finish();
		}

		internal static void Finish()
		{
			foreach (GameObject item in pool.Unused)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					item.SetActive(false);
					Object.Destroy((Object)(object)item);
				}
			}
			pool.Clear();
			clicks.Clear();
			owner = null;
		}

		private static void ReleaseRow(Object value)
		{
			GameObject val = (GameObject)(object)((value is GameObject) ? value : null);
			if (val == null || !pool.Contains(val))
			{
				Object.Destroy(value);
			}
		}

		internal static GameObject GetRow(GameObject prefab, Transform parent, Recipe recipe)
		{
			if (Object.op_Implicit((Object)(object)owner) && (Object)(object)parent == (Object)(object)owner.m_recipeListRoot)
			{
				GameObject val;
				while ((val = pool.Take(recipe)) != null)
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						CraftRowIdentity component = val.GetComponent<CraftRowIdentity>();
						if (component.Click != null)
						{
							((UnityEvent)val.GetComponent<Button>().onClick).RemoveListener(component.Click);
						}
						component.Click = null;
						clicks[(UnityEvent)(object)val.GetComponent<Button>().onClick] = component;
						Transform val2 = val.transform.Find("selected");
						if (Object.op_Implicit((Object)(object)val2))
						{
							((Component)val2).gameObject.SetActive(false);
						}
						return val;
					}
				}
			}
			GameObject val3 = Object.Instantiate<GameObject>(prefab, parent);
			if (Object.op_Implicit((Object)(object)owner) && (Object)(object)parent == (Object)(object)owner.m_recipeListRoot)
			{
				CraftRowIdentity craftRowIdentity = val3.AddComponent<CraftRowIdentity>();
				craftRowIdentity.Recipe = recipe;
				craftRowIdentity.Prefab = prefab;
				clicks[(UnityEvent)(object)val3.GetComponent<Button>().onClick] = craftRowIdentity;
			}
			return val3;
		}

		internal static void AddClick(UnityEvent clickEvent, UnityAction listener)
		{
			clickEvent.AddListener(listener);
			if (clicks.TryGetValue(clickEvent, out var value))
			{
				value.Click = listener;
				clicks.Remove(clickEvent);
			}
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo destroy = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null);
			List<CodeInstruction> list = instructions.ToList();
			ReleaseHookReady = list.Count((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, destroy)) == 1;
			foreach (CodeInstruction item in list)
			{
				if (ReleaseHookReady && CodeInstructionExtensions.Calls(item, destroy))
				{
					item.operand = AccessTools.Method(typeof(CraftRowReuse), "ReleaseRow", (Type[])null, (Type[])null);
				}
				yield return item;
			}
		}
	}
	internal sealed class CraftRowIdentity : MonoBehaviour
	{
		internal Recipe Recipe;

		internal GameObject Prefab;

		internal UnityAction Click;
	}
	[HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")]
	internal static class CraftRowCreation
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo addListener = AccessTools.Method(typeof(UnityEvent), "AddListener", new Type[1] { typeof(UnityAction) }, (Type[])null);
			CraftRowReuse.CreationHookReady = list.Count(IsRowCreation) == 1 && list.Count((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, addListener)) == 1;
			if (!CraftRowReuse.CreationHookReady)
			{
				return list;
			}
			List<CodeInstruction> list2 = new List<CodeInstruction>();
			foreach (CodeInstruction item in list)
			{
				if (IsRowCreation(item))
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_2, (object)null);
					val.labels.AddRange(item.labels);
					item.labels.Clear();
					val.blocks.AddRange(item.blocks);
					item.blocks.Clear();
					list2.Add(val);
					item.operand = AccessTools.Method(typeof(CraftRowReuse), "GetRow", (Type[])null, (Type[])null);
				}
				else if (CodeInstructionExtensions.Calls(item, addListener))
				{
					item.opcode = OpCodes.Call;
					item.operand = AccessTools.Method(typeof(CraftRowReuse), "AddClick", (Type[])null, (Type[])null);
				}
				list2.Add(item);
			}
			return list2;
		}

		private static bool IsRowCreation(CodeInstruction instruction)
		{
			if (instruction.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Object) && methodInfo.Name == "Instantiate" && methodInfo.IsGenericMethod && methodInfo.GetGenericArguments()[0] == typeof(GameObject) && methodInfo.GetParameters().Length == 2)
			{
				return methodInfo.GetParameters()[1].ParameterType == typeof(Transform);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
	internal static class FavoriteRows
	{
		private static readonly FieldInfo Available = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

		private static readonly Type Pair = Available.FieldType.GetGenericArguments()[0];

		private static readonly PropertyInfo RecipeProperty = Pair.GetProperty("Recipe");

		private static readonly PropertyInfo Element = Pair.GetProperty("InterfaceElement");

		private static readonly FieldInfo BaseSize = AccessTools.Field(typeof(InventoryGui), "m_recipeListBaseSize");

		private static readonly MethodInfo SelectedIndex = AccessTools.Method(typeof(InventoryGui), "GetSelectedRecipeIndex", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetRecipe = AccessTools.Method(typeof(InventoryGui), "SetRecipe", (Type[])null, (Type[])null);

		private static readonly FieldInfo Selected = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

		private static InventoryGui owner;

		private static List<object> cachedRows;

		private static List<object> appliedRows;

		private static bool preserveIndices;

		private static readonly RowEntryCache SearchEntries = new RowEntryCache();

		private static readonly Dictionary<GameObject, SpellingEntry> RowEntries = new Dictionary<GameObject, SpellingEntry>();

		private static SpellingEntry RowEntry(object pair)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			GameObject val = (GameObject)Element.GetValue(pair, null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			if (!RowEntries.TryGetValue(val, out var value))
			{
				Transform val2 = val.transform.Find("name");
				TMP_Text val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<TMP_Text>() : null);
				value = SearchEntries.Get(SearchCatalog.Get((Recipe)RecipeProperty.GetValue(pair, null)), Object.op_Implicit((Object)(object)val3) ? val3.text : null, Plugin.Overrides);
				RowEntries[val] = value;
			}
			return value;
		}

		internal static string Key(Recipe recipe)
		{
			if (!Object.op_Implicit((Object)(object)recipe) || !Object.op_Implicit((Object)(object)recipe.m_item))
			{
				return null;
			}
			return ((Object)recipe.m_item).name;
		}

		[HarmonyPriority(800)]
		private static void Prefix(InventoryGui __instance)
		{
			BeforeRebuild(__instance);
			CraftRowReuse.Begin(__instance, ((IList)Available.GetValue(__instance)).Cast<object>().Select((Func<object, GameObject>)((object pair) => (GameObject)Element.GetValue(pair, null))));
		}

		internal static void BeforeRebuild(InventoryGui __instance)
		{
			if ((Object)(object)owner != (Object)(object)__instance || cachedRows == null)
			{
				return;
			}
			IList list = (IList)Available.GetValue(__instance);
			if (OwnsCurrentRows(list))
			{
				list.Clear();
				foreach (object cachedRow in cachedRows)
				{
					if (IsAlive(cachedRow))
					{
						list.Add(cachedRow);
					}
				}
			}
			else
			{
				DiscardDetachedRows(list);
			}
			cachedRows = null;
			appliedRows = null;
			RowEntries.Clear();
		}

		[HarmonyPriority(0)]
		private static void Postfix(InventoryGui __instance)
		{
			CraftRowReuse.Finish();
			Capture(__instance, keepIndices: false);
		}

		internal static void Capture(InventoryGui __instance, bool keepIndices)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			owner = __instance;
			preserveIndices = keepIndices;
			RowEntries.Clear();
			cachedRows = ((IList)Available.GetValue(__instance)).Cast<object>().Where(IsAlive).ToList();
			appliedRows = ((IList)Available.GetValue(__instance)).Cast<object>().ToList();
			foreach (object cachedRow in cachedRows)
			{
				GameObject val = (GameObject)Element.GetValue(cachedRow, null);
				string text = Key((Recipe)RecipeProperty.GetValue(cachedRow, null));
				if (!string.IsNullOrEmpty(text))
				{
					(val.GetComponent<FavoriteRow>() ?? val.AddComponent<FavoriteRow>()).Initialize(__instance, text);
				}
			}
			if ((Object.op_Implicit((Object)(object)Plugin.Panel) && !Plugin.Panel.Query.IsEmpty) || !Plugin.Favorites.IsEmpty)
			{
				Apply(__instance, updateSelection: false);
			}
		}

		private static bool IsAlive(object pair)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return Object.op_Implicit((Object)(GameObject)Element.GetValue(pair, null));
		}

		private static bool OwnsCurrentRows(IList rows)
		{
			return RowListPolicy.MatchesSnapshot(rows, appliedRows);
		}

		private static void DiscardDetachedRows(IList rows)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			HashSet<GameObject> hashSet = new HashSet<GameObject>(rows.Cast<object>().Select((Func<object, GameObject>)((object pair) => (GameObject)Element.GetValue(pair, null))));
			foreach (object cachedRow in cachedRows)
			{
				GameObject val = (GameObject)Element.GetValue(cachedRow, null);
				if (Object.op_Implicit((Object)(object)val) && !hashSet.Contains(val))
				{
					val.SetActive(false);
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static SpellingEntry BaseEntry(object pair)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			GameObject val = (GameObject)Element.GetValue(pair, null);
			SpellingEntry spellingEntry = SearchCatalog.Get((Recipe)RecipeProperty.GetValue(pair, null));
			Transform val2 = (Object.op_Implicit((Object)(object)val) ? val.transform.Find("name") : null);
			TMP_Text val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<TMP_Text>() : null);
			if (!Object.op_Implicit((Object)(object)val3) || spellingEntry == null)
			{
				return spellingEntry;
			}
			return spellingEntry.WithDisplayName(val3.text);
		}

		internal static void Edit(GameObject row)
		{
			if (cachedRows != null)
			{
				object obj = cachedRows.Find((object value) => (Object)(GameObject)Element.GetValue(value, null) == (Object)(object)row);
				if (obj != null)
				{
					CategoryEditor.Open(owner, BaseEntry(obj));
				}
			}
		}

		internal static void RefreshOverrides(string prefab)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			if (cachedRows == null)
			{
				return;
			}
			foreach (object cachedRow in cachedRows)
			{
				if (!(Key((Recipe)RecipeProperty.GetValue(cachedRow, null)) != prefab))
				{
					GameObject val = (GameObject)Element.GetValue(cachedRow, null);
					if (Object.op_Implicit((Object)(object)val))
					{
						RowEntries[val] = Plugin.Overrides.Apply(BaseEntry(cachedRow));
					}
				}
			}
			if (Object.op_Implicit((Object)(object)Plugin.Panel))
			{
				Plugin.Panel.RequestRefresh();
			}
		}

		internal static void Apply(InventoryGui __instance, bool updateSelection = true)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)owner != (Object)(object)__instance || cachedRows == null)
			{
				return;
			}
			IList list = (IList)Available.GetValue(__instance);
			if (!OwnsCurrentRows(list) || cachedRows.Any((object pair) => !IsAlive(pair)))
			{
				DiscardDetachedRows(list);
				Release(__instance);
				return;
			}
			SearchQuery searchQuery = (Object.op_Implicit((Object)(object)Plugin.Panel) ? Plugin.Panel.Query : new SearchQuery(""));
			if (!searchQuery.IsEmpty)
			{
				SearchCatalog.Ensure();
			}
			bool approximate;
			List<object> list2 = searchQuery.SelectMatches(cachedRows, RowEntry, out approximate);
			HashSet<object> hashSet = new HashSet<object>(list2);
			foreach (object cachedRow in cachedRows)
			{
				GameObject val = (GameObject)Element.GetValue(cachedRow, null);
				bool flag = hashSet.Contains(cachedRow);
				if (val.activeSelf != flag)
				{
					val.SetActive(flag);
				}
				FavoriteRow component = val.GetComponent<FavoriteRow>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.RefreshMarker();
				}
			}
			float num = (float)BaseSize.GetValue(__instance);
			__instance.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(num, (float)list2.Count * __instance.m_recipeListSpace));
			List<object> list3 = FavoriteSet.First(searchQuery.RankMatches(list2, RowEntry), (object row) => Plugin.Favorites.Contains(Key((Recipe)RecipeProperty.GetValue(row, null))));
			Vector2 val3 = default(Vector2);
			for (int num2 = 0; num2 < list3.Count; num2++)
			{
				RectTransform val2 = (RectTransform)((GameObject)Element.GetValue(list3[num2], null)).transform;
				((Vector2)(ref val3))..ctor(0f, (float)(-num2) * __instance.m_recipeListSpace);
				if (val2.anchoredPosition != val3)
				{
					val2.anchoredPosition = val3;
				}
			}
			appliedRows = RowListPolicy.ApplyVisibleOrder(list, list3, preserveIndices);
			if (updateSelection && !preserveIndices)
			{
				int num3 = ((list.Count == 0) ? (-1) : ((int)SelectedIndex.Invoke(__instance, new object[1] { true })));
				object value = Selected.GetValue(__instance);
				if ((num3 >= 0) ? (!value.Equals(list[num3])) : (RecipeProperty.GetValue(value, null) != null))
				{
					SetRecipe.Invoke(__instance, new object[2] { num3, false });
				}
			}
			SyncSelection(__instance);
		}

		internal static void SyncSelection(InventoryGui gui)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			if ((Object)(object)owner != (Object)(object)gui || cachedRows == null)
			{
				return;
			}
			GameObject val = (GameObject)Element.GetValue(Selected.GetValue(gui), null);
			if (preserveIndices && Object.op_Implicit((Object)(object)val) && !val.activeSelf)
			{
				SetRecipe.Invoke(gui, new object[2] { -1, false });
				return;
			}
			foreach (object cachedRow in cachedRows)
			{
				GameObject val2 = (GameObject)Element.GetValue(cachedRow, null);
				if (!Object.op_Implicit((Object)(object)val2))
				{
					continue;
				}
				Transform val3 = val2.transform.Find("selected");
				if (Object.op_Implicit((Object)(object)val3))
				{
					bool flag = val2.activeSelf && (Object)(object)val2 == (Object)(object)val;
					if (((Component)val3).gameObject.activeSelf != flag)
					{
						((Component)val3).gameObject.SetActive(flag);
					}
				}
			}
		}

		internal static void Release(InventoryGui gui)
		{
			if (!((Object)(object)owner != (Object)(object)gui))
			{
				owner = null;
				cachedRows = null;
				appliedRows = null;
				preserveIndices = false;
				RowEntries.Clear();
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetRecipe")]
	internal static class RecipeSelectionVisuals
	{
		[HarmonyPriority(0)]
		private static void Postfix(InventoryGui __instance)
		{
			FavoriteRows.SyncSelection(__instance);
		}
	}
	public sealed class FavoriteRow : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
	{
		private static readonly FieldInfo CraftTimer = AccessTools.Field(typeof(InventoryGui), "m_craftTimer");

		private InventoryGui gui;

		private string key;

		private GameObject marker;

		internal void Initialize(InventoryGui owner, string itemKey)
		{
			gui = owner;
			key = itemKey;
			RefreshMarker();
		}

		private void CreateMarker()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_004a: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)marker))
			{
				return;
			}
			marker = new GameObject("CraftSearchFavorite", new Type[1] { typeof(RectTransform) });
			marker.SetActive(false);
			RectTransform val = (RectTransform)marker.transform;
			((Transform)val).SetParent(((Component)this).transform.Find("icon") ?? ((Component)this).transform, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1f, 1f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.pivot = Vector2.one;
			val.anchoredPosition = Vector2.zero;
			val.sizeDelta = new Vector2(14f, 14f);
			Image val3 = null;
			if (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_buildUi))
			{
				object? value = AccessTools.Field(typeof(BuildUi), "m_pieceButtonPrefab").GetValue(Hud.instance.m_buildUi);
				GameObject val4 = (GameObject)((value is GameObject) ? value : null);
				BuildUiPieceButton val5 = (Object.op_Implicit((Object)(object)val4) ? val4.GetComponent<BuildUiPieceButton>() : null);
				if (Object.op_Implicit((Object)(object)val5))
				{
					object? value2 = AccessTools.Field(typeof(BuildUiPieceButton), "m_favoriteStar").GetValue(val5);
					val3 = (Image)((value2 is Image) ? value2 : null);
				}
			}
			if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.sprite))
			{
				Image obj = marker.AddComponent<Image>();
				obj.sprite = val3.sprite;
				((Graphic)obj).color = ((Graphic)val3).color;
				((Graphic)obj).material = ((Graphic)val3).material;
				obj.preserveAspect = true;
				((Graphic)obj).raycastTarget = false;
			}
			else
			{
				TextMeshProUGUI obj2 = marker.AddComponent<TextMeshProUGUI>();
				((TMP_Text)obj2).font = gui.m_recipeName.font;
				((TMP_Text)obj2).fontSharedMaterial = gui.m_recipeName.fontSharedMaterial;
				((TMP_Text)obj2).text = "★";
				((TMP_Text)obj2).fontSize = 14f;
				((Graphic)obj2).color = new Color(1f, 0.8f, 0.3f);
				((TMP_Text)obj2).alignment = (TextAlignmentOptions)514;
				((Graphic)obj2).raycastTarget = false;
			}
		}

		internal void RefreshMarker()
		{
			bool flag = Plugin.Favorites.Contains(key);
			if (flag && !Object.op_Implicit((Object)(object)marker))
			{
				CreateMarker();
			}
			if (Object.op_Implicit((Object)(object)marker) && marker.activeSelf != flag)
			{
				marker.SetActive(flag);
			}
		}

		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)eventData.button != 2 || !Object.op_Implicit((Object)(object)gui) || (float)CraftTimer.GetValue(gui) >= 0f || CategoryEditor.IsOpen)
			{
				return;
			}
			if (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305))
			{
				FavoriteRows.Edit(((Component)this).gameObject);
				((AbstractEventData)eventData).Use();
				return;
			}
			Plugin.ToggleFavorite(key);
			RefreshMarker();
			if (Object.op_Implicit((Object)(object)Plugin.Panel))
			{
				Plugin.Panel.RequestRefresh();
			}
		}
	}
	internal sealed class FavoriteSet
	{
		private readonly HashSet<string> items = new HashSet<string>(StringComparer.Ordinal);

		internal bool IsEmpty => items.Count == 0;

		internal FavoriteSet(string saved)
		{
			string[] array = (saved ?? "").Split(new char[1] { ';' });
			foreach (string text in array)
			{
				if (text.Length > 0)
				{
					items.Add(Uri.UnescapeDataString(text));
				}
			}
		}

		internal bool Contains(string key)
		{
			if (key != null)
			{
				return items.Contains(key);
			}
			return false;
		}

		internal void Toggle(string key)
		{
			if (!string.IsNullOrEmpty(key) && !items.Remove(key))
			{
				items.Add(key);
			}
		}

		internal string Save()
		{
			return string.Join(";", items.OrderBy<string, string>((string x) => x, StringComparer.Ordinal).Select(Uri.EscapeDataString));
		}

		internal static List<T> First<T>(IEnumerable<T> source, Func<T, bool> favorite)
		{
			List<T> list = new List<T>();
			List<T> list2 = new List<T>();
			foreach (T item in source)
			{
				(favorite(item) ? list : list2).Add(item);
			}
			list.AddRange(list2);
			return list;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Update")]
	internal static class InventoryInputGuard
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo consoleVisible = AccessTools.Method(typeof(Console), "IsVisible", (Type[])null, (Type[])null);
			MethodInfo inputActive = AccessTools.Method(typeof(InventoryInputGuard), "IsConsoleOrSearchInputActive", (Type[])null, (Type[])null);
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, consoleVisible))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = inputActive;
				}
				yield return instruction;
			}
		}

		private static bool IsConsoleOrSearchInputActive()
		{
			if (!Console.IsVisible())
			{
				return SearchPanel.BlockInput;
			}
			return true;
		}
	}
	internal enum ItemCategory
	{
		Legs,
		Helmet,
		Chest,
		Shoulder,
		Hands,
		Shield,
		Utility,
		Trinket,
		Ammo,
		Material,
		Consumable,
		Trophy,
		Fish,
		Tool,
		Torch,
		Swords,
		Knives,
		Clubs,
		Polearms,
		Spears,
		Axes,
		Bows,
		Crossbows,
		Pickaxes,
		ElementalMagic,
		BloodMagic,
		Fishing,
		Armour,
		Accessory,
		Arrow,
		Bolt,
		Magic,
		Weapon,
		Food,
		Blunt,
		ResistBlunt,
		Slash,
		ResistSlash,
		Pierce,
		ResistPierce,
		ResistChop,
		ResistPickaxe,
		Fire,
		ResistFire,
		Frost,
		ResistFrost,
		Lightning,
		ResistLightning,
		Poison,
		ResistPoison,
		Spirit,
		ResistSpirit,
		ResistDamage,
		ResistNonPlayer,
		ResistPhysical,
		ResistElemental
	}
	internal static class CategoryHierarchy
	{
		internal static ItemCategory[] Expand(IEnumerable<ItemCategory> categories)
		{
			HashSet<ItemCategory> hashSet = new HashSet<ItemCategory>(categories);
			using (IEnumerator<ItemCategory> enumerator = categories.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					switch (enumerator.Current)
					{
					case ItemCategory.Legs:
						hashSet.Add(ItemCategory.Armour);
						break;
					case ItemCategory.Helmet:
						hashSet.Add(ItemCategory.Armour);
						break;
					case ItemCategory.Chest:
						hashSet.Add(ItemCategory.Armour);
						break;
					case ItemCategory.Utility:
						hashSet.Add(ItemCategory.Accessory);
						break;
					case ItemCategory.Trinket:
						hashSet.Add(ItemCategory.Accessory);
						break;
					case ItemCategory.Arrow:
						hashSet.Add(ItemCategory.Ammo);
						break;
					case ItemCategory.Bolt:
						hashSet.Add(ItemCategory.Ammo);
						break;
					case ItemCategory.ElementalMagic:
						hashSet.Add(ItemCategory.Magic);
						break;
					case ItemCategory.BloodMagic:
						hashSet.Add(ItemCategory.Magic);
						break;
					}
				}
			}
			return hashSet.OrderBy((ItemCategory category) => category).ToArray();
		}
	}
	internal static class ItemTagRules
	{
		internal static ItemCategory[] Build(ItemType type, SkillType skill, bool food, IEnumerable<ItemCategory> properties = null, string ammoType = null)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected I4, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Invalid comparison between Unknown and I4
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Invalid comparison between Unknown and I4
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Invalid comparison between Unknown and I4
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Invalid comparison between Unknown and I4
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Invalid comparison between Unknown and I4
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Invalid comparison between Unknown and I4
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected I4, but got Unknown
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Invalid comparison between Unknown and I4
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Invalid comparison between Unknown and I4
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Invalid comparison between Unknown and I4
			List<ItemCategory> list = ((properties == null) ? new List<ItemCategory>() : new List<ItemCategory>(properties));
			switch (type - 1)
			{
			case 10:
				list.Add(ItemCategory.Legs);
				break;
			case 5:
				list.Add(ItemCategory.Helmet);
				break;
			case 6:
				list.Add(ItemCategory.Chest);
				break;
			case 16:
				list.Add(ItemCategory.Shoulder);
				break;
			case 11:
				list.Add(ItemCategory.Hands);
				break;
			case 4:
				list.Add(ItemCategory.Shield);
				break;
			case 17:
				list.Add(ItemCategory.Utility);
				break;
			case 23:
				list.Add(ItemCategory.Trinket);
				break;
			case 8:
				list.Add(ItemCategory.Ammo);
				break;
			case 22:
				list.Add(ItemCategory.Ammo);
				break;
			case 0:
				list.Add(ItemCategory.Material);
				break;
			case 1:
				list.Add(ItemCategory.Consumable);
				break;
			case 12:
				list.Add(ItemCategory.Trophy);
				break;
			case 20:
				list.Add(ItemCategory.Fish);
				break;
			case 18:
				list.Add(ItemCategory.Tool);
				break;
			case 14:
				list.Add(ItemCategory.Torch);
				break;
			}
			if ((int)type == 9 || (int)type == 23)
			{
				if (ammoType == "$ammo_arrows")
				{
					list.Add(ItemCategory.Arrow);
				}
				else if (ammoType == "$ammo_bolts")
				{
					list.Add(ItemCategory.Bolt);
				}
			}
			int num;
			if ((int)type != 3 && (int)type != 14 && (int)type != 22 && (int)type != 4)
			{
				num = (((int)type == 20) ? 1 : 0);
				if (num == 0)
				{
					goto IL_0175;
				}
			}
			else
			{
				num = 1;
			}
			list.Add(ItemCategory.Weapon);
			goto IL_0175;
			IL_0175:
			if (num != 0 || (int)type == 19)
			{
				switch (skill - 1)
				{
				default:
					if ((int)skill == 104)
					{
						list.Add(ItemCategory.Fishing);
					}
					break;
				case 0:
					list.Add(ItemCategory.Swords);
					break;
				case 1:
					list.Add(ItemCategory.Knives);
					break;
				case 2:
					list.Add(ItemCategory.Clubs);
					break;
				case 3:
					list.Add(ItemCategory.Polearms);
					break;
				case 4:
					list.Add(ItemCategory.Spears);
					break;
				case 6:
					list.Add(ItemCategory.Axes);
					break;
				case 7:
					list.Add(ItemCategory.Bows);
					break;
				case 13:
					list.Add(ItemCategory.Crossbows);
					break;
				case 11:
					list.Add(ItemCategory.Pickaxes);
					break;
				case 8:
					list.Add(ItemCategory.ElementalMagic);
					break;
				case 9:
					list.Add(ItemCategory.BloodMagic);
					break;
				case 5:
				case 10:
				case 12:
					break;
				}
			}
			if (food)
			{
				list.Add(ItemCategory.Food);
			}
			return CategoryHierarchy.Expand(list);
		}
	}
	internal static class ItemTags
	{
		internal static ItemCategory[] Get(SharedData data)
		{
			//IL_0007: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Invalid comparison between Unknown and I4
			//IL_00ea: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Invalid comparison between Unknown and I4
			//IL_00d5: 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_00dc: Invalid comparison between Unknown and I4
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: 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_014a: Invalid comparison between Unknown and I4
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Invalid comparison between Unknown and I4
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Invalid comparison between Unknown and I4
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Invalid comparison between Unknown and I4
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Invalid comparison between Unknown and I4
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Invalid comparison between Unknown and I4
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected I4, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Invalid comparison between Unknown and I4
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Invalid comparison between Unknown and I4
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Invalid comparison between Unknown and I4
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Invalid comparison between Unknown and I4
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Invalid comparison between Unknown and I4
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Invalid comparison between Unknown and I4
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Invalid comparison between Unknown and I4
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Invalid comparison between Unknown and I4
			List<ItemCategory> list = new List<ItemCategory>();
			DamageTypes damages = data.m_damages;
			if (damages.m_fire > 0f)
			{
				list.Add(ItemCategory.Fire);
			}
			if (damages.m_frost > 0f)
			{
				list.Add(ItemCategory.Frost);
			}
			if (damages.m_poison > 0f)
			{
				list.Add(ItemCategory.Poison);
			}
			if (damages.m_lightning > 0f)
			{
				list.Add(ItemCategory.Lightning);
			}
			if (damages.m_spirit > 0f)
			{
				list.Add(ItemCategory.Spirit);
			}
			if (damages.m_blunt > 0f)
			{
				list.Add(ItemCategory.Blunt);
			}
			if (damages.m_slash > 0f)
			{
				list.Add(ItemCategory.Slash);
			}
			if (damages.m_pierce > 0f)
			{
				list.Add(ItemCategory.Pierce);
			}
			foreach (DamageModPair damageModifier in data.m_damageModifiers)
			{
				if ((int)damageModifier.m_modifier != 1 && (int)damageModifier.m_modifier != 5 && (int)damageModifier.m_modifier != 3)
				{
					continue;
				}
				DamageType type = damageModifier.m_type;
				if ((int)type <= 64)
				{
					if ((int)type <= 16)
					{
						switch (type - 1)
						{
						case 0:
							list.Add(ItemCategory.ResistBlunt);
							continue;
						case 1:
							list.Add(ItemCategory.ResistSlash);
							continue;
						case 3:
							list.Add(ItemCategory.ResistPierce);
							continue;
						case 2:
							continue;
						}
						if ((int)type != 8)
						{
							if ((int)type == 16)
							{
								list.Add(ItemCategory.ResistPickaxe);
							}
						}
						else
						{
							list.Add(ItemCategory.ResistChop);
						}
					}
					else if ((int)type != 31)
					{
						if ((int)type != 32)
						{
							if ((int)type == 64)
							{
								list.Add(ItemCategory.ResistFrost);
							}
						}
						else
						{
							list.Add(ItemCategory.ResistFire);
						}
					}
					else
					{
						list.Add(ItemCategory.ResistPhysical);
					}
				}
				else if ((int)type <= 256)
				{
					if ((int)type != 128)
					{
						if ((int)type != 224)
						{
							if ((int)type == 256)
							{
								list.Add(ItemCategory.ResistPoison);
							}
						}
						else
						{
							list.Add(ItemCategory.ResistElemental);
						}
					}
					else
					{
						list.Add(ItemCategory.ResistLightning);
					}
				}
				else if ((int)type != 512)
				{
					if ((int)type != 1024)
					{
						if ((int)type == 2048)
						{
							list.Add(ItemCategory.ResistNonPlayer);
						}
					}
					else
					{
						list.Add(ItemCategory.ResistDamage);
					}
				}
				else
				{
					list.Add(ItemCategory.ResistSpirit);
				}
			}
			return ItemTagRules.Build(data.m_itemType, data.m_skillType, data.m_food > 0f || data.m_foodStamina > 0f || data.m_foodEitr > 0f, list, data.m_ammoType);
		}
	}
	[BepInPlugin("local.valheim.craftsearch", "Workstation Search", "0.6.13")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		private static class CreatePanel
		{
			private static void Postfix(InventoryGui __instance)
			{
				Panel = ((Component)__instance).gameObject.AddComponent<SearchPanel>();
				Panel.Initialize(__instance);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static class RefreshCatalogOnOpen
		{
			private static void Prefix()
			{
				SearchCatalog.Rebuild();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static class ClearSearch
		{
			private static void Postfix()
			{
				CategoryEditor.Close();
				if (Object.op_Implicit((Object)(object)Panel))
				{
					Panel.ResetSearch();
				}
			}
		}

		[HarmonyPatch(typeof(TextInput), "IsVisible")]
		private static class TextFocus
		{
			private static void Postfix(ref bool __result)
			{
				__result |= SearchPanel.BlockInput;
			}
		}

		[HarmonyPatch]
		private static class GameInput
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(ZInput)))
				{
					if (declaredMethod.ReturnType == typeof(bool) && (declaredMethod.Name == "GetButtonDown" || declaredMethod.Name == "GetButton" || declaredMethod.Name == "GetKeyDown"))
					{
						yield return declaredMethod;
					}
				}
			}

			private static bool Prefix(ref bool __result)
			{
				if (!SearchPanel.BlockInput)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		internal const string Id = "local.valheim.craftsearch";

		private Harmony harmony;

		internal static SearchPanel Panel;

		private static ConfigEntry<string> savedFavorites;

		internal static FavoriteSet Favorites;

		internal static CategoryOverrides Overrides = new CategoryOverrides();

		private static ConfigEntry<string> savedOverrides;

		private static bool overridesReadable = true;

		private static Plugin instance;

		private Player indexedPlayer;

		internal static bool SaveOverride(string prefab, CategoryOverride value)
		{
			if (!overridesReadable)
			{
				return false;
			}
			CategoryOverrides categoryOverrides = CategoryOverrides.Load(Overrides.Save());
			categoryOverrides.Set(prefab, value);
			string value2 = savedOverrides.Value;
			bool saveOnConfigSet = ((BaseUnityPlugin)instance).Config.SaveOnConfigSet;
			try
			{
				((BaseUnityPlugin)instance).Config.SaveOnConfigSet = false;
				savedOverrides.Value = categoryOverrides.Save();
				((BaseUnityPlugin)instance).Config.Save();
				Overrides = categoryOverrides;
				return true;
			}
			catch (Exception ex)
			{
				savedOverrides.Value = value2;
				((BaseUnityPlugin)instance).Logger.LogError((object)("Could not save search categories: " + ex.Message));
				return false;
			}
			finally
			{
				((BaseUnityPlugin)instance).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		internal static void ToggleFavorite(string key)
		{
			Favorites.Toggle(key);
			savedFavorites.Value = Favorites.Save();
		}

		private void Awake()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			instance = this;
			savedOverrides = ((BaseUnityPlugin)this).Config.Bind<string>("Search categories", "Overrides", "", "Per-prefab category overrides and custom search terms. Kept when items or mods are absent. Edit in game with Ctrl + middle-click.");
			try
			{
				Overrides = CategoryOverrides.Load(savedOverrides.Value);
			}
			catch (Exception ex)
			{
				overridesReadable = false;
				((BaseUnityPlugin)this).Logger.LogError((object)("Search category overrides could not be read; saved data will be preserved. " + ex.Message));
			}
			savedFavorites = ((BaseUnityPlugin)this).Config.Bind<string>("Favorites", "Items", "", "Favourite item prefab names. Shared by Craft and Upgrade in this profile.");
			Favorites = new FavoriteSet(savedFavorites.Value);
			harmony = new Harmony("local.valheim.craftsearch");
			harmony.PatchAll();
			if (!CraftRowReuse.ReleaseHookReady || !CraftRowReuse.CreationHookReady)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Craft row reuse is unavailable for this recipe implementation; using normal rebuilding.");
			}
			ReclaimCompatibility.Install(harmony, ((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Workstation Search 0.6.13 loaded");
		}

		private void OnDestroy()
		{
			CategoryEditor.Close();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if (Object.op_Implicit((Object)(object)Panel))
			{
				Object.Destroy((Object)(object)Panel);
			}
		}

		private void Update()
		{
			if ((Object)(object)Player.m_localPlayer != (Object)(object)indexedPlayer)
			{
				indexedPlayer = Player.m_localPlayer;
				if (Object.op_Implicit((Object)(object)indexedPlayer))
				{
					SearchCatalog.Rebuild();
				}
			}
		}
	}
	public sealed class SearchPanel : MonoBehaviour
	{
		private static readonly FieldInfo CraftTimer = AccessTools.Field(typeof(InventoryGui), "m_craftTimer");

		internal InventoryGui Gui;

		internal ScrollRect RecipeScroll;

		internal SearchQuery Query = new SearchQuery("");

		private TMP_InputField input;

		private GameObject bar;

		private RectTransform scroll;

		private Vector2 originalOffset;

		private bool pending;

		private bool styled;

		private static int blockedFrame = -1;

		internal static bool BlockInput
		{
			get
			{
				if (!CategoryEditor.IsOpen && Time.frameCount != blockedFrame)
				{
					if (Object.op_Implicit((Object)(object)Plugin.Panel) && Object.op_Implicit((Object)(object)Plugin.Panel.input) && Plugin.Panel.input.isFocused)
					{
						return ((Component)Plugin.Panel.input).gameObject.activeInHierarchy;
					}
					return false;
				}
				return true;
			}
		}

		internal void RequestRefresh()
		{
			pending = true;
		}

		internal static void SuppressInputFrame()
		{
			blockedFrame = Time.frameCount;
		}

		internal void Initialize(InventoryGui gui)
		{
			//IL_005d: 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_0073: 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_00a8: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Expected O, but got Unknown
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Expected O, but got Unknown
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_048b: Expected O, but got Unknown
			Gui = gui;
			ScrollRect val = (RecipeScroll = ((Component)gui.m_recipeListRoot).GetComponentInParent<ScrollRect>());
			((Component)gui.m_recipeListRoot).gameObject.AddComponent<RecipeWheelScroll>();
			((Component)gui.m_recipeListScroll).gameObject.AddComponent<RecipeWheelScroll>();
			scroll = (RectTransform)((!Object.op_Implicit((Object)(object)val)) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)(RectTransform)((Component)val).transform));
			originalOffset = scroll.offsetMax;
			bar = new GameObject("CraftSearch", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform val2 = (RectTransform)bar.transform;
			((Transform)val2).SetParent(((Transform)scroll).parent, false);
			val2.anchorMin = new Vector2(scroll.anchorMin.x, scroll.anchorMax.y);
			val2.anchorMax = scroll.anchorMax;
			val2.offsetMin = new Vector2(scroll.offsetMin.x, originalOffset.y - 6f - 34f);
			val2.offsetMax = originalOffset - new Vector2(0f, 6f);
			scroll.offsetMax = originalOffset - new Vector2(0f, 46f);
			((Graphic)bar.GetComponent<Image>()).color = new Color(0.08f, 0.07f, 0.06f, 0.95f);
			RectTransform val3 = (RectTransform)new GameObject("Text Area", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			}).transform;
			((Transform)val3).SetParent((Transform)(object)val2, false);
			Stretch(val3, 9f, 38f);
			TextMeshProUGUI val4 = Label("Text", (Transform)(object)val3, gui.m_recipeName, "");
			((TMP_Text)val4).richText = false;
			TextMeshProUGUI val5 = Label("Placeholder", (Transform)(object)val3, gui.m_recipeName, "Search recipes...");
			((Graphic)val5).color = new Color(0.7f, 0.67f, 0.6f);
			input = bar.AddComponent<TMP_InputField>();
			input.textViewport = val3;
			input.textComponent = (TMP_Text)(object)val4;
			input.placeholder = (Graphic)(object)val5;
			((Selectable)input).targetGraphic = (Graphic)(object)bar.GetComponent<Image>();
			input.lineType = (LineType)0;
			input.characterLimit = 128;
			((UnityEvent<string>)(object)input.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				pending = true;
			});
			((UnityEvent<string>)(object)input.onEndEdit).AddListener((UnityAction<string>)delegate
			{
				blockedFrame = Time.frameCount;
			});
			GameObject val6 = new GameObject("Clear", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			RectTransform val7 = (RectTransform)val6.transform;
			((Transform)val7).SetParent((Transform)(object)val2, false);
			val7.anchorMin = new Vector2(1f, 0f);
			val7.anchorMax = Vector2.one;
			val7.offsetMin = new Vector2(-34f, 0f);
			val7.offsetMax = Vector2.zero;
			Button component = val6.GetComponent<Button>();
			Button craftCancelButton = gui.m_craftCancelButton;
			Graphic targetGraphic = ((Selectable)craftCancelButton).targetGraphic;
			CopyImage((Image)(object)((targetGraphic is Image) ? targetGraphic : null), val6.GetComponent<Image>());
			CopySelectable((Selectable)(object)craftCancelButton, (Selectable)(object)component);
			((Selectable)component).targetGraphic = (Graphic)(object)val6.GetComponent<Image>();
			TMP_Text componentInChildren = ((Component)gui.m_tabCraft).GetComponentInChildren<TMP_Text>(true);
			TextMeshProUGUI val8 = Label("Label", (Transform)(object)val7, Object.op_Implicit((Object)(object)componentInChildren) ? componentInChildren : gui.m_recipeName, "X");
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				CopyTextStyle(componentInChildren, (TMP_Text)(object)val8);
			}
			((TMP_Text)val8).fontSize = Mathf.Max(26f, ((TMP_Text)val8).fontSize) * 0.5f;
			((TMP_Text)val8).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val8).rectTransform.offsetMin = Vector2.zero;
			((TMP_Text)val8).rectTransform.offsetMax = Vector2.zero;
			val6.AddComponent<ClearButtonText>().Initialize((TMP_Text)(object)val8, gui.m_tabCraft, gui.m_tabUpgrade);
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				input.text = "";
			});
			TryApplyBuildFilterStyle();
		}

		private void TryApplyBuildFilterStyle()
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			if (!styled && Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_buildUi))
			{
				object? value = AccessTools.Field(typeof(BuildUi), "m_searchField").GetValue(Hud.instance.m_buildUi);
				TMP_InputField val = (TMP_InputField)((value is TMP_InputField) ? value : null);
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.textComponent))
				{
					Graphic targetGraphic = ((Selectable)val).targetGraphic;
					CopyImage((Image)(object)((targetGraphic is Image) ? targetGraphic : null), bar.GetComponent<Image>());
					CopySelectable((Selectable)(object)val, (Selectable)(object)input);
					input.caretColor = val.caretColor;
					input.customCaretColor = val.customCaretColor;
					input.caretWidth = val.caretWidth;
					input.selectionColor = val.selectionColor;
					CopyTextStyle(val.textComponent, input.textComponent);
					FixBaseline(input.textComponent);
					TMP_Text val2 = (TMP_Text)input.placeholder;
					Graphic placeholder = val.placeholder;
					CopyTextStyle((TMP_Text)(((object)((placeholder is TMP_Text) ? placeholder : null)) ?? ((object)val.textComponent)), val2);
					FixBaseline(val2);
					styled = true;
				}
			}
		}

		internal static void CopyImage(Image source, Image target)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)source))
			{
				target.sprite = source.sprite;
				target.type = source.type;
				((Graphic)target).color = ((Graphic)source).color;
				((Graphic)target).material = ((Graphic)source).material;
				target.preserveAspect = source.preserveAspect;
				target.fillCenter = source.fillCenter;
				target.pixelsPerUnitMultiplier = source.pixelsPerUnitMultiplier;
			}
		}

		internal static void CopySelectable(Selectable source, Selectable target)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0023: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			target.colors = source.colors;
			target.spriteState = source.spriteState;
			target.transition = (Transition)(((int)source.transition == 3) ? 1 : ((int)source.transition));
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			target.navigation = navigation;
		}

		private static void CopyTextStyle(TMP_Text source, TMP_Text target)
		{
			//IL_0026: 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)
			target.font = source.font;
			target.fontSharedMaterial = source.fontSharedMaterial;
			target.fontSize = source.fontSize;
			target.fontStyle = source.fontStyle;
			((Graphic)target).color = ((Graphic)source).color;
			target.characterSpacing = source.characterSpacing;
		}

		private static void FixBaseline(TMP_Text text, bool centered = false)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			text.enableAutoSizing = false;
			text.textWrappingMode = (TextWrappingModes)0;
			text.alignment = (TextAlignmentOptions)(centered ? 2050 : 2049);
			FaceInfo faceInfo = ((TMP_Asset)text.font).faceInfo;
			float num = text.fontSize * ((FaceInfo)(ref faceInfo)).scale / ((FaceInfo)(ref faceInfo)).pointSize;
			float num2 = (0f - (((FaceInfo)(ref faceInfo)).ascentLine + ((FaceInfo)(ref faceInfo)).descentLine)) * num * 0.5f;
			text.rectTransform.offsetMin = new Vector2(0f, num2);
			text.rectTransform.offsetMax = new Vector2(0f, num2);
			text.margin = Vector4.zero;
		}

		internal static void Stretch(RectTransform rect, float left = 0f, float right = 0f)
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = new Vector2(left, 0f);
			rect.offsetMax = new Vector2(0f - right, 0f);
		}

		internal static TextMeshProUGUI Label(string name, Transform parent, TMP_Text source, string value)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			Stretch(((TMP_Text)obj).rectTransform);
			((TMP_Text)obj).font = source.font;
			((TMP_Text)obj).fontSharedMaterial = source.fontSharedMaterial;
			((TMP_Text)obj).fontSize = 18f;
			((Graphic)obj).color = new Color(1f, 0.88f, 0.65f);
			FixBaseline((TMP_Text)(object)obj);
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).text = value;
			val.SetActive(true);
			return obj;
		}

		private void Update()
		{
			TryApplyBuildFilterStyle();
			if (!Object.op_Implicit((Object)(object)input) || !Object.op_Implicit((Object)(object)Gui) || !InventoryGui.IsVisible() || CategoryEditor.IsOpen)
			{
				return;
			}
			bool flag = (float)CraftTimer.GetValue(Gui) >= 0f;
			((Selectable)input).interactable = !flag;
			if (input.isFocused)
			{
				blockedFrame = Time.frameCount;
				if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))
				{
					input.DeactivateInputField(false);
					if (Object.op_Implicit((Object)(object)EventSystem.current))
					{
						EventSystem.current.SetSelectedGameObject((GameObject)null);
					}
				}
			}
			if (!(!pending || flag) && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				pending = false;
				Query = new SearchQuery(input.text);
				FavoriteRows.Apply(Gui);
				Gui.m_recipeListScroll.value = 1f;
			}
		}

		internal void ResetSearch()
		{
			Query = new SearchQuery("");
			pending = false;
			if (Object.op_Implicit((Object)(object)input))
			{
				input.DeactivateInputField(false);
				input.SetTextWithoutNotify("");
			}
		}

		private void OnDestroy()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			CategoryEditor.Close();
			FavoriteRows.Release(Gui);
			if (Object.op_Implicit((Object)(object)Gui))
			{
				RecipeWheelScroll component = ((Component)Gui.m_recipeListRoot).GetComponent<RecipeWheelScroll>();
				if (Object.op_Implicit((Object)(object)component))
				{
					Object.Destroy((Object)(object)component);
				}
				RecipeWheelScroll component2 = ((Component)Gui.m_recipeListScroll).GetComponent<RecipeWheelScroll>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					Object.Destroy((Object)(object)component2);
				}
			}
			if (Object.op_Implicit((Object)(object)scroll))
			{
				scroll.offsetMax = originalOffset;
			}
			if (Object.op_Implicit((Object)(object)bar))
			{
				Object.Destroy((Object)(object)bar);
			}
			if ((Object)(object)Plugin.Panel == (Object)(object)this)
			{
				Plugin.Panel = null;
			}
		}
	}
	public sealed class ClearButtonText : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		private static readonly FieldInfo DefaultColor = AccessTools.Field(typeof(ButtonTextColor), "m_defaultMeshColor");

		private TMP_Text label;

		private Button craftTab;

		private Button upgradeTab;

		private bool hovered;

		internal void Initialize(TMP_Text text, Button craft, Button upgrade)
		{
			label = text;
			craftTab = craft;
			upgradeTab = upgrade;
		}

		private void LateUpdate()
		{
			//IL_0050: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)label) || !Object.op_Implicit((Object)(object)craftTab))
			{
				return;
			}
			ButtonTextColor component = ((Component)craftTab).GetComponent<ButtonTextColor>();
			if (Object.op_Implicit((Object)(object)component))
			{
				((Graphic)label).color = (Color)(hovered ? component.m_disabledColor : ((Color)DefaultColor.GetValue(component)));
				return;
			}
			Button val = ((((Selectable)craftTab).interactable == !hovered) ? craftTab : upgradeTab);
			TMP_Text val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponentInChildren<TMP_Text>(true) : null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				((Graphic)label).color = ((Graphic)val2).color;
			}
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			hovered = true;
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			hovered = false;
		}

		private void OnDisable()
		{
			hovered = false;
		}
	}
	internal sealed class RebuildPool<TKey, TRow> where TRow : class
	{
		private readonly Dictionary<TKey, Queue<TRow>> rows = new Dictionary<TKey, Queue<TRow>>();

		private readonly HashSet<TRow> unused = new HashSet<TRow>();

		internal IEnumerable<TRow> Unused => unused;

		internal bool Contains(TRow row)
		{
			return unused.Contains(row);
		}

		internal void Add(TKey key, TRow row)
		{
			if (unused.Add(row))
			{
				if (!rows.TryGetValue(key, out var value))
				{
					value = (rows[key] = new Queue<TRow>());
				}
				value.Enqueue(row);
			}
		}

		internal TRow Take(TKey key)
		{
			if (!rows.TryGetValue(key, out var value) || value.Count == 0)
			{
				return null;
			}
			TRow val = value.Dequeue();
			unused.Remove(val);
			return val;
		}

		internal void Clear()
		{
			rows.Clear();
			unused.Clear();
		}
	}
	public sealed class RecipeWheelScroll : MonoBehaviour, IScrollHandler, IEventSystemHandler
	{
		public void OnScroll(PointerEventData eventData)
		{
			Move(eventData);
		}

		internal static bool Move(PointerEventData eventData)
		{
			//IL_003a: 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)
			SearchPanel panel = Plugin.Panel;
			if (!Object.op_Implicit((Object)(object)panel) || !Object.op_Implicit((Object)(object)panel.Gui) || !Object.op_Implicit((Object)(object)panel.Gui.m_recipeListScroll))
			{
				return false;
			}
			if (((AbstractEventData)eventData).used)
			{
				return true;
			}
			float num = eventData.scrollDelta.y;
			if (num == 0f)
			{
				num = 0f - eventData.scrollDelta.x;
			}
			if (num == 0f)
			{
				return true;
			}
			Scrollbar recipeListScroll = panel.Gui.m_recipeListScroll;
			float num2 = WheelStep.FromVisibleFraction(recipeListScroll.size);
			if (Object.op_Implicit((Object)(object)panel.RecipeScroll))
			{
				panel.RecipeScroll.StopMovement();
			}
			recipeListScroll.value = Mathf.Clamp01(recipeListScroll.value + Mathf.Sign(num) * num2);
			((AbstractEventData)eventData).Use();
			return true;
		}
	}
	[HarmonyPatch(typeof(ScrollRect), "OnScroll", new Type[] { typeof(PointerEventData) })]
	internal static class RecipeViewportWheel
	{
		private static bool Prefix(ScrollRect __instance, PointerEventData __0)
		{
			if (!Object.op_Implicit((Object)(object)Plugin.Panel) || !Object.op_Implicit((Object)(object)Plugin.Panel.Gui) || ((Object)(object)__instance != (Object)(object)Plugin.Panel.RecipeScroll && (Object)(object)__instance.content != (Object)(object)Plugin.Panel.Gui.m_recipeListRoot))
			{
				return true;
			}
			return !RecipeWheelScroll.Move(__0);
		}
	}
	internal static class ReclaimCompatibility
	{
		internal static void Install(Harmony harmony, ManualLogSource log)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00a4: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("Azumatt.Recycle_N_Reclaim", out var value))
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("Recycle_N_Reclaim.GamePatches.UI.StationRecyclingTabHolder");
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.DeclaredMethod(type, "UpdateRecyclingList", (Type[])null, (Type[])null));
				if (methodInfo == null)
				{
					log.LogWarning((object)"Reclaim list compatibility unavailable: UpdateRecyclingList was not found.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ReclaimCompatibility), "BeforeRebuild", (Type[])null)
				{
					priority = 800
				}, new HarmonyMethod(typeof(ReclaimCompatibility), "AfterRebuild", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"Recycle_N_Reclaim search compatibility enabled");
			}
		}

		private static void BeforeRebuild()
		{
			if (Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				FavoriteRows.BeforeRebuild(InventoryGui.instance);
			}
		}

		private static void AfterRebuild()
		{
			if (Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				FavoriteRows.Capture(InventoryGui.instance, keepIndices: true);
			}
		}
	}
	internal sealed class RowEntryCache
	{
		private readonly Dictionary<SpellingEntry, Dictionary<string, SpellingEntry>> entries = new Dictionary<SpellingEntry, Dictionary<string, SpellingEntry>>();

		private readonly SpellingEntry unknown = new SpellingEntry("", "");

		private CategoryOverrides overrides;

		private int count;

		internal SpellingEntry Get(SpellingEntry source, string title, CategoryOverrides currentOverrides)
		{
			if (overrides != currentOverrides || count >= 16384)
			{
				entries.Clear();
				count = 0;
				overrides = currentOverrides;
			}
			if (source == null && string.IsNullOrWhiteSpace(title))
			{
				return null;
			}
			source = source ?? unknown;
			title = title ?? "";
			if (!entries.TryGetValue(source, out var value))
			{
				value = (entries[source] = new Dictionary<string, SpellingEntry>());
			}
			if (!value.TryGetValue(title, out var value2))
			{
				value2 = (value[title] = currentOverrides.Apply(source.WithDisplayName(title)));
				count++;
			}
			return value2;
		}
	}
	internal static class RowListPolicy
	{
		internal static bool MatchesSnapshot(IList current, IEnumerable<object> snapshot)
		{
			return snapshot?.SequenceEqual(current.Cast<object>()) ?? false;
		}

		internal static List<object> ApplyVisibleOrder(IList current, IList<object> visible, bool preserveIndices)
		{
			if (!preserveIndices)
			{
				current.Clear();
				foreach (object item in visible)
				{
					current.Add(item);
				}
			}
			return current.Cast<object>().ToList();
		}
	}
	internal static class SearchCatalog
	{
		private static readonly Dictionary<Recipe, SpellingEntry> Entries = new Dictionary<Recipe, SpellingEntry>();

		private static ObjectDB database;

		private static string language;

		private static int count;

		internal static void Rebuild()
		{
			database = ObjectDB.instance;
			language = Localization.instance.GetSelectedLanguage();
			count = (Object.op_Implicit((Object)(object)database) ? database.m_recipes.Count : 0);
			HashSet<Recipe> hashSet = new HashSet<Recipe>();
			if (Object.op_Implicit((Object)(object)database))
			{
				foreach (Recipe recipe in database.m_recipes)
				{
					if (Object.op_Implicit((Object)(object)recipe) && Object.op_Implicit((Object)(object)recipe.m_item))
					{
						hashSet.Add(recipe);
						string text = Localization.instance.Localize(recipe.m_item.m_itemData.m_shared.m_name);
						string name = ((Object)recipe.m_item).name;
						ItemCategory[] array = ItemTags.Get(recipe.m_item.m_itemData.m_shared);
						if (!Entries.TryGetValue(recipe, out var value) || value.Name != text || value.Prefab != name || !value.Categories.SequenceEqual(array))
						{
							Entries[recipe] = new SpellingEntry(text, name, array);
						}
					}
				}
			}
			foreach (Recipe item in new List<Recipe>(Entries.Keys))
			{
				if (!hashSet.Contains(item))
				{
					Entries.Remove(item);
				}
			}
		}

		internal static void Ensure()
		{
			if ((Object)(object)database != (Object)(object)ObjectDB.instance || language != Localization.instance.GetSelectedLanguage() || (Object.op_Implicit((Object)(object)database) && count != database.m_recipes.Count))
			{
				Rebuild();
			}
		}

		internal static SpellingEntry Get(Recipe recipe)
		{
			if (!Object.op_Implicit((Object)(object)recipe) || !Object.op_Implicit((Object)(object)recipe.m_item))
			{
				return null;
			}
			if (!Entries.TryGetValue(recipe, out var value))
			{
				value = new SpellingEntry(Localization.instance.Localize(recipe.m_item.m_itemData.m_shared.m_name), ((Object)recipe.m_item).name, ItemTags.Get(recipe.m_item.m_itemData.m_shared));
				Entries[recipe] = value;
			}
			return value;
		}
	}
	internal sealed class SearchQuery
	{
		private readonly string[] terms;

		private readonly SearchTerm[] compiledTerms;

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

		internal SearchQuery(string text)
		{
			terms = (text ?? "").Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
			compiledTerms = terms.Select((string term) => new SearchTerm(term)).ToArray();
		}

		internal bool FuzzyMatches(SpellingEntry entry)
		{
			return entry?.FuzzyMatches(compiledTerms) ?? false;
		}

		internal List<T> RankMatches<T>(IEnumerable<T> source, Func<T, SpellingEntry> entry)
		{
			if (IsEmpty)
			{
				return source.ToList();
			}
			string phrase = string.Join(" ", terms);
			return (from row in source.Select(delegate(T row)
				{
					string name = entry(row)?.Name;
					return new
					{
						Row = row,
						TitleTerms = terms.Count((string term) => Contains(name, term)),
						ExactTitle = (name != null && CultureInfo.InvariantCulture.CompareInfo.Compare(name, phrase, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) == 0)
					};
				})
				orderby row.TitleTerms descending, row.ExactTitle descending
				select row.Row).ToList();
		}

		internal List<T> SelectMatches<T>(IEnumerable<T> source, Func<T, SpellingEntry> entry, out bool approximate)
		{
			List<T> list = source.ToList();
			approximate = false;
			if (IsEmpty)
			{
				return list;
			}
			List<T> list2 = list.FindAll((T row) => entry(row)?.DirectMatches(compiledTerms) ?? true);
			if (!IsEmpty && list2.Count == 0)
			{
				list2 = list.FindAll((T row) => FuzzyMatches(entry(row)));
				approximate = list2.Count > 0;
			}
			return list2;
		}

		internal bool Matches(string displayName, string prefabName)
		{
			string[] array = terms;
			foreach (string term in array)
			{
				if (!Contains(displayName, term) && !Contains(prefabName, term))
				{
					return false;
				}
			}
			return true;
		}

		internal static bool Contains(string text, string term)
		{
			if (text != null)
			{
				return CultureInfo.InvariantCulture.CompareInfo.IndexOf(text, term, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0;
			}
			return false;
		}
	}
	internal static class SearchVocabulary
	{
		private static readonly Dictionary<string, string> WordForms;

		private static readonly Dictionary<string, ItemCategory> Aliases;

		private static readonly KeyValuePair<string, ItemCategory>[] FuzzyWords;

		static SearchVocabulary()
		{
			WordForms = new Dictionary<string, string>
			{
				{ "legs", "leg" },
				{ "boots", "boot" },
				{ "helmets", "helmet" },
				{ "hats", "hat" },
				{ "shoulders", "shoulder" },
				{ "capes", "cape" },
				{ "cloaks", "cloak" },
				{ "hands", "hand" },
				{ "gloves", "glove" },
				{ "shields", "shield" },
				{ "accessories", "accessory" },
				{ "trinkets", "trinket" },
				{ "materials", "material" },
				{ "resources", "resource" },
				{ "consumables", "consumable" },
				{ "trophies", "trophy" },
				{ "tools", "tool" },
				{ "torches", "torch" },
				{ "swords", "sword" },
				{ "knives", "knife" },
				{ "daggers", "dagger" },
				{ "clubs", "club" },
				{ "maces", "mace" },
				{ "polearms", "polearm" },
				{ "atgeirs", "atgeir" },
				{ "spears", "spear" },
				{ "axes", "axe" },
				{ "bows", "bow" },
				{ "crossbows", "crossbow" },
				{ "pickaxes", "pickaxe" },
				{ "arrows", "arrow" },
				{ "bolts", "bolt" },
				{ "weapons", "weapon" },
				{ "armour", "armor" }
			};
			Aliases = new Dictionary<string, ItemCategory>();
			Add(ItemCategory.Legs, "leg", "boot", "greaves", "leggings", "pants", "trousers");
			Add(ItemCategory.Helmet, "helmet", "hat", "head", "headgear");
			Add(ItemCategory.Chest, "chest", "tunic", "cuirass", "breastplate", "torso");
			Add(ItemCategory.Shoulder, "shoulder", "cape", "cloak");
			Add(ItemCategory.Hands, "hand", "glove", "gauntlets");
			Add(ItemCategory.Shield, "shield");
			Add(ItemCategory.Utility, "utility");
			Add(ItemCategory.Trinket, "trinket");
			Add(ItemCategory.Ammo, "ammo", "ammunition");
			Add(ItemCategory.Material, "material", "resource");
			Add(ItemCategory.Consumable, "consumable");
			Add(ItemCategory.Trophy, "trophy");
			Add(ItemCategory.Fish, "fish");
			Add(ItemCategory.Tool, "tool");
			Add(ItemCategory.Torch, "torch");
			Add(ItemCategory.Swords, "sword");
			Add(ItemCategory.Knives, "knife", "dagger");
			Add(ItemCategory.Clubs, "club", "mace");
			Add(ItemCategory.Polearms, "polearm", "atgeir");
			Add(ItemCategory.Spears, "spear");
			Add(ItemCategory.Axes, "axe");
			Add(ItemCategory.Bows, "bow");
			Add(ItemCategory.Crossbows, "crossbow");
			Add(ItemCategory.Pickaxes, "pickaxe", "mining