Decompiled source of CraftingCategories v1.0.1

plugins/CraftingCategories.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("CraftingCategories")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CraftingCategories")]
[assembly: AssemblyTitle("CraftingCategories")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 CraftingCategories
{
	internal class CategoryPanel : MonoBehaviour
	{
		public static CategoryPanel Instance;

		private const float Padding = 8f;

		private const float Gap = 6f;

		private const float SearchHeight = 34f;

		private static readonly Color SelectedTint = new Color(1f, 0.72f, 0.32f, 1f);

		private static readonly Color SelectedText = new Color(1f, 0.84f, 0.5f, 1f);

		private static readonly Color CountText = new Color(0.75f, 0.75f, 0.75f, 1f);

		private InventoryGui _gui;

		private RectTransform _root;

		private RectTransform _content;

		private ScrollRect _scroll;

		private TMP_InputField _search;

		private Button _craftableButton;

		private Image _craftableImage;

		private TMP_Text _craftableLabel;

		private Button _templateButton;

		private Image _templateImage;

		private TMP_Text _templateText;

		private ButtonSfx _templateSfx;

		private readonly List<GameObject> _buttons = new List<GameObject>();

		private string _signature;

		private bool _layoutDirty = true;

		private int _shownFrame;

		private Vector2Int _screenSize;

		private bool _refreshRequested;

		private bool _loggedLayout;

		public bool SearchFocused
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_search))
				{
					return _search.isFocused;
				}
				return false;
			}
		}

		public void RequestRefresh()
		{
			_refreshRequested = true;
		}

		public static void Ensure(InventoryGui gui)
		{
			//IL_004d: 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)
			if ((!Object.op_Implicit((Object)(object)Instance) || !((Object)(object)Instance._gui == (Object)(object)gui)) && Object.op_Implicit((Object)(object)gui) && Object.op_Implicit((Object)(object)gui.m_crafting))
			{
				GameObject val = new GameObject("CraftingCategoriesPanel", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent((Transform)(object)gui.m_crafting, false);
				Instance = val.AddComponent<CategoryPanel>();
				Instance.Build(gui);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void OnEnable()
		{
			_shownFrame = Time.frameCount;
		}

		private void Update()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			_ = InputGuard.Blocking;
			Vector2Int val = default(Vector2Int);
			((Vector2Int)(ref val))..ctor(Screen.width, Screen.height);
			if (val != _screenSize)
			{
				_screenSize = val;
				_layoutDirty = true;
			}
			if (_layoutDirty && Time.frameCount - _shownFrame > 5 && InventoryGui.IsVisible())
			{
				ApplyLayout();
			}
			if (_refreshRequested)
			{
				_refreshRequested = false;
				CraftFilter.Refresh(scrollToTop: false);
			}
			if (Object.op_Implicit((Object)(object)_search) && ((Component)_search).gameObject.activeInHierarchy && !SearchFocused && ZInput.GetKey((KeyCode)306, true) && ZInput.GetKeyDown((KeyCode)102, true))
			{
				((Selectable)_search).Select();
				_search.ActivateInputField();
			}
		}

		public void OnInventoryHidden()
		{
			if (Object.op_Implicit((Object)(object)_search) && _search.isFocused)
			{
				_search.DeactivateInputField(false);
			}
		}

		public void ClearSearchField()
		{
			if (Object.op_Implicit((Object)(object)_search))
			{
				_search.SetTextWithoutNotify("");
			}
		}

		public void OnConfigChanged()
		{
			((Component)this).gameObject.SetActive(Plugin.Enabled.Value);
			if (Plugin.SearchEnabled != Object.op_Implicit((Object)(object)_search))
			{
				if (Object.op_Implicit((Object)(object)_search))
				{
					Object.Destroy((Object)(object)((Component)_search).gameObject);
					_search = null;
					CraftFilter.SearchText = "";
				}
				else
				{
					CreateSearchField();
				}
			}
			_layoutDirty = true;
			_signature = null;
			ApplyLayout();
			CraftFilter.Refresh(scrollToTop: false);
		}

		private void Build(InventoryGui gui)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Expected O, but got Unknown
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Expected O, but got Unknown
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			_gui = gui;
			_root = (RectTransform)((Component)this).transform;
			_templateButton = gui.m_tabCraft;
			_templateImage = (Object.op_Implicit((Object)(object)_templateButton) ? ((Component)_templateButton).GetComponent<Image>() : null);
			_templateText = (Object.op_Implicit((Object)(object)_templateButton) ? ((Component)_templateButton).GetComponentInChildren<TMP_Text>(true) : null);
			if (!Object.op_Implicit((Object)(object)_templateText))
			{
				_templateText = gui.m_recipeName;
			}
			_templateSfx = (Object.op_Implicit((Object)(object)_templateButton) ? ((Component)_templateButton).GetComponent<ButtonSfx>() : null);
			Image val = ((Component)this).gameObject.AddComponent<Image>();
			Image component = ((Component)gui.m_crafting).GetComponent<Image>();
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sprite))
			{
				val.sprite = component.sprite;
				val.type = component.type;
				((Graphic)val).color = ((Graphic)component).color;
				val.pixelsPerUnitMultiplier = component.pixelsPerUnitMultiplier;
				((Graphic)val).material = ((Graphic)component).material;
			}
			else
			{
				((Graphic)val).color = new Color(0f, 0f, 0f, 0.65f);
			}
			GameObject val2 = new GameObject("Scroll", new Type[4]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(RectMask2D),
				typeof(ScrollRect)
			});
			val2.transform.SetParent((Transform)(object)_root, false);
			((Graphic)val2.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.001f);
			GameObject val3 = new GameObject("Content", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			val3.transform.SetParent(val2.transform, false);
			_content = (RectTransform)val3.transform;
			_content.anchorMin = new Vector2(0f, 1f);
			_content.anchorMax = new Vector2(1f, 1f);
			_content.pivot = new Vector2(0.5f, 1f);
			_content.offsetMin = Vector2.zero;
			_content.offsetMax = Vector2.zero;
			VerticalLayoutGroup component2 = val3.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component2).spacing = 3f;
			((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
			val3.GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			_scroll = val2.GetComponent<ScrollRect>();
			_scroll.content = _content;
			_scroll.viewport = (RectTransform)val2.transform;
			_scroll.horizontal = false;
			_scroll.vertical = true;
			_scroll.movementType = (MovementType)2;
			_scroll.scrollSensitivity = 40f;
			GameObject val4 = CreateButton((Transform)(object)_root, "CraftableOnly", out _craftableButton, out _craftableImage);
			_craftableLabel = CreateText(val4.transform, "Label", Loc.CraftableOnly, (TextAlignmentOptions)514, 1f);
			Stretch(_craftableLabel.rectTransform, 8f, 8f);
			((UnityEvent)_craftableButton.onClick).AddListener((UnityAction)delegate
			{
				CraftFilter.SetCraftableOnly(!CraftFilter.CraftableOnly);
				UpdateCraftableVisual();
			});
			UpdateCraftableVisual();
			if (Plugin.SearchEnabled)
			{
				CreateSearchField();
			}
			if (Object.op_Implicit((Object)(object)((Component)gui.m_crafting).GetComponentInParent<Mask>()) || Object.op_Implicit((Object)(object)((Component)gui.m_crafting).GetComponent<RectMask2D>()))
			{
				Plugin.Log.LogWarning((object)"Crafting panel is masked - the sidebar may be clipped.");
			}
			ApplyLayout();
			((Component)this).gameObject.SetActive(Plugin.Enabled.Value);
		}

		private void CreateSearchField()
		{
			_search = CloneVanillaSearchField() ?? CreatePlainSearchField();
			((Object)((Component)_search).gameObject).name = "Search";
			_search.restoreOriginalTextOnEscape = false;
			_search.lineType = (LineType)0;
			_search.SetTextWithoutNotify(CraftFilter.SearchText);
			Graphic placeholder = _search.placeholder;
			TMP_Text val = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null);
			if (val != null)
			{
				val.text = Loc.Search + "  (Ctrl+F)";
			}
			((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)CraftFilter.SetSearch);
			((Component)_search).gameObject.SetActive(true);
			_layoutDirty = true;
		}

		private TMP_InputField CloneVanillaSearchField()
		{
			try
			{
				BuildUi val = (Object.op_Implicit((Object)(object)Hud.instance) ? Hud.instance.m_buildUi : null);
				GuiInputField val2 = (Object.op_Implicit((Object)(object)val) ? val.m_searchField : null);
				if (!Object.op_Implicit((Object)(object)val2))
				{
					return null;
				}
				GameObject obj = Object.Instantiate<GameObject>(((Component)val2).gameObject, (Transform)(object)_root, false);
				GuiInputField component = obj.GetComponent<GuiInputField>();
				DisablePersistent((UnityEventBase)(object)((TMP_InputField)component).onValueChanged);
				DisablePersistent((UnityEventBase)(object)((TMP_InputField)component).onEndEdit);
				DisablePersistent((UnityEventBase)(object)((TMP_InputField)component).onSubmit);
				DisablePersistent((UnityEventBase)(object)((TMP_InputField)component).onSelect);
				DisablePersistent((UnityEventBase)(object)((TMP_InputField)component).onDeselect);
				DisablePersistent((UnityEventBase)(object)component.OnInputSubmit);
				UIGamePad[] componentsInChildren = obj.GetComponentsInChildren<UIGamePad>(true);
				foreach (UIGamePad val3 in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val3.m_hint))
					{
						Object.Destroy((Object)(object)val3.m_hint);
					}
					Object.Destroy((Object)(object)val3);
				}
				((TMP_InputField)component).text = "";
				return (TMP_InputField)(object)component;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not clone the build menu search field, using a plain one: " + ex.Message));
				return null;
			}
		}

		private static void DisablePersistent(UnityEventBase evt)
		{
			if (evt != null)
			{
				for (int i = 0; i < evt.GetPersistentEventCount(); i++)
				{
					evt.SetPersistentListenerState(i, (UnityEventCallState)0);
				}
			}
		}

		private TMP_InputField CreatePlainSearchField()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_005e: 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_0093: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Search", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.SetActive(false);
			val.transform.SetParent((Transform)(object)_root, false);
			((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.55f);
			GameObject val2 = new GameObject("Text Area", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			});
			val2.transform.SetParent(val.transform, false);
			Stretch((RectTransform)val2.transform, 10f, 10f);
			TMP_Text val3 = CreateText(val2.transform, "Text", "", (TextAlignmentOptions)4097, 1f);
			Stretch(val3.rectTransform, 0f, 0f);
			TMP_Text val4 = CreateText(val2.transform, "Placeholder", Loc.Search, (TextAlignmentOptions)4097, 1f);
			Stretch(val4.rectTransform, 0f, 0f);
			val4.fontStyle = (FontStyles)2;
			((Graphic)val4).color = new Color(1f, 1f, 1f, 0.45f);
			TMP_InputField obj = val.AddComponent<TMP_InputField>();
			obj.textViewport = (RectTransform)val2.transform;
			obj.textComponent = val3;
			obj.placeholder = (Graphic)(object)val4;
			obj.fontAsset = val3.font;
			obj.pointSize = val3.fontSize;
			obj.caretColor = Color.white;
			obj.customCaretColor = true;
			return obj;
		}

		private GameObject CreateButton(Transform parent, string name, out Button button, out Image image)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[4]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button),
				typeof(LayoutElement)
			});
			val.transform.SetParent(parent, false);
			image = val.GetComponent<Image>();
			if (Object.op_Implicit((Object)(object)_templateImage))
			{
				image.sprite = _templateImage.sprite;
				image.type = _templateImage.type;
				((Graphic)image).color = ((Graphic)_templateImage).color;
				image.pixelsPerUnitMultiplier = _templateImage.pixelsPerUnitMultiplier;
				((Graphic)image).material = ((Graphic)_templateImage).material;
			}
			else
			{
				((Graphic)image).color = new Color(0.25f, 0.2f, 0.15f, 0.9f);
			}
			button = val.GetComponent<Button>();
			((Selectable)button).targetGraphic = (Graphic)(object)image;
			if (Object.op_Implicit((Object)(object)_templateButton))
			{
				((Selectable)button).transition = ((Selectable)_templateButton).transition;
				((Selectable)button).colors = ((Selectable)_templateButton).colors;
				((Selectable)button).spriteState = ((Selectable)_templateButton).spriteState;
			}
			Button obj = button;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)obj).navigation = navigation;
			if (Object.op_Implicit((Object)(object)_templateSfx))
			{
				ButtonSfx obj2 = val.AddComponent<ButtonSfx>();
				obj2.m_sfxPrefab = _templateSfx.m_sfxPrefab;
				obj2.m_sfxPrefabVibrationOnly = _templateSfx.m_sfxPrefabVibrationOnly;
				obj2.m_selectSfxPrefab = _templateSfx.m_selectSfxPrefab;
				obj2.m_selectSfxPrefabVibrationOnly = _templateSfx.m_selectSfxPrefabVibrationOnly;
				obj2.m_enterSfxPrefab = _templateSfx.m_enterSfxPrefab;
				obj2.m_enterSfxPrefabVibrationOnly = _templateSfx.m_enterSfxPrefabVibrationOnly;
			}
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.preferredHeight = Plugin.ButtonHeight.Value;
			component.minHeight = Plugin.ButtonHeight.Value;
			component.flexibleWidth = 1f;
			return val;
		}

		private TMP_Text CreateText(Transform parent, string name, string value, TextAlignmentOptions align, float sizeFactor)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(parent, false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			if (Object.op_Implicit((Object)(object)_templateText))
			{
				((TMP_Text)component).font = _templateText.font;
				((TMP_Text)component).fontSharedMaterial = _templateText.fontSharedMaterial;
			}
			((TMP_Text)component).fontSize = Mathf.Clamp(Plugin.ButtonHeight.Value * 0.52f, 12f, 26f) * sizeFactor;
			((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)component).overflowMode = (TextOverflowModes)1;
			((TMP_Text)component).alignment = align;
			((Graphic)component).color = Color.white;
			((Graphic)component).raycastTarget = false;
			((TMP_Text)component).text = value;
			return (TMP_Text)(object)component;
		}

		private static void Stretch(RectTransform rt, float left, float right)
		{
			//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)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.offsetMin = new Vector2(left, 0f);
			rt.offsetMax = new Vector2(0f - right, 0f);
		}

		private void ApplyLayout()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_gui) && Object.op_Implicit((Object)(object)_root))
			{
				float value = Plugin.PanelWidth.Value;
				MeasureProtrusions(out var protrudeLeft, out var protrudeRight);
				bool flag = ResolveSide(value, protrudeLeft, protrudeRight) == PanelSide.Left;
				((Transform)_root).SetAsFirstSibling();
				_root.anchorMin = new Vector2(flag ? 0f : 1f, 0f);
				_root.anchorMax = new Vector2(flag ? 0f : 1f, 1f);
				_root.pivot = new Vector2(flag ? 1f : 0f, 0.5f);
				_root.sizeDelta = new Vector2(value, 0f);
				float num = (flag ? (0f - (6f + protrudeLeft)) : (6f + protrudeRight));
				_root.anchoredPosition = new Vector2(num + Plugin.OffsetX.Value, Plugin.OffsetY.Value);
				float num2 = 8f;
				if (Object.op_Implicit((Object)(object)_search))
				{
					RectTransform val = (RectTransform)((Component)_search).transform;
					val.anchorMin = new Vector2(0f, 1f);
					val.anchorMax = new Vector2(1f, 1f);
					val.pivot = new Vector2(0.5f, 1f);
					val.anchoredPosition = new Vector2(0f, -8f);
					val.sizeDelta = new Vector2(-16f, 34f);
					((Transform)val).localScale = Vector3.one;
					num2 += 40f;
				}
				float value2 = Plugin.ButtonHeight.Value;
				RectTransform val2 = (RectTransform)((Component)_craftableButton).transform;
				val2.anchorMin = new Vector2(0f, 0f);
				val2.anchorMax = new Vector2(1f, 0f);
				val2.pivot = new Vector2(0.5f, 0f);
				val2.anchoredPosition = new Vector2(0f, 8f);
				val2.sizeDelta = new Vector2(-16f, value2);
				RectTransform val3 = (RectTransform)((Component)_scroll).transform;
				val3.anchorMin = Vector2.zero;
				val3.anchorMax = Vector2.one;
				val3.offsetMin = new Vector2(8f, 8f + value2 + 6f);
				val3.offsetMax = new Vector2(-8f, 0f - num2);
				_layoutDirty = !InventoryGui.IsVisible();
			}
		}

		private void MeasureProtrusions(out float protrudeLeft, out float protrudeRight)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			protrudeLeft = 0f;
			protrudeRight = 0f;
			RectTransform crafting = _gui.m_crafting;
			Rect rect = crafting.rect;
			List<RectTransform> list = new List<RectTransform>();
			if (Object.op_Implicit((Object)(object)_gui.m_repairButton))
			{
				list.Add((RectTransform)((Component)_gui.m_repairButton).transform);
			}
			Selectable[] componentsInChildren = ((Component)crafting).GetComponentsInChildren<Selectable>(true);
			foreach (Selectable val in componentsInChildren)
			{
				if (!((Component)val).transform.IsChildOf((Transform)(object)_root))
				{
					list.Add((RectTransform)((Component)val).transform);
				}
			}
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			foreach (RectTransform item in list)
			{
				item.GetWorldCorners(array);
				float num = float.MaxValue;
				float num2 = float.MinValue;
				Vector3[] array2 = array;
				foreach (Vector3 val2 in array2)
				{
					float x = ((Transform)crafting).InverseTransformPoint(val2).x;
					num = Mathf.Min(num, x);
					num2 = Mathf.Max(num2, x);
				}
				if (num < ((Rect)(ref rect)).xMin && ((Rect)(ref rect)).xMin - num < 300f)
				{
					protrudeLeft = Mathf.Max(protrudeLeft, ((Rect)(ref rect)).xMin - num);
				}
				if (num2 > ((Rect)(ref rect)).xMax && num2 - ((Rect)(ref rect)).xMax < 300f)
				{
					protrudeRight = Mathf.Max(protrudeRight, num2 - ((Rect)(ref rect)).xMax);
				}
			}
			if (!_loggedLayout)
			{
				_loggedLayout = true;
				Plugin.Log.LogInfo((object)$"Crafting panel {rect}; widgets stick out left {protrudeLeft:0}, right {protrudeRight:0}");
			}
		}

		private PanelSide ResolveSide(float width, float protrudeLeft, float protrudeRight)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0066: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Side.Value != PanelSide.Auto)
			{
				return Plugin.Side.Value;
			}
			Canvas componentInParent = ((Component)_gui).GetComponentInParent<Canvas>();
			componentInParent = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.rootCanvas : null);
			if (!Object.op_Implicit((Object)(object)componentInParent))
			{
				return PanelSide.Left;
			}
			RectTransform val = (RectTransform)((Component)componentInParent).transform;
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			_gui.m_crafting.GetWorldCorners(array);
			float x = ((Transform)val).InverseTransformPoint(array[0]).x;
			float x2 = ((Transform)val).InverseTransformPoint(array[2]).x;
			Rect rect = val.rect;
			float num = x - ((Rect)(ref rect)).xMin;
			rect = val.rect;
			float num2 = ((Rect)(ref rect)).xMax - x2;
			if (num >= width + 6f + protrudeLeft)
			{
				return PanelSide.Left;
			}
			if (num2 >= width + 6f + protrudeRight)
			{
				return PanelSide.Right;
			}
			if (!(num - protrudeLeft >= num2 - protrudeRight))
			{
				return PanelSide.Right;
			}
			return PanelSide.Left;
		}

		public void SetCategories(List<CategoryEntry> categories, string selectedKey)
		{
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Expected O, but got Unknown
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			string text = Signature(categories, selectedKey);
			if (text == _signature)
			{
				return;
			}
			_signature = text;
			foreach (GameObject button2 in _buttons)
			{
				Object.Destroy((Object)(object)button2);
			}
			_buttons.Clear();
			float value = Plugin.ButtonHeight.Value;
			foreach (CategoryEntry category in categories)
			{
				bool flag = category.Key == selectedKey;
				Button button;
				Image image;
				GameObject val = CreateButton((Transform)(object)_content, "Category_" + category.Key, out button, out image);
				Sprite val2 = ((!Plugin.ShowModIcons.Value) ? null : category.Source?.Icon);
				float left = 10f;
				if (Object.op_Implicit((Object)(object)val2))
				{
					GameObject val3 = new GameObject("Icon", new Type[2]
					{
						typeof(RectTransform),
						typeof(Image)
					});
					val3.transform.SetParent(val.transform, false);
					Image component = val3.GetComponent<Image>();
					component.sprite = val2;
					component.preserveAspect = true;
					((Graphic)component).raycastTarget = false;
					RectTransform val4 = (RectTransform)val3.transform;
					Vector2 anchorMin = (val4.anchorMax = new Vector2(0f, 0.5f));
					val4.anchorMin = anchorMin;
					val4.pivot = new Vector2(0f, 0.5f);
					val4.sizeDelta = new Vector2(value - 8f, value - 8f);
					val4.anchoredPosition = new Vector2(5f, 0f);
					left = value + 2f;
				}
				bool flag2 = NewRecipes.Enabled && category.NewCount > 0;
				float num = (Plugin.ShowCounts.Value ? 38f : 0f) + (flag2 ? 34f : 0f);
				TMP_Text val6 = CreateText(val.transform, "Label", category.Name, (TextAlignmentOptions)4097, 1f);
				Stretch(val6.rectTransform, left, num + 6f);
				if (Plugin.ShowCounts.Value || flag2)
				{
					string text2 = (Plugin.ShowCounts.Value ? category.Count.ToString() : "");
					if (flag2)
					{
						text2 = $"<color=#8CFF5A><b>+{category.NewCount}</b></color> " + text2;
					}
					TMP_Text obj = CreateText(val.transform, "Count", text2.TrimEnd(), (TextAlignmentOptions)4100, 0.85f);
					RectTransform rectTransform = obj.rectTransform;
					rectTransform.anchorMin = new Vector2(1f, 0f);
					rectTransform.anchorMax = new Vector2(1f, 1f);
					rectTransform.pivot = new Vector2(1f, 0.5f);
					rectTransform.sizeDelta = new Vector2(num, 0f);
					rectTransform.anchoredPosition = new Vector2(-8f, 0f);
					((Graphic)obj).color = (flag ? SelectedText : CountText);
				}
				if (flag)
				{
					((Graphic)image).color = SelectedTint;
					((Graphic)val6).color = SelectedText;
					val6.fontStyle = (FontStyles)1;
				}
				string key = category.Key;
				((UnityEvent)button.onClick).AddListener((UnityAction)delegate
				{
					CraftFilter.SelectCategory(key);
				});
				val.AddComponent<RightClickHandler>().OnRightClick = delegate
				{
					CraftFilter.MarkCategorySeen(key);
				};
				_buttons.Add(val);
			}
		}

		private static string Signature(List<CategoryEntry> categories, string selectedKey)
		{
			StringBuilder stringBuilder = new StringBuilder(selectedKey);
			foreach (CategoryEntry category in categories)
			{
				stringBuilder.Append('|').Append(category.Key).Append(':')
					.Append(category.Count)
					.Append('+')
					.Append(category.NewCount);
			}
			return stringBuilder.ToString();
		}

		private void UpdateCraftableVisual()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			bool craftableOnly = CraftFilter.CraftableOnly;
			((Graphic)_craftableImage).color = (craftableOnly ? SelectedTint : (Object.op_Implicit((Object)(object)_templateImage) ? ((Graphic)_templateImage).color : Color.white));
			((Graphic)_craftableLabel).color = (craftableOnly ? SelectedText : Color.white);
			_craftableLabel.text = (craftableOnly ? "<b>" : "") + Loc.CraftableOnly + (craftableOnly ? "</b>" : "");
		}
	}
	internal class RightClickHandler : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
	{
		public Action OnRightClick;

		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 == 1)
			{
				OnRightClick?.Invoke();
			}
		}
	}
	internal sealed class CategoryEntry
	{
		public string Key;

		public string Name;

		public int Count;

		public int NewCount;

		public ModSource Source;
	}
	[HarmonyPatch]
	internal static class CraftFilter
	{
		public const string AllKey = "*";

		public static string SelectedKey = "*";

		public static string SearchText = "";

		public static bool CraftableOnly;

		public static readonly List<CategoryEntry> Categories = new List<CategoryEntry>();

		public static readonly List<Recipe> LastUnfiltered = new List<Recipe>();

		private static readonly Dictionary<string, string> SelectedByStation = new Dictionary<string, string>();

		private static string _stationKey;

		private static readonly List<ItemData> TempItems = new List<ItemData>();

		private static readonly Dictionary<string, int> TempCounts = new Dictionary<string, int>();

		private static readonly Dictionary<string, int> TempNewCounts = new Dictionary<string, int>();

		private static readonly Dictionary<string, ModSource> TempSources = new Dictionary<string, ModSource>();

		private static bool _loggedOwners;

		public static void SelectCategory(string key)
		{
			SelectedKey = key;
			if (_stationKey != null)
			{
				SelectedByStation[_stationKey] = key;
			}
			Refresh(scrollToTop: true);
		}

		public static void SetSearch(string text)
		{
			text = text ?? "";
			if (!(text == SearchText))
			{
				SearchText = text;
				Refresh(scrollToTop: true);
			}
		}

		public static void SetCraftableOnly(bool value)
		{
			CraftableOnly = value;
			Refresh(scrollToTop: true);
		}

		public static void MarkCategorySeen(string key)
		{
			if (NewRecipes.MarkSeen(LastUnfiltered.Where((Recipe r) => key == "*" || ModOwnership.Resolve(r).Key == key).ToList()))
			{
				Refresh(scrollToTop: false);
			}
		}

		public static void Refresh(bool scrollToTop)
		{
			InventoryGui instance = InventoryGui.instance;
			if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && InventoryGui.IsVisible())
			{
				instance.UpdateCraftingPanel(false);
				if (scrollToTop && Object.op_Implicit((Object)(object)instance.m_recipeListScroll))
				{
					instance.m_recipeListScroll.value = 1f;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		[HarmonyPostfix]
		private static void ShowPostfix(InventoryGui __instance)
		{
			if (Plugin.Enabled.Value)
			{
				CategoryPanel.Ensure(__instance);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		[HarmonyPostfix]
		private static void HidePostfix()
		{
			CategoryPanel.Instance?.OnInventoryHidden();
			if (Plugin.ResetSearchOnClose.Value)
			{
				SearchText = "";
				CategoryPanel.Instance?.ClearSearchField();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "local.valheim.craftsearch" })]
		private static void UpdateRecipeListPrefix(InventoryGui __instance, List<Recipe> recipes)
		{
			if (!Plugin.Enabled.Value || recipes == null)
			{
				return;
			}
			Player player = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)player))
			{
				return;
			}
			try
			{
				CategoryPanel.Ensure(__instance);
				ModOwnership.RefreshIndex();
				CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
				OnStationChanged(currentCraftingStation);
				bool craftTab = __instance.InCraftTab();
				BuildCategories(recipes, player, currentCraftingStation, craftTab);
				LogOwnersOnce(recipes);
				bool noCost = Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey((GlobalKeys)25);
				string[] terms = SplitTerms(SearchText);
				recipes.RemoveAll((Recipe recipe) => !MatchesCategory(recipe) || !MatchesSearch(recipe, terms) || (CraftableOnly && craftTab && !noCost && !player.HaveRequirements(recipe, false, 1, 1)));
				CategoryPanel.Instance?.SetCategories(Categories, SelectedKey);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Filtering recipes failed: {arg}");
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		[HarmonyPostfix]
		private static void UpdateRecipeListPostfix(InventoryGui __instance)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value)
			{
				return;
			}
			try
			{
				bool flag = __instance.InCraftTab();
				bool flag2 = NewRecipes.Enabled && flag;
				bool flag3 = Plugin.ShowModTagInAll.Value && SelectedKey == "*";
				if (!flag2 && !flag3)
				{
					return;
				}
				foreach (RecipeDataPair availableRecipe in __instance.m_availableRecipes)
				{
					RecipeDataPair current = availableRecipe;
					if (!Object.op_Implicit((Object)(object)((RecipeDataPair)(ref current)).InterfaceElement))
					{
						continue;
					}
					Transform obj = ((RecipeDataPair)(ref current)).InterfaceElement.transform.Find("name");
					TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
					if (!Object.op_Implicit((Object)(object)val))
					{
						continue;
					}
					if (flag2 && NewRecipes.IsNew(((RecipeDataPair)(ref current)).Recipe))
					{
						val.text = "<size=75%><color=#8CFF5A><b>" + Loc.New + "</b></color></size> " + val.text;
					}
					if (flag3)
					{
						ModSource modSource = ModOwnership.Resolve(((RecipeDataPair)(ref current)).Recipe);
						if (modSource.Key != "valheim")
						{
							val.text = val.text + " <size=70%><color=#C8A26B>· " + modSource.Name + "</color></size>";
						}
					}
				}
				if (flag2 && Plugin.SortNewFirst.Value)
				{
					List<RecipeDataPair> list = __instance.m_availableRecipes.OrderBy((RecipeDataPair p) => (!NewRecipes.IsNew(((RecipeDataPair)(ref p)).Recipe)) ? 1 : 0).ToList();
					__instance.m_availableRecipes.Clear();
					__instance.m_availableRecipes.AddRange(list);
					for (int num = 0; num < list.Count; num++)
					{
						RecipeDataPair val2 = list[num];
						((RectTransform)((RecipeDataPair)(ref val2)).InterfaceElement.transform).anchoredPosition = new Vector2(0f, (float)num * (0f - __instance.m_recipeListSpace));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Mod tags failed: " + ex.Message));
			}
		}

		private static void OnStationChanged(CraftingStation station)
		{
			string text = (Object.op_Implicit((Object)(object)station) ? station.m_name : "$hand");
			if (!(text == _stationKey))
			{
				_stationKey = text;
				if (Plugin.RememberPerStation.Value)
				{
					SelectedKey = (SelectedByStation.TryGetValue(text, out var value) ? value : "*");
				}
			}
		}

		private static bool VisibleInTab(Recipe recipe, Player player, CraftingStation station, bool craftTab)
		{
			if (!Object.op_Implicit((Object)(object)recipe) || !Object.op_Implicit((Object)(object)recipe.m_item))
			{
				return false;
			}
			if (craftTab)
			{
				return !recipe.m_noCraftOnlyUpgrade;
			}
			SharedData shared = recipe.m_item.m_itemData.m_shared;
			if (shared.m_maxQuality <= 1)
			{
				return false;
			}
			bool flag = Object.op_Implicit((Object)(object)station) && station.m_upgrader;
			TempItems.Clear();
			((Humanoid)player).GetInventory().GetAllItems(shared.m_name, TempItems);
			foreach (ItemData tempItem in TempItems)
			{
				if (flag || tempItem.m_quality < tempItem.m_shared.m_maxQuality)
				{
					return true;
				}
			}
			return false;
		}

		private static void BuildCategories(List<Recipe> recipes, Player player, CraftingStation station, bool craftTab)
		{
			TempCounts.Clear();
			TempNewCounts.Clear();
			TempSources.Clear();
			LastUnfiltered.Clear();
			int num = 0;
			int num2 = 0;
			foreach (Recipe recipe in recipes)
			{
				if (VisibleInTab(recipe, player, station, craftTab))
				{
					ModSource modSource = ModOwnership.Resolve(recipe);
					TempSources[modSource.Key] = modSource;
					TempCounts.TryGetValue(modSource.Key, out var value);
					TempCounts[modSource.Key] = value + 1;
					num++;
					LastUnfiltered.Add(recipe);
					if (craftTab && NewRecipes.IsNew(recipe))
					{
						TempNewCounts.TryGetValue(modSource.Key, out var value2);
						TempNewCounts[modSource.Key] = value2 + 1;
						num2++;
					}
				}
			}
			if (SelectedKey != "*" && !TempCounts.ContainsKey(SelectedKey))
			{
				ModSource modSource2 = Categories.FirstOrDefault((CategoryEntry c) => c.Key == SelectedKey)?.Source;
				if (modSource2 != null)
				{
					TempSources[modSource2.Key] = modSource2;
					TempCounts[modSource2.Key] = 0;
				}
				else
				{
					SelectedKey = "*";
				}
			}
			Categories.Clear();
			Categories.Add(new CategoryEntry
			{
				Key = "*",
				Name = Loc.All,
				Count = num,
				NewCount = num2
			});
			foreach (ModSource item in TempSources.Values.OrderBy((ModSource s) => s.Order).ThenBy<ModSource, string>((ModSource s) => s.Name, StringComparer.OrdinalIgnoreCase))
			{
				Categories.Add(new CategoryEntry
				{
					Key = item.Key,
					Name = item.Name,
					Count = TempCounts[item.Key],
					NewCount = (TempNewCounts.TryGetValue(item.Key, out var value3) ? value3 : 0),
					Source = item
				});
			}
		}

		private static bool MatchesCategory(Recipe recipe)
		{
			if (!(SelectedKey == "*"))
			{
				return ModOwnership.Resolve(recipe).Key == SelectedKey;
			}
			return true;
		}

		private static string[] SplitTerms(string text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return Array.Empty<string>();
			}
			return text.ToLowerInvariant().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
		}

		private static bool MatchesSearch(Recipe recipe, string[] terms)
		{
			if (terms.Length == 0)
			{
				return true;
			}
			if (!Object.op_Implicit((Object)(object)recipe) || !Object.op_Implicit((Object)(object)recipe.m_item))
			{
				return false;
			}
			StringBuilder stringBuilder = new StringBuilder();
			SharedData shared = recipe.m_item.m_itemData.m_shared;
			stringBuilder.Append(Localization.instance.Localize(shared.m_name)).Append('\n');
			stringBuilder.Append(((Object)recipe.m_item).name).Append('\n');
			if (Plugin.SearchIngredients.Value && recipe.m_resources != null)
			{
				Requirement[] resources = recipe.m_resources;
				foreach (Requirement val in resources)
				{
					if (Object.op_Implicit((Object)(object)val?.m_resItem))
					{
						stringBuilder.Append(Localization.instance.Localize(val.m_resItem.m_itemData.m_shared.m_name)).Append('\n');
					}
				}
			}
			string text = stringBuilder.ToString().ToLowerInvariant();
			foreach (string value in terms)
			{
				if (!text.Contains(value))
				{
					return false;
				}
			}
			return true;
		}

		private static void LogOwnersOnce(List<Recipe> recipes)
		{
			if (!Plugin.LogRecipeOwners.Value || _loggedOwners || !Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return;
			}
			_loggedOwners = true;
			StringBuilder stringBuilder = new StringBuilder("Recipe owners:\n");
			foreach (IGrouping<string, Recipe> item in from r in ObjectDB.instance.m_recipes
				where Object.op_Implicit((Object)(object)r) && Object.op_Implicit((Object)(object)r.m_item)
				group r by ModOwnership.Resolve(r).Name into g
				orderby g.Key
				select g)
			{
				stringBuilder.AppendLine($"  [{item.Key}] {item.Count()} recipes");
				foreach (Recipe item2 in item)
				{
					stringBuilder.AppendLine("      " + ((Object)item2).name + " -> " + ((Object)item2.m_item).name);
				}
			}
			Plugin.Log.LogInfo((object)stringBuilder.ToString());
		}
	}
	[HarmonyPatch]
	internal static class InputGuard
	{
		private static int _lastTypingFrame = -10;

		public static bool Blocking
		{
			get
			{
				if (Object.op_Implicit((Object)(object)CategoryPanel.Instance) && CategoryPanel.Instance.SearchFocused)
				{
					_lastTypingFrame = Time.frameCount;
					return true;
				}
				return Time.frameCount - _lastTypingFrame <= 1;
			}
		}

		[HarmonyPatch(typeof(ZInput), "TryGetButtonState")]
		[HarmonyPrefix]
		private static bool ButtonStatePrefix(string name, ref bool __result)
		{
			if (!Blocking || name == null || name.StartsWith("Mouse", StringComparison.Ordinal))
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(ZInput), "TryGetKeyStateLowLevel")]
		[HarmonyPrefix]
		private static bool KeyStatePrefix(KeyCode keyCode, ref bool __result)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (!Blocking || IsEditingKey(keyCode))
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool IsEditingKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: 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_0011: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			if ((int)key == 8 || (int)key == 127 || key - 305 <= 1)
			{
				return true;
			}
			if ((int)key >= 323)
			{
				return (int)key <= 329;
			}
			return false;
		}
	}
	internal static class Loc
	{
		private static string Lang
		{
			get
			{
				try
				{
					Localization instance = Localization.instance;
					return ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "English";
				}
				catch
				{
					return "English";
				}
			}
		}

		public static string All => Pick("All", "Усі", "Все");

		public static string OtherMods => Pick("Other mods", "Інші моди", "Другие моды");

		public static string Search => Pick("Search...", "Пошук...", "Поиск...");

		public static string CraftableOnly => Pick("Craftable only", "Лише доступні", "Только доступные");

		public static string New => Pick("NEW", "НОВЕ", "НОВОЕ");

		public static string Categories => Pick("Categories", "Категорії", "Категории");

		private static string Pick(string en, string uk, string ru)
		{
			string lang = Lang;
			if (!(lang == "Ukrainian"))
			{
				if (lang == "Russian")
				{
					return ru;
				}
				return en;
			}
			return uk;
		}
	}
	internal sealed class ModSource
	{
		public readonly string Key;

		public readonly string Name;

		public readonly int Order;

		private readonly string _iconPath;

		private Sprite _icon;

		private bool _iconLoaded;

		public Sprite Icon
		{
			get
			{
				if (_iconLoaded)
				{
					return _icon;
				}
				_iconLoaded = true;
				_icon = ((Key == "valheim") ? ModOwnership.VanillaIcon() : LoadSprite(_iconPath));
				return _icon;
			}
		}

		public ModSource(string key, string name, int order, string iconPath)
		{
			Key = key;
			Name = name;
			Order = order;
			_iconPath = iconPath;
		}

		private static Sprite LoadSprite(string path)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(path) || !File.Exists(path))
			{
				return null;
			}
			try
			{
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
				{
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)1;
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Could not load icon " + path + ": " + ex.Message));
				return null;
			}
		}
	}
	[HarmonyPatch]
	internal static class ModOwnership
	{
		public const string VanillaKey = "valheim";

		public const string UnknownKey = "unknown";

		private static HashSet<string> _vanillaRecipes;

		private static HashSet<string> _vanillaItems;

		private static readonly Dictionary<Recipe, ModSource> Cache = new Dictionary<Recipe, ModSource>();

		private static readonly Dictionary<string, ModSource> Sources = new Dictionary<string, ModSource>();

		private static readonly Dictionary<Recipe, string> RecipeToGuid = new Dictionary<Recipe, string>();

		private static int _indexedRecipeCount = -1;

		private static int _indexedObjectDbRecipes = -1;

		private static readonly FieldInfo ModQueryRecipesField = AccessTools.Field(typeof(ModQuery), "Recipes");

		public static ModSource Vanilla => GetSource("valheim");

		public static ModSource Unknown => GetSource("unknown");

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		[HarmonyPrefix]
		[HarmonyPriority(int.MaxValue)]
		private static void ObjectDBAwakePrefix(ObjectDB __instance)
		{
			TrySnapshot(__instance);
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		[HarmonyPrefix]
		[HarmonyPriority(int.MaxValue)]
		private static void ObjectDBCopyPrefix(ObjectDB other)
		{
			TrySnapshot(other);
		}

		private static void TrySnapshot(ObjectDB db)
		{
			if (_vanillaRecipes != null || !Object.op_Implicit((Object)(object)db) || db.m_recipes == null || db.m_recipes.Count == 0)
			{
				return;
			}
			_vanillaRecipes = new HashSet<string>();
			foreach (Recipe recipe in db.m_recipes)
			{
				if (Object.op_Implicit((Object)(object)recipe))
				{
					_vanillaRecipes.Add(((Object)recipe).name);
				}
			}
			_vanillaItems = new HashSet<string>();
			foreach (GameObject item in db.m_items)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					_vanillaItems.Add(((Object)item).name);
				}
			}
			Plugin.Log.LogInfo((object)$"Vanilla snapshot: {_vanillaRecipes.Count} recipes, {_vanillaItems.Count} items");
		}

		[HarmonyPatch(typeof(ZNetScene), "OnDestroy")]
		[HarmonyPostfix]
		private static void ClearOnLogout()
		{
			Cache.Clear();
			RecipeToGuid.Clear();
			_indexedRecipeCount = -1;
			_indexedObjectDbRecipes = -1;
		}

		public static ModSource Resolve(Recipe recipe)
		{
			if (!Object.op_Implicit((Object)(object)recipe))
			{
				return Unknown;
			}
			if (Cache.TryGetValue(recipe, out var value))
			{
				return value;
			}
			ModSource modSource = ResolveUncached(recipe);
			Cache[recipe] = modSource;
			return modSource;
		}

		private static ModSource ResolveUncached(Recipe recipe)
		{
			string text = (Object.op_Implicit((Object)(object)recipe.m_item) ? ((Object)recipe.m_item).name : null);
			bool flag = text != null && _vanillaItems != null && _vanillaItems.Contains(text);
			if (_vanillaRecipes != null && _vanillaRecipes.Contains(((Object)recipe).name) && (text == null || flag))
			{
				return Vanilla;
			}
			if (RecipeToGuid.TryGetValue(recipe, out var value))
			{
				return FromGuid(value);
			}
			ModSource modSource = FromJotunnRegistry(recipe);
			if (modSource != null)
			{
				return modSource;
			}
			if (text != null && !flag)
			{
				IModPrefab val = SafeGetPrefab(text);
				if (((val != null) ? val.SourceMod : null) != null)
				{
					return FromGuid(val.SourceMod.GUID);
				}
			}
			if (_vanillaRecipes == null)
			{
				if (!flag && text != null)
				{
					return Unknown;
				}
				return Vanilla;
			}
			if (!flag || !_vanillaRecipes.Contains(((Object)recipe).name))
			{
				return Unknown;
			}
			return Vanilla;
		}

		private static IModPrefab SafeGetPrefab(string name)
		{
			try
			{
				return ModQuery.GetPrefab(name);
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static ModSource FromJotunnRegistry(Recipe recipe)
		{
			try
			{
				foreach (CustomRecipe recipe2 in ModRegistry.GetRecipes())
				{
					if (!((Object)(object)((recipe2 != null) ? recipe2.Recipe : null) == (Object)null) && ((CustomEntity)recipe2).SourceMod != null && ((Object)(object)recipe2.Recipe == (Object)(object)recipe || ((Object)recipe2.Recipe).name == ((Object)recipe).name))
					{
						return FromGuid(((CustomEntity)recipe2).SourceMod.GUID);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("ModRegistry lookup failed: " + ex.Message));
			}
			return null;
		}

		public static void RefreshIndex()
		{
			int num = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.m_recipes.Count : 0);
			Dictionary<string, List<Recipe>> dictionary = ModQueryRecipesField?.GetValue(null) as Dictionary<string, List<Recipe>>;
			int num2 = 0;
			if (dictionary != null)
			{
				foreach (KeyValuePair<string, List<Recipe>> item in dictionary)
				{
					num2 += item.Value?.Count ?? 0;
				}
			}
			if (num2 == _indexedRecipeCount && num == _indexedObjectDbRecipes)
			{
				return;
			}
			_indexedRecipeCount = num2;
			_indexedObjectDbRecipes = num;
			RecipeToGuid.Clear();
			Cache.Clear();
			if (dictionary == null)
			{
				return;
			}
			foreach (KeyValuePair<string, List<Recipe>> item2 in dictionary)
			{
				if (item2.Value == null || item2.Key == "com.jotunn.jotunn")
				{
					continue;
				}
				foreach (Recipe item3 in item2.Value)
				{
					if (Object.op_Implicit((Object)(object)item3) && !RecipeToGuid.ContainsKey(item3))
					{
						RecipeToGuid.Add(item3, item2.Key);
					}
				}
			}
		}

		private static ModSource FromGuid(string guid)
		{
			if (!string.IsNullOrEmpty(guid))
			{
				return GetSource(guid);
			}
			return Unknown;
		}

		private static ModSource GetSource(string key)
		{
			if (Sources.TryGetValue(key, out var value))
			{
				return value;
			}
			if (!(key == "valheim"))
			{
				if (key == "unknown")
				{
					value = new ModSource(key, Loc.OtherMods, 2, null);
				}
				else
				{
					string name = key;
					string iconPath = null;
					if (Chainloader.PluginInfos.TryGetValue(key, out var value2))
					{
						name = value2.Metadata.Name;
						iconPath = FindIcon(value2.Location);
					}
					value = new ModSource(key, name, 1, iconPath);
				}
			}
			else
			{
				value = new ModSource(key, "Valheim", 0, null);
			}
			Sources[key] = value;
			return value;
		}

		private static string FindIcon(string dllPath)
		{
			try
			{
				if (string.IsNullOrEmpty(dllPath))
				{
					return null;
				}
				string b = Path.GetFullPath(Paths.PluginPath).TrimEnd(Path.DirectorySeparatorChar);
				string directoryName = Path.GetDirectoryName(Path.GetFullPath(dllPath));
				for (int i = 0; i < 4; i++)
				{
					if (string.IsNullOrEmpty(directoryName))
					{
						break;
					}
					if (string.Equals(directoryName.TrimEnd(Path.DirectorySeparatorChar), b, StringComparison.OrdinalIgnoreCase))
					{
						break;
					}
					string text = Path.Combine(directoryName, "icon.png");
					if (File.Exists(text))
					{
						return text;
					}
					directoryName = Path.GetDirectoryName(directoryName);
				}
			}
			catch (Exception)
			{
			}
			return null;
		}

		internal static Sprite VanillaIcon()
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer");
			ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return val.m_itemData.GetIcon();
		}
	}
	[HarmonyPatch]
	internal static class NewRecipes
	{
		private const string SaveKey = "CraftingCategories.NewRecipes";

		private static Player _owner;

		private static HashSet<string> _new = new HashSet<string>();

		private static bool _inPanelUpdate;

		public static bool Enabled => Plugin.HighlightNew.Value;

		public static bool IsNew(Recipe recipe)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Enabled || !Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)recipe) || !Object.op_Implicit((Object)(object)recipe.m_item))
			{
				return false;
			}
			return For(localPlayer).Contains(recipe.m_item.m_itemData.m_shared.m_name);
		}

		public static bool MarkSeen(IEnumerable<Recipe> recipes)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return false;
			}
			HashSet<string> hashSet = For(localPlayer);
			bool flag = false;
			foreach (Recipe recipe in recipes)
			{
				if (Object.op_Implicit((Object)(object)recipe) && Object.op_Implicit((Object)(object)recipe.m_item))
				{
					flag |= hashSet.Remove(recipe.m_item.m_itemData.m_shared.m_name);
				}
			}
			if (flag)
			{
				Save(localPlayer);
			}
			return flag;
		}

		private static HashSet<string> For(Player player)
		{
			if ((Object)(object)_owner == (Object)(object)player)
			{
				return _new;
			}
			_owner = player;
			_new = new HashSet<string>();
			if (player.m_customData.TryGetValue("CraftingCategories.NewRecipes", out var value) && !string.IsNullOrEmpty(value))
			{
				string[] array = value.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string item in array)
				{
					_new.Add(item);
				}
			}
			return _new;
		}

		private static void Save(Player player)
		{
			HashSet<string> hashSet = For(player);
			if (hashSet.Count == 0)
			{
				player.m_customData.Remove("CraftingCategories.NewRecipes");
			}
			else
			{
				player.m_customData["CraftingCategories.NewRecipes"] = string.Join("\n", hashSet);
			}
		}

		[HarmonyPatch(typeof(Player), "AddKnownRecipe")]
		[HarmonyPrefix]
		private static void AddKnownRecipePrefix(Player __instance, Recipe recipe, out bool __state)
		{
			__state = Object.op_Implicit((Object)(object)recipe) && Object.op_Implicit((Object)(object)recipe.m_item) && !__instance.m_knownRecipes.Contains(recipe.m_item.m_itemData.m_shared.m_name);
		}

		[HarmonyPatch(typeof(Player), "AddKnownRecipe")]
		[HarmonyPostfix]
		private static void AddKnownRecipePostfix(Player __instance, Recipe recipe, bool __state)
		{
			if (__state && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && For(__instance).Add(recipe.m_item.m_itemData.m_shared.m_name))
			{
				Save(__instance);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
		[HarmonyPrefix]
		private static void UpdateCraftingPanelPrefix()
		{
			_inPanelUpdate = true;
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
		[HarmonyFinalizer]
		private static void UpdateCraftingPanelFinalizer()
		{
			_inPanelUpdate = false;
		}

		[HarmonyPatch(typeof(InventoryGui), "SetRecipe")]
		[HarmonyPostfix]
		private static void SetRecipePostfix(InventoryGui __instance, int index)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!_inPanelUpdate && Enabled && index >= 0 && index < __instance.m_availableRecipes.Count)
			{
				Recipe[] array = new Recipe[1];
				RecipeDataPair val = __instance.m_availableRecipes[index];
				array[0] = ((RecipeDataPair)(ref val)).Recipe;
				if (MarkSeen((IEnumerable<Recipe>)(object)array))
				{
					CategoryPanel.Instance?.RequestRefresh();
				}
			}
		}
	}
	public enum PanelSide
	{
		Auto,
		Left,
		Right
	}
	public enum SearchMode
	{
		Auto,
		On,
		Off
	}
	[BepInPlugin("com.kuzuk.valheim.craftingcategories", "CraftingCategories", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.kuzuk.valheim.craftingcategories";

		public const string Name = "CraftingCategories";

		public const string Version = "1.0.1";

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

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<PanelSide> Side;

		internal static ConfigEntry<float> PanelWidth;

		internal static ConfigEntry<float> OffsetX;

		internal static ConfigEntry<float> OffsetY;

		internal static ConfigEntry<float> ButtonHeight;

		internal static ConfigEntry<bool> ShowModIcons;

		internal static ConfigEntry<bool> ShowCounts;

		internal static ConfigEntry<SearchMode> Search;

		internal static ConfigEntry<bool> SearchIngredients;

		internal static ConfigEntry<bool> ResetSearchOnClose;

		internal static ConfigEntry<bool> RememberPerStation;

		internal static ConfigEntry<bool> ShowModTagInAll;

		internal static ConfigEntry<bool> LogRecipeOwners;

		internal static ConfigEntry<bool> HighlightNew;

		internal static ConfigEntry<bool> SortNewFirst;

		internal static bool SearchEnabled => Search.Value switch
		{
			SearchMode.On => true, 
			SearchMode.Off => false, 
			_ => !Chainloader.PluginInfos.ContainsKey("local.valheim.craftsearch"), 
		};

		private void Awake()
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Invalid comparison between Unknown and I4
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Show the category sidebar next to the crafting menu.");
			RememberPerStation = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "RememberCategoryPerStation", true, "Remember the last selected category separately for every crafting station.");
			ShowModTagInAll = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ShowModTagInAllCategory", true, "In the 'All' category, append the source mod name to recipes added by mods.");
			Side = ((BaseUnityPlugin)this).Config.Bind<PanelSide>("2 - Layout", "PanelSide", PanelSide.Auto, "Which side of the crafting panel the sidebar is attached to. Auto picks the side with more free space.");
			PanelWidth = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Layout", "PanelWidth", 230f, new ConfigDescription("Sidebar width.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(120f, 500f), Array.Empty<object>()));
			ButtonHeight = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Layout", "ButtonHeight", 32f, new ConfigDescription("Height of one category button.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 64f), Array.Empty<object>()));
			OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Layout", "OffsetX", 0f, "Extra horizontal offset of the sidebar.");
			OffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Layout", "OffsetY", 0f, "Extra vertical offset of the sidebar.");
			ShowModIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Layout", "ShowModIcons", true, "Show the mod's Thunderstore icon (icon.png next to the DLL) on its category button.");
			ShowCounts = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Layout", "ShowCounts", true, "Show how many recipes each category contains at the current station.");
			Search = ((BaseUnityPlugin)this).Config.Bind<SearchMode>("3 - Search", "SearchField", SearchMode.Auto, "Search field at the top of the sidebar. Auto = enabled unless Workstation Search is installed (it has its own).");
			SearchIngredients = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Search", "SearchInIngredients", false, "Also match recipes whose ingredients contain the search text.");
			ResetSearchOnClose = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Search", "ResetSearchOnClose", true, "Clear the search text when the inventory is closed.");
			HighlightNew = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - New recipes", "HighlightNewRecipes", true, "Mark freshly discovered recipes with a NEW badge (and +N on category buttons) until you select them. Right-click a category button to mark all its recipes as seen.");
			SortNewFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - New recipes", "SortNewFirst", false, "Put new recipes at the top of the list.");
			LogRecipeOwners = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "LogRecipeOwners", false, "Write every recipe and the mod it was attributed to into the BepInEx log when a station is opened.");
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				Log.LogInfo((object)"Dedicated server detected - CraftingCategories is client-only and stays inactive.");
				return;
			}
			ModQuery.Enable();
			new Harmony("com.kuzuk.valheim.craftingcategories").PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				CategoryPanel.Instance?.OnConfigChanged();
			};
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}