Decompiled source of ZenUI v0.9.2

plugins/ZenUI.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using GUIFramework;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.PostProcessing;
using UnityEngine.UI;
using Zen;
using Zen.Lib;
using Zen.Lib.Config;
using ZenUI.Compatibility;
using ZenUI.Section;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenUI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZenUI")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ZenUI
{
	internal enum UncraftableSymbolPosition
	{
		None,
		Center,
		TopLeft
	}
	[Flags]
	internal enum BiomeNoticeType
	{
		PlayerSpawn = 1,
		Teleport = 2,
		Discovery = 4
	}
	internal static class Configs
	{
		public static readonly ConfigEntry<bool> CameraRemoveLensDirt;

		public static readonly ConfigEntry<int> CameraLodBias;

		public static readonly ConfigEntry<bool> EnableAmmoCount;

		public static readonly ConfigEntry<bool> AutoOpenSkillsPanel;

		public static readonly ConfigEntry<bool> EnableSlideAnimation;

		public static readonly ConfigEntry<bool> ColoredFoodBars;

		public static readonly ConfigEntry<BiomeNoticeType> ShowBiomeNotice;

		public static readonly ConfigEntry<StringList> HideStatusEffects;

		public static readonly ConfigEntry<bool> CraftPanelEnabled;

		public static readonly ConfigEntry<bool> CraftPanelTooltipReq;

		public static readonly ConfigEntry<bool> CraftPanelTooltipHover;

		public static readonly ConfigEntry<bool> CraftPanelSearch;

		public static readonly ConfigEntry<Vector2> CraftPanelSearchPosition;

		public static readonly ConfigEntry<bool> CraftPanelSearchResources;

		public static readonly ConfigEntry<bool> CraftPanelSearchArmorSets;

		public static readonly ConfigEntry<bool> CraftPanelSortCraftable;

		public static readonly ConfigEntry<bool> CraftPanelShowAnyKnownStation;

		public static readonly ConfigEntry<bool> CraftPanelHideUncraftableVariants;

		public static readonly ConfigEntry<float> CraftPanelUncraftableBrightness;

		public static readonly ConfigEntry<string> CraftPanelUncraftableSymbol;

		public static readonly ConfigEntry<Color> CraftPanelUncraftableSymbolColor;

		public static readonly ConfigEntry<UncraftableSymbolPosition> CraftPanelUncraftableSymbolPosition;

		public static readonly ConfigEntry<Vector2> CraftPanelInfoPosition;

		private static readonly ZColor VanillaSelectGridActivatedColorBlue;

		private static readonly ZColor VanillaSelectMenuActivatedColorOrange;

		public static readonly ConfigEntry<Color> ItemActivatedColor;

		public static readonly ConfigEntry<Color> ItemActivatedHotbarColor;

		public static readonly ConfigEntry<bool> EnableTakeStacks;

		public static readonly ConfigEntry<bool> RemoveItemFromSmallestStack;

		public static readonly ConfigEntry<bool> CombineExistingStacks;

		public static readonly ConfigEntry<bool> ExcludeHotbarWhenStacking;

		public static readonly ConfigEntry<InventoryRules.DropStyle> DiscardStyle;

		public static readonly ConfigEntry<bool> AssignedGearSlots;

		public static readonly ConfigEntry<Color> ItemStackColorFull;

		public static readonly ConfigEntry<Color> ItemStackColorPartial;

		public static readonly ConfigEntry<Color> DurabilityGood;

		public static readonly ConfigEntry<Color> DurabilityWorn;

		public static readonly ConfigEntry<Color> DurabilityAtRisk;

		public static readonly ConfigEntry<Color> DurabilityBroken;

		public static readonly ConfigEntry<bool> ShowQualityAsSymbols;

		public static readonly ConfigEntry<bool> Rotate90Degrees;

		public static readonly ConfigEntry<Color> ItemQualitySymbolColor;

		public static readonly ConfigEntry<string> ExtraQualityLevelSym;

		static Configs()
		{
			//IL_0014: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_0100: Expected O, but got Unknown
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: 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_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: 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_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_055c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			VanillaSelectGridActivatedColorBlue = ZColor.op_Implicit(new Color(0.376f, 0.66f, 0.897f, 0.761f));
			VanillaSelectMenuActivatedColorOrange = ZColor.op_Implicit(new Color(0.7574f, 0.5042f, 0.1838f, 1f));
			CameraRemoveLensDirt = Config.Define<bool>(true, "Camera", "Remove Lens Dirt", true, "Remove the lens dirt from the camera.\r\n[logout for changes to take effect]");
			CameraLodBias = Config.Define<int>(false, "Camera", "LOD Bias", 10, Config.AcceptRange<int>(0, 10), "Set the LOD Bias for the camera on startup. (Vanilla: 2)\r\nHigher values render objects farther away.  Lower this if you have a slow computer.\r\nSet to 0 to disable this config and use vanilla or other mods to set this value instead.");
			CameraLodBias.SettingChanged += delegate
			{
				CameraRules.SetLodBias(CameraLodBias.Value);
			};
			ShowBiomeNotice = Config.Define<BiomeNoticeType>(true, "General", "Show Biome Notification", BiomeNoticeType.PlayerSpawn | BiomeNoticeType.Teleport | BiomeNoticeType.Discovery, $"Show the biome notification on key events.  (Vanilla: {BiomeNoticeType.Discovery})\r\nPlayer Spawn, After teleport, First discovery\r\nNOTE: Using this with the BiomeObserver mod is probably overkill and could result in double notifications.");
			StringList val = new StringList();
			((List<string>)val).Add("$se_windrun_name");
			((List<string>)val).Add("$item_beltstrength");
			((List<string>)val).Add("$item_demister");
			HideStatusEffects = Config.Define<StringList>(true, "General", "Hide Status Effects", val, "Hide status effect icons from the UI.\r\nSome status effect icons are redundant and noisy and you don't need to see all of them all the time.\r\nDoes not change the internal application of the status effect. It just hides the icon from the UI.\r\nComma separated list of status effect names.  This is usually the translation string name prefixed with $\r\nhttps://valheim-modding.github.io/Jotunn/data/localization/translations/English.html");
			EnableAmmoCount = Config.Define<bool>(true, "General", "Enable Ammo Count", true, "When true an icon and count appears on the hotbar with ammo type and count.\r\n[logout required]");
			AutoOpenSkillsPanel = Config.Define<bool>(false, "General", "Auto Open Skills Panel", false, "Automatically open the skills panel when the inventory is opened. (vanilla: false)\r\n[logout required]");
			EnableSlideAnimation = Config.Define<bool>(false, "General", "Enable Slide Animation", false, "Enable the panel slide animation when opening/closing your inventory. (vanilla: true)\r\nDisabled by default because it draws faster without the sliding animation.\r\nOn slower hardware the slide animation can appear a bit choppy every time you open/close your inventory.\r\nIf you have fast hardware you can turn this on and see if you like it.");
			ColoredFoodBars = Config.Define<bool>(true, "General", "Colored Food Bars", true, "Colored food bars. (vanilla: false)\r\nTint the background of the food you ate based on the main property of the food: Health = red, stamina = yellow, blue = eitr");
			EnableTakeStacks = Config.Define<bool>(false, "Inventory", "Enable Take Stacks", true, "When enabled the Take All button changes behavior to three states instead of one. (Vanilla: false)\r\nThe state changes based on the condition of the inventory:\r\n- Take stacks: Unfilled stacks in the player's inventory are filled (example: refill ammo). (ignores weight).\r\n- Take weight: If there are no stacks that can be filled, the button will take items up to max weight.\r\n- Take all: Press again, items are moved to inventory via vanilla behavior (ignores weight).");
			DiscardStyle = Config.Define<InventoryRules.DropStyle>(false, "Inventory", "Drop Style", InventoryRules.DropStyle.CameraDirection, "When dropping items on the ground throw them towards the camera instead of\r\nthe vanilla method of chucking them in the direction the character is facing");
			RemoveItemFromSmallestStack = Config.Define<bool>(false, "Inventory", "Use From Smallest Stack First", true, "When items are automatically removed from your inventory, such as when fueling a fireplace or crafting,\r\nalways draw from the smallest stacks first");
			CombineExistingStacks = Config.Define<bool>(false, "Inventory", "Stacking Combines Existing Stacks", true, "When stacking items into a container the existing items are combined into as few slots as possible. (Vanilla: false)");
			ExcludeHotbarWhenStacking = Config.Define<bool>(false, "Inventory", "Exclude Hotbar When Stacking", true, "When stacking items into a container any items on the hotbar are skipped. (Vanilla: false)");
			AssignedGearSlots = Config.Define<bool>(true, "Inventory Equip", "Assigned Gear Slots", true, "When gear is equipped it always moves to the same pre-configured slot (Vanilla: false)");
			InventoryEquip.InitConfigs("Inventory Equip");
			ItemActivatedColor = Config.Define<Color>(false, "Item Colors", "Activated Color", ZColor.op_Implicit(VanillaSelectMenuActivatedColorOrange), $"Background color when the item is activated (equipped / selected)\r\nVanilla blue color: {VanillaSelectGridActivatedColorBlue}\r\nVanilla orange color: {VanillaSelectMenuActivatedColorOrange}");
			ItemActivatedHotbarColor = Config.Define<Color>(false, "Item Colors", "Activated Color - Hotbar", new Color(0.35f, 0.35f, 0.35f, 0.55f), $"Background color when the item is activated on the hotbar.\r\nVanilla blue color: {VanillaSelectGridActivatedColorBlue}\r\nVanilla orange color: {VanillaSelectMenuActivatedColorOrange}");
			ItemStackColorFull = Config.Define<Color>(false, "Item Colors", "Item Stack Color - Full", UIColor.ValheimYellow.Color, "The color of the item stack when the item stack is full. (vanilla: white)");
			ItemStackColorPartial = Config.Define<Color>(false, "Item Colors", "Item Stack Color - Partial", Color32.op_Implicit(new Color32((byte)221, (byte)221, (byte)221, byte.MaxValue)), "The color of the item stack when the item stack is incomplete. (vanilla: white)");
			Color green = Color.green;
			green.a = 0.2f;
			DurabilityGood = Config.Define<Color>(false, "Item Colors", "Durability 1 - Good", green, "Durability bar color when durability is good");
			green = Color.yellow;
			green.a = 0.5f;
			DurabilityWorn = Config.Define<Color>(false, "Item Colors", "Durability 2 - Worn", green, "Durability bar color when durability is worn");
			green = Color.red;
			green.a = 0.7f;
			DurabilityAtRisk = Config.Define<Color>(false, "Item Colors", "Durability 3 - At Risk", green, "Durability bar color when durability is at risk of breaking");
			DurabilityBroken = Config.Define<Color>(false, "Item Colors", "Durability 4 - Broken", Color.gray, "Durability bar color when item is broken");
			green = UIColor.LightYellow.Color;
			green.a = 0.6f;
			ItemQualitySymbolColor = Config.Define<Color>(false, "Item Colors", "Symbol Color", green, "Color of the item quality symbols");
			ShowQualityAsSymbols = Config.Define<bool>(true, "Item Quality Symbols", "Show Quality As Symbols", true, "Item quality is shown as symbols instead of numbers on the inventory grid.");
			Rotate90Degrees = Config.Define<bool>(true, "Item Quality Symbols", "Rotate Symbols 90 Degrees", false, "The quality symbols are rotated 90 degrees to display them vertically instead of horizontally. This is only used if Show Quality As Symbols is enabled.");
			ExtraQualityLevelSym = Config.Define<string>(true, "Item Quality Symbols", "Extra Level Symbols", "★", "The sequence of symbols used to display the quality level. The first symbol is always the dots and can not be changed.\r\nEach symbol adds 4 levels. Preconfigured with 1 symobl so 8 levels supported: Vanilla 4 + 1 symbol x 4 more levels.\r\nSo if you wanted to add 8 more levels for a total of 12 levels (4 + 8), you would add 2 more symbols to the end of the sequence.\r\nHere are some extra symbols you can try.  Not all unicode works, These are known to work: ★✽◈⚡▲\r\nExample: ★▲ would be 4 vanilla levels + 4 more levels for ★ + 4 more levels for ▲\r\nNOTE: If your item level exceeds this value it will be displayed as a number instead of a symbol.");
			CraftPanelEnabled = Config.Define<bool>(false, "Crafting Panel", "Enable Panel", true, "Replace the vanilla crafting panel with a visual icon style with sorting and grouping. (vanilla: false)\r\n[logout required for changes to take effect]");
			CraftPanelTooltipHover = Config.Define<bool>(false, "Crafting Panel", "Tooltip - Show Hover Item", true, "When using a mouse enable tooltips when hovering over an item in the crafting panel grid.");
			CraftPanelTooltipReq = Config.Define<bool>(false, "Crafting Panel", "Tooltip - Show Requirements", true, "Enable full tooltips on the item requirements. (vanilla: false)\r\n[logout required for changes to take effect]");
			CraftPanelSortCraftable = Config.Define<bool>(false, "Crafting Panel", "Sort Craftable Together", true, "Show all craftable items together sorted to the top of the list.\r\n[close/open your UI for changes to take effect]");
			CraftPanelHideUncraftableVariants = Config.Define<bool>(false, "Crafting Panel", "Hide Uncraftable Variants", true, "Enabled: Variants will only be shown when the item can be crafted. This reduces clutter by hiding variants for items that can not be crafted.\r\nDisabled: Variants will always be shown, even if the item can not be crafted.");
			CraftPanelShowAnyKnownStation = Config.Define<bool>(true, "Crafting Panel", "Show Any Known Station", true, "When not at a crafting station show all known items from any known station.\r\nThis lets you easily recall the recipe of an item which aids in locating the resources.\r\nIf you have ZenSign installed then you can middle-click the recipe ingredient and find the\r\nresources in nearby containers.\r\nNOTE: You can not craft the item without being at the correct station.\r\nThe required station is displayed at the top of the panel.");
			CraftPanelInfoPosition = Config.Define<Vector2>(false, "Crafting Panel", "Adjust Info Position", Vector2.zero, "Item info position offset. Positive X is right, positive Y is up.\r\nUse this to compensate for mods that add extra long tooltip information.");
			CraftPanelUncraftableBrightness = Config.Define<float>(false, "Crafting Panel", "Uncraftable Brightness", 0f, Config.AcceptRange<float>(0f, 1f), "Uncraftable items are displayed with this level of brightness.\r\nWhen set to 0 then black & white is used instead of the item color.");
			CraftPanelUncraftableSymbol = Config.Define<string>(false, "Crafting Panel", "Uncraftable Symbol", "X", "Display this symbol over items that can not be crafted\r\nSome people have different visual distinction prefernces.");
			CraftPanelUncraftableSymbolColor = Config.Define<Color>(false, "Crafting Panel", "Uncraftable Symbol Color", new Color(0.667f, 0.2f, 0f, 0.8f), "The color of the symbol over uncraftable items.");
			CraftPanelUncraftableSymbolPosition = Config.Define<UncraftableSymbolPosition>(false, "Crafting Panel", "Uncraftable Symbol Position", UncraftableSymbolPosition.None, "Position of the uncraftable symbol.");
			CraftPanelSearch = Config.Define<bool>(false, "Crafting Panel - Search", "Enable", true, "Enable the crafting panel search filter text box, does not function without panel enabled.");
			CraftPanelSearchPosition = Config.Define<Vector2>(false, "Crafting Panel - Search", "Adjust Position", Vector2.zero, "Adjust the search filter's text box position. Positive X is right, positive Y is up.");
			CraftPanelSearchResources = Config.Define<bool>(false, "Crafting Panel - Search", "Search Resource Requirements", true, "When searching the crafting panel, also search the recipe's resource requirements for matching items.");
			CraftPanelSearchArmorSets = Config.Define<bool>(false, "Crafting Panel - Search", "Search Armor Sets", true, "When searching the crafting panel, also search the gear set names for matching items.");
			CraftingPanel.InitExplicitGroupConfigs();
		}
	}
	[BepInPlugin("ZenDragon.ZenUI", "ZenUI", "0.9.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : ZenMod<Plugin>
	{
		public const string PluginName = "ZenUI";

		public const string PluginVersion = "0.9.2";

		public const string PluginGUID = "ZenDragon.ZenUI";

		protected override void Setup()
		{
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

		protected override void WorldStart()
		{
			if (Configs.CameraRemoveLensDirt.Value)
			{
				CameraRules.RemoveDirt();
			}
			CameraRules.SetLodBias(Configs.CameraLodBias.Value);
		}

		protected override void HotRestore()
		{
			CraftingPanel.Game_Start();
			CraftingPanelSearch.Game_Start();
			FoodPanel.Game_Start();
		}

		protected override void Shutdown()
		{
			CraftingPanel.Shutdown();
			CraftingPanelSearch.Shutdown();
		}
	}
}
namespace ZenUI.Section
{
	[HarmonyPatch]
	internal static class AmmoCountIcon
	{
		private class ElementExtraData
		{
			[CompilerGenerated]
			private TMP_Text <text>P;

			[CompilerGenerated]
			private Image <icon>P;

			[CompilerGenerated]
			private Image <bait>P;

			public ItemData? Item;

			public ElementExtraData(TMP_Text text, Image icon, Image bait)
			{
				<text>P = text;
				<icon>P = icon;
				<bait>P = bait;
				base..ctor();
			}

			public void UpdateState(ElementData elementData)
			{
				if (Item == null)
				{
					((Component)<text>P).gameObject.SetActive(false);
					((Component)<icon>P).gameObject.SetActive(false);
					((Component)<bait>P).gameObject.SetActive(false);
					return;
				}
				ItemData currentAmmo = GetCurrentAmmo();
				int num = ((currentAmmo != null) ? ((Humanoid)Player.m_localPlayer).GetInventory().CountItems(currentAmmo.m_shared.m_name, -1, true) : 0);
				((Component)<text>P).gameObject.SetActive(Configs.EnableAmmoCount.Value && num > 0);
				if (num > 0)
				{
					<text>P.SetText(num.ToString());
				}
				Sprite val = ((currentAmmo != null) ? currentAmmo.GetIcon() : null);
				((Component)<icon>P).gameObject.SetActive(Configs.EnableAmmoCount.Value && Object.op_Implicit((Object)(object)val));
				if (Object.op_Implicit((Object)(object)val))
				{
					<icon>P.overrideSprite = val;
				}
				ItemData currentBait = GetCurrentBait();
				Sprite val2 = ((currentBait != null) ? currentBait.GetIcon() : null);
				((Component)<bait>P).gameObject.SetActive(Object.op_Implicit((Object)(object)val2));
				if (Object.op_Implicit((Object)(object)val2))
				{
					<bait>P.overrideSprite = val2;
				}
				int num2 = ((currentBait != null) ? ((Humanoid)Player.m_localPlayer).GetInventory().CountItems(currentBait.m_shared.m_name, -1, true) : 0);
				if (num2 > 0 && !((Component)elementData.m_amount).gameObject.activeSelf)
				{
					((Component)elementData.m_amount).gameObject.SetActive(true);
					elementData.m_amount.SetText(num2.ToString());
				}
			}

			private ItemData? GetCurrentAmmo()
			{
				if (Item == null || Utility.IsNullOrWhiteSpace(Item.m_shared.m_ammoType) || IsBaitAmmo() || IsAmmo())
				{
					return null;
				}
				ItemData ammoItem = ((Humanoid)Player.m_localPlayer).GetAmmoItem();
				if (ammoItem == null || ammoItem.m_shared.m_ammoType != Item.m_shared.m_ammoType || !((Humanoid)Player.m_localPlayer).GetInventory().ContainsItem(ammoItem))
				{
					ammoItem = ((Humanoid)Player.m_localPlayer).GetInventory().GetAmmoItem(Item.m_shared.m_ammoType, (string)null);
				}
				return ammoItem;
			}

			private ItemData? GetCurrentBait()
			{
				if (Item == null || Utility.IsNullOrWhiteSpace(Item.m_shared.m_ammoType) || !IsBaitAmmo() || IsAmmo())
				{
					return null;
				}
				ItemData ammoItem = ((Humanoid)Player.m_localPlayer).GetAmmoItem();
				if (ammoItem == null || ammoItem.m_shared.m_ammoType != Item.m_shared.m_ammoType || !((Humanoid)Player.m_localPlayer).GetInventory().ContainsItem(ammoItem))
				{
					ammoItem = ((Humanoid)Player.m_localPlayer).GetInventory().GetAmmoItem(Item.m_shared.m_ammoType, (string)null);
				}
				return ammoItem;
			}

			private bool IsAmmo()
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//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)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Invalid comparison between Unknown and I4
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Invalid comparison between Unknown and I4
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Invalid comparison between Unknown and I4
				ItemType? val = Item?.m_shared.m_itemType;
				if (val.HasValue)
				{
					ItemType valueOrDefault = val.GetValueOrDefault();
					if ((int)valueOrDefault == 2 || (int)valueOrDefault == 9 || (int)valueOrDefault == 23)
					{
						return true;
					}
				}
				return false;
			}

			private bool IsBaitAmmo()
			{
				return Item?.m_shared.m_ammoType == "$item_fishingbait";
			}
		}

		private static readonly Vector2 AmmoCountPosition = new Vector2(0f, 86f);

		private const int AmmoCountFontSize = 14;

		private const HorizontalAlignmentOptions AmmoCountAlignment = 2;

		private static readonly Vector2 AmmoIconPosition = new Vector2(0f, 40f);

		private static readonly Vector2 AmmoIconSize = new Vector2(-10f, -10f);

		private const string ObjectAmmoName = "ZenUI_AmmoAmount";

		private const string ObjectIconName = "ZenUI_AmmoIcon";

		private const string ObjectBaitName = "ZenUI_AmmoBait";

		private static readonly Dictionary<HotkeyBar, bool> IsDirty = new Dictionary<HotkeyBar, bool>();

		private static readonly Dictionary<HotkeyBar, Dictionary<ElementData, ElementExtraData>> ElementExtraDatas = new Dictionary<HotkeyBar, Dictionary<ElementData, ElementExtraData>>();

		private static void UpdateVisibility(GameObject ammoCount, GameObject ammoIcon, GameObject ammoBait)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0057: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			((RectTransform)ammoCount.transform).anchoredPosition = AmmoCountPosition;
			TMP_Text component = ammoCount.GetComponent<TMP_Text>();
			component.fontSize = 14f;
			component.horizontalAlignment = (HorizontalAlignmentOptions)2;
			RectTransform val = (RectTransform)ammoIcon.transform;
			val.anchoredPosition = AmmoIconPosition;
			val.sizeDelta = AmmoIconSize;
			RectTransform val2 = (RectTransform)ammoBait.transform;
			val2.anchorMin = new Vector2(0.5f, 0f);
			val2.anchorMax = new Vector2(1f, 0.5f);
			foreach (HotkeyBar key in IsDirty.Keys)
			{
				IsDirty[key] = true;
			}
		}

		private static void AddCustomElementsToHotkeyPrefab(HotkeyBar bar)
		{
			if (Configs.EnableAmmoCount.Value)
			{
				Logging<Plugin>.Info((object)"Adding Custom Elements", 0);
				GameObject elementPrefab = bar.m_elementPrefab;
				if (!Object.op_Implicit((Object)(object)elementPrefab))
				{
					throw new NullReferenceException("HotkeyBar.m_elementPrefab is null, this should never happen");
				}
				int num = elementPrefab.transform.Find("icon").GetSiblingIndex() + 1;
				Transform obj = elementPrefab.transform.Find("ZenUI_AmmoAmount");
				GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
				if ((Object)(object)val == (Object)null)
				{
					GameObject gameObject = ((Component)elementPrefab.transform.Find("amount")).gameObject;
					val = Object.Instantiate<GameObject>(gameObject);
					((Object)val).name = "ZenUI_AmmoAmount";
					val.transform.SetSiblingIndex(num);
					val.SetActive(false);
					val.transform.SetParent(elementPrefab.transform);
					num++;
					FillFields(gameObject.transform, val.transform);
				}
				Transform obj2 = elementPrefab.transform.Find("ZenUI_AmmoIcon");
				GameObject val2 = ((obj2 != null) ? ((Component)obj2).gameObject : null);
				if ((Object)(object)val2 == (Object)null)
				{
					GameObject gameObject2 = ((Component)elementPrefab.transform.Find("icon")).gameObject;
					val2 = Object.Instantiate<GameObject>(gameObject2);
					((Object)val2).name = "ZenUI_AmmoIcon";
					val2.transform.SetSiblingIndex(num);
					val2.SetActive(false);
					val2.transform.SetParent(elementPrefab.transform);
					num++;
					FillFields(gameObject2.transform, val2.transform);
				}
				Transform obj3 = elementPrefab.transform.Find("ZenUI_AmmoBait");
				GameObject val3 = ((obj3 != null) ? ((Component)obj3).gameObject : null);
				if ((Object)(object)val3 == (Object)null)
				{
					GameObject gameObject3 = ((Component)elementPrefab.transform.Find("icon")).gameObject;
					val3 = Object.Instantiate<GameObject>(gameObject3);
					((Object)val3).name = "ZenUI_AmmoBait";
					val3.transform.SetSiblingIndex(num);
					val3.SetActive(false);
					val3.transform.SetParent(elementPrefab.transform);
					FillFields(gameObject3.transform, val3.transform);
				}
				UpdateVisibility(val, val2, val3);
				Logging<Plugin>.Info((object)"Added custom elements to hotkey bar", 0);
			}
		}

		private static void FillFields(Transform source, Transform dest)
		{
			//IL_0001: 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_0011: Expected O, but got Unknown
			//IL_0011: Expected O, but got Unknown
			FillFields((RectTransform)source, (RectTransform)dest);
		}

		private static void FillFields(RectTransform rtSource, RectTransform rtDestination)
		{
			//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)
			rtDestination.anchoredPosition = rtSource.anchoredPosition;
			rtDestination.sizeDelta = rtSource.sizeDelta;
		}

		private static void UpdateDirtyState(HotkeyBar hotkeyBar)
		{
			if (GeneralExtensions.GetValueSafe<HotkeyBar, bool>(IsDirty, hotkeyBar))
			{
				Logging<Plugin>.Info((object)"HotkeyBar is dirty", 0);
				IsDirty[hotkeyBar] = false;
				if (hotkeyBar.m_elements.Count > 0)
				{
					hotkeyBar.UpdateIcons((Player)null);
				}
			}
		}

		private static void UpdateAmmoAndIcon(HotkeyBar hotkeyBar, Player player)
		{
			if (!ElementExtraDatas.ContainsKey(hotkeyBar))
			{
				ElementExtraDatas.Add(hotkeyBar, new Dictionary<ElementData, ElementExtraData>());
			}
			Dictionary<ElementData, ElementExtraData> dictionary = ElementExtraDatas[hotkeyBar];
			if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead())
			{
				dictionary.Clear();
				return;
			}
			if (dictionary.Count != hotkeyBar.m_elements.Count)
			{
				dictionary.Clear();
			}
			if (dictionary.Count > 0 && hotkeyBar.m_elements.Count > 0 && !dictionary.ContainsKey(hotkeyBar.m_elements[0]))
			{
				dictionary.Clear();
			}
			if (dictionary.Count == 0)
			{
				foreach (ElementData element in hotkeyBar.m_elements)
				{
					Logging<Plugin>.Info((object)"Get element data from Hotbar objects", 0);
					ElementExtraData value = new ElementExtraData(((Component)element.m_go.transform.Find("ZenUI_AmmoAmount")).GetComponent<TMP_Text>(), ((Component)element.m_go.transform.Find("ZenUI_AmmoIcon")).GetComponent<Image>(), ((Component)element.m_go.transform.Find("ZenUI_AmmoBait")).GetComponent<Image>());
					dictionary.Add(element, value);
				}
			}
			int num = 0;
			foreach (ElementData element2 in hotkeyBar.m_elements)
			{
				ElementExtraData elementExtraData = dictionary[element2];
				if (elementExtraData == null)
				{
					continue;
				}
				if (!element2.m_used || num > hotkeyBar.m_items.Count)
				{
					elementExtraData.Item = null;
				}
				else
				{
					elementExtraData.Item = hotkeyBar.m_items[num];
					if ((Object)(object)elementExtraData.Item.GetIcon() != (Object)(object)element2.m_icon.sprite)
					{
						elementExtraData.Item = null;
					}
					num++;
				}
				elementExtraData.UpdateState(element2);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HotkeyBar), "OnEnable")]
		private static void HotkeyBar_OnEnable(HotkeyBar __instance)
		{
			if (Configs.EnableAmmoCount.Value)
			{
				AddCustomElementsToHotkeyPrefab(__instance);
			}
		}

		[HarmonyPriority(0)]
		[HarmonyBefore(new string[] { "Azumatt.AzuExtendedPlayerInventory" })]
		[HarmonyPrefix]
		[HarmonyPatch(typeof(HotkeyBar), "Update")]
		private static void HotkeyBar_Update(HotkeyBar __instance)
		{
			if (Configs.EnableAmmoCount.Value)
			{
				UpdateDirtyState(__instance);
			}
		}

		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "Azumatt.AzuExtendedPlayerInventory" })]
		[HarmonyPostfix]
		[HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")]
		private static void HotkeyBar_UpdateIcons(HotkeyBar __instance, Player player)
		{
			if (Configs.EnableAmmoCount.Value)
			{
				UpdateAmmoAndIcon(__instance, player);
			}
		}
	}
	[HarmonyPatch]
	internal static class BiomeNotice
	{
		private const float BiomeMessageDelay = 3.5f;

		private const float BiomeMessageCooldown = 0f;

		private static float _lastBiomeMessageTime;

		private static void ShowBiomeMessage(Biome prevBiome = 0)
		{
			//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)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			Timing.Delay((MonoBehaviour)(object)Player.m_localPlayer, 3.5f, (Action)delegate
			{
				//IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				Biome biome = EnvMan.instance.GetBiome();
				if (biome == prevBiome)
				{
					Logging<Plugin>.Info((object)$"Biome unchanged, skipping {biome}", 0);
				}
				else if (MessageHud.instance.m_biomeFoundQueue.Count > 0)
				{
					Logging<Plugin>.Info((object)$"Biome message already queued, skipping {biome}", 0);
				}
				else if (Time.time < _lastBiomeMessageTime + 0f)
				{
					Logging<Plugin>.Info((object)$"Biome message recently displayed, cooldown: {0f} skipping {biome}", 0);
				}
				else
				{
					Logging<Plugin>.Info((object)$"Show biome messsage: {biome}", 0);
					MessageHud.instance.ShowBiomeFoundMsg("$biome_" + ((object)(Biome)(ref biome)).ToString().ToLower(), true);
				}
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Game), "SpawnPlayer")]
		private static void Game_SpawnPlayer(Game __instance, bool spawnValkyrie)
		{
			if (!spawnValkyrie && Configs.ShowBiomeNotice.Value.HasFlag(BiomeNoticeType.PlayerSpawn))
			{
				ShowBiomeMessage((Biome)0);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "TeleportTo")]
		private static void Player_TeleportTo(Player __instance, bool distantTeleport, bool __result)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Player __instance2 = __instance;
			if (Configs.ShowBiomeNotice.Value.HasFlag(BiomeNoticeType.Teleport) && distantTeleport && __result)
			{
				Biome prevBiome = EnvMan.instance.GetBiome();
				Timing.When((MonoBehaviour)(object)__instance2, (Func<bool>)(() => !((Character)__instance2).IsTeleporting()), (Action)delegate
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					ShowBiomeMessage(prevBiome);
				});
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MessageHud), "ShowBiomeFoundMsg")]
		private static void MessageHud_ShowBiomeFoundMsg(ref bool __runOriginal)
		{
			if (Configs.ShowBiomeNotice.Value.HasFlag(BiomeNoticeType.Teleport))
			{
				_lastBiomeMessageTime = Time.time;
				if (Player.m_localPlayer.ShowTeleportAnimation())
				{
					__runOriginal = false;
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player), "AddKnownBiome")]
		private static IEnumerable<CodeInstruction> Player_AddKnownBiome_Transpiler(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(MessageHud), "ShowBiomeFoundMsg", (Type[])null, (Type[])null);
			Action<MessageHud, string, bool> action = AddKnownBiome_ShowBiomeFoundMsg_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method);
		}

		private static void AddKnownBiome_ShowBiomeFoundMsg_Intercept(MessageHud self, string text, bool playStinger)
		{
			if (Configs.ShowBiomeNotice.Value.HasFlag(BiomeNoticeType.Discovery))
			{
				self.ShowBiomeFoundMsg(text, playStinger);
			}
		}
	}
	[HarmonyPatch]
	internal static class CraftingPanel
	{
		private enum CraftGroup
		{
			Everything,
			Weapons,
			Ammo,
			Armor,
			Shields,
			Magic,
			Tools,
			Equipment,
			Resources,
			Food,
			Trophy,
			Misc
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		private static class InventoryGuiUpdateRecipeList
		{
			[HarmonyPrefix]
			[HarmonyPriority(700)]
			private static void PrefixEarly(InventoryGui __instance)
			{
				if (Configs.CraftPanelEnabled.Value && !__instance.InCraftTab() && _isLeftPanelDirty)
				{
					ClearLeftPanel();
				}
			}

			[HarmonyPrefix]
			[HarmonyPriority(0)]
			private static void PrefixLate(InventoryGui __instance, List<Recipe> recipes, ref bool __runOriginal)
			{
				if (!Configs.CraftPanelEnabled.Value || !__instance.InCraftTab())
				{
					return;
				}
				if (_isLeftPanelDirty)
				{
					ClearLeftPanel();
				}
				__runOriginal = false;
				if (IsObjectDBRecipesChanged)
				{
					AssignRecipesToCraftGroups();
				}
				bool globalKey = ZoneSystem.instance.GetGlobalKey((GlobalKeys)20);
				ActiveGroups.Clear();
				__instance.m_availableRecipes.Clear();
				foreach (Recipe recipe in recipes)
				{
					bool flag = globalKey || Player.m_localPlayer.HaveRequirements(recipe, false, 1, 1);
					InventoryGui.instance.AddRecipeToList(Player.m_localPlayer, recipe, (ItemData)null, flag);
					ActiveGroups.UnionWith(RecipeToGroups[recipe]);
				}
				if (ActiveGroups.Count == 2)
				{
					ActiveGroups.Remove(CraftGroup.Everything);
				}
			}

			[UsedImplicitly]
			private static void Postfix(InventoryGui __instance)
			{
				if (Configs.CraftPanelEnabled.Value && __instance.InCraftTab())
				{
					UpdateRecipeList();
				}
			}
		}

		private static readonly Stopwatch Stopwatch = new Stopwatch();

		private const int DefaultWidth = 5;

		private const int DefaultHeight = 7;

		private static CraftingPanelGrid _craftingGrid = null;

		private static RectTransform _leftPanel = null;

		private static RectTransform _rightPanel = null;

		private static CraftingStation? _currentStation;

		private static CraftGroup? _currentGroup;

		private static bool _isGroupChanged;

		private static bool _isLeftPanelDirty;

		private static GameObject? _itemInfoTooltipKBM;

		private static ItemData? _selectedItem;

		private static Vector2 _craftTypeTextOrigPos;

		private const float CraftTypeTextVanillaOffsetY = 20f;

		private const float CraftTypeTextOffsetY = -150f;

		private static int _lastObjectDBRecipesCount;

		private static readonly Dictionary<(Recipe Recipe, int Variant), ItemData> RecipeItemCloneCache = new Dictionary<(Recipe, int), ItemData>();

		private static readonly Dictionary<CraftGroup, float> ScrollPositions = new Dictionary<CraftGroup, float>();

		private static readonly Dictionary<Recipe, HashSet<CraftGroup>> RecipeToGroups = new Dictionary<Recipe, HashSet<CraftGroup>>();

		private static readonly Dictionary<ItemData, RecipeDataPair> ItemRecipeData = new Dictionary<ItemData, RecipeDataPair>();

		private static readonly SortedSet<CraftGroup> ActiveGroups = new SortedSet<CraftGroup>();

		private static readonly SortedDictionary<CraftGroup, (string IconPrefabName, HashSet<ItemType> Types)> CraftGroups = new SortedDictionary<CraftGroup, (string, HashSet<ItemType>)>
		{
			{
				CraftGroup.Everything,
				("Wisp", Enum.GetValues(typeof(ItemType)).Cast<ItemType>().ToHashSet())
			},
			{
				CraftGroup.Weapons,
				("Battleaxe", new HashSet<ItemType>
				{
					(ItemType)3,
					(ItemType)14,
					(ItemType)4,
					(ItemType)22,
					(ItemType)20
				})
			},
			{
				CraftGroup.Ammo,
				("ArrowIron", new HashSet<ItemType>
				{
					(ItemType)9,
					(ItemType)23
				})
			},
			{
				CraftGroup.Armor,
				("HelmetCarapace", new HashSet<ItemType>
				{
					(ItemType)6,
					(ItemType)7,
					(ItemType)11,
					(ItemType)17
				})
			},
			{
				CraftGroup.Shields,
				("ShieldIronBuckler", new HashSet<ItemType> { (ItemType)5 })
			},
			{
				CraftGroup.Magic,
				("StaffFireball", new HashSet<ItemType> { (ItemType)24 })
			},
			{
				CraftGroup.Tools,
				("PickaxeIron", new HashSet<ItemType>
				{
					(ItemType)19,
					(ItemType)15,
					(ItemType)18,
					(ItemType)16
				})
			},
			{
				CraftGroup.Equipment,
				("chest_hildir1", new HashSet<ItemType> { (ItemType)10 })
			},
			{
				CraftGroup.Resources,
				("piece_chest_barrel", new HashSet<ItemType> { (ItemType)1 })
			},
			{
				CraftGroup.Food,
				("CookedMeat", new HashSet<ItemType>
				{
					(ItemType)2,
					(ItemType)21
				})
			},
			{
				CraftGroup.Trophy,
				("TrophyDeer", new HashSet<ItemType> { (ItemType)13 })
			},
			{
				CraftGroup.Misc,
				("BoneFragments", new HashSet<ItemType> { (ItemType)0 })
			}
		};

		private static readonly Dictionary<CraftGroup, HashSet<string>> ExplicitGroupAssignment = new Dictionary<CraftGroup, HashSet<string>>
		{
			{
				CraftGroup.Ammo,
				new HashSet<string> { "Catapult_ammo", "BombSiege" }
			},
			{
				CraftGroup.Tools,
				new HashSet<string> { "Pickaxe*", "Scythe", "FishingRod", "Tankard*", "KnifeButcher" }
			},
			{
				CraftGroup.Resources,
				new HashSet<string> { "FishingBait*" }
			},
			{
				CraftGroup.Magic,
				new HashSet<string> { "Staff*" }
			},
			{
				CraftGroup.Food,
				new HashSet<string> { "Feast*" }
			}
		};

		private static readonly HashSet<string> AllExplicitAssignmentPatterns = new HashSet<string>();

		private static readonly HashSet<ItemType> AllKnownTypes = CraftGroups.Where<KeyValuePair<CraftGroup, (string, HashSet<ItemType>)>>((KeyValuePair<CraftGroup, (string IconPrefabName, HashSet<ItemType> Types)> kvp) => kvp.Key != CraftGroup.Everything).SelectMany<KeyValuePair<CraftGroup, (string, HashSet<ItemType>)>, ItemType>((KeyValuePair<CraftGroup, (string IconPrefabName, HashSet<ItemType> Types)> kvp) => kvp.Value.Types).ToHashSet();

		private static bool IsObjectDBRecipesChanged => _lastObjectDBRecipesCount != ObjectDB.instance.m_recipes.Count;

		private static bool IsStationChanged
		{
			get
			{
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					return (Object)(object)_currentStation != (Object)(object)Player.m_localPlayer.GetCurrentCraftingStation();
				}
				return false;
			}
		}

		private static IEnumerable<RecipeDataPair> ActiveRecipes
		{
			get
			{
				if (_currentGroup.HasValue)
				{
					return InventoryGui.instance.m_availableRecipes.Where(InCurrentGroup).Where(CraftingPanelSearch.ApplySearchFilter).SortCraftRecipes();
				}
				return Array.Empty<RecipeDataPair>();
			}
		}

		private static bool IsNoCraftCost
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZoneSystem.instance) || !ZoneSystem.instance.GetGlobalKey((GlobalKeys)20))
				{
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
					{
						return Player.m_localPlayer.NoCostCheat();
					}
					return false;
				}
				return true;
			}
		}

		internal static bool CanCraft(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			RecipeDataPair val = ItemRecipeData[item];
			if (!((RecipeDataPair)(ref val)).CanCraft)
			{
				return IsNoCraftCost;
			}
			return true;
		}

		private static bool InCurrentGroup(ItemData? item)
		{
			if (item != null)
			{
				return ItemRecipeData.ContainsKey(item);
			}
			return false;
		}

		private static bool InCurrentGroup(RecipeDataPair r)
		{
			if (_currentGroup.HasValue)
			{
				return RecipeToGroups[((RecipeDataPair)(ref r)).Recipe].Contains(_currentGroup.Value);
			}
			return false;
		}

		private static bool IsInGroups(this RecipeDataPair recipeData, params CraftGroup[] groups)
		{
			return ((RecipeDataPair)(ref recipeData)).Recipe.IsInGroups(groups);
		}

		private static bool IsInGroups(this Recipe recipe, params CraftGroup[] groups)
		{
			return groups.Any(RecipeToGroups[recipe].Contains);
		}

		internal static void InitExplicitGroupConfigs()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			foreach (CraftGroup group2 in Enum.GetValues(typeof(CraftGroup)))
			{
				if (group2 != 0)
				{
					if (!ExplicitGroupAssignment.TryGetValue(group2, out HashSet<string> value))
					{
						value = new HashSet<string>();
						ExplicitGroupAssignment.Add(group2, value);
					}
					ConfigEntry<StringList> config = Config.Define<StringList>(true, "Crafting Group Assignment", group2.ToString(), new StringList((IEnumerable<string>)value), "Comma separated list of item prefab names explicitly assigned to this group.\r\nUse this to override the default groupings which are based on item type.\r\nThe prefix and suffix wildcard * is supported.\r\nExplicltly remove an item from a group with: -prefabName\r\nRemoval wildcards are not supported. Example: -Wood* is not valid.");
					ExplicitGroupAssignment[group2] = ((IEnumerable<string>)config.Value).ToHashSet();
					config.SettingChanged += delegate
					{
						UpdatePatterns(group2, ((IEnumerable<string>)config.Value).ToHashSet());
					};
				}
			}
			UpdateExplicitAssignmentPatterns();
			static void UpdatePatterns(CraftGroup group, HashSet<string> patterns)
			{
				ExplicitGroupAssignment[group] = patterns;
				UpdateExplicitAssignmentPatterns();
			}
		}

		private static void UpdateExplicitAssignmentPatterns()
		{
			AllExplicitAssignmentPatterns.Clear();
			AllExplicitAssignmentPatterns.UnionWith(ExplicitGroupAssignment.SelectMany<KeyValuePair<CraftGroup, HashSet<string>>, string>((KeyValuePair<CraftGroup, HashSet<string>> kv) => kv.Value));
		}

		private static void InitPanel()
		{
			Reset();
			BuildPanel();
		}

		private static void BuildPanel()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_005b: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0093: 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)
			//IL_00bb: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: 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)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: 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_02c9: 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_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			_rightPanel = (RectTransform)((Transform)instance.m_crafting).Find("Decription");
			_leftPanel = (RectTransform)((Transform)instance.m_crafting).Find("RecipeList");
			Logging<Plugin>.Info((object)"Resize the panels", 0);
			Logging<Plugin>.Info((object)"Resize the crafting window", 0);
			RectTransform val = (RectTransform)((Component)instance.m_crafting).transform;
			Vector2 sizeDelta = val.sizeDelta;
			sizeDelta.y = 685f;
			val.sizeDelta = sizeDelta;
			Logging<Plugin>.Info((object)"Resize the right panel", 0);
			RectTransform rightPanel = _rightPanel;
			sizeDelta = _rightPanel.sizeDelta;
			sizeDelta.y = 490f;
			rightPanel.sizeDelta = sizeDelta;
			Logging<Plugin>.Info((object)"Resize the left panel", 0);
			RectTransform leftPanel = _leftPanel;
			sizeDelta = _leftPanel.sizeDelta;
			sizeDelta.y = 490f;
			leftPanel.sizeDelta = sizeDelta;
			Rect rect = instance.m_recipeListRoot.rect;
			instance.m_recipeListBaseSize = ((Rect)(ref rect)).height;
			Logging<Plugin>.Info((object)"Clone the ContainerGrid game object", 0);
			GameObject obj = Object.Instantiate<GameObject>(((Component)instance.ContainerGrid).gameObject, (Transform)(object)_rightPanel);
			((Object)obj).name = "ZenUI_CraftingGrid";
			Logging<Plugin>.Info((object)"Replace the InventoryGrid with a CraftingPanelGrid", 0);
			Object.Destroy((Object)(object)obj.GetComponent<InventoryGrid>());
			_craftingGrid = obj.AddComponent<CraftingPanelGrid>();
			_craftingGrid.Init(5, 7);
			Logging<Plugin>.Info((object)"Setup selected event handlers", 0);
			_craftingGrid.OnSelectedItem += SelectItem;
			Logging<Plugin>.Info((object)"Setup scroll event handlers", 0);
			_craftingGrid.OnScrollChanged += ScrollChanged;
			Logging<Plugin>.Info((object)"Move the crafting button down and to the left", 0);
			RectTransform val2 = (RectTransform)((Component)instance.m_craftButton).transform.parent;
			val2.anchoredPosition = new Vector2(-280f, -50f);
			val2.sizeDelta = new Vector2(-160f, 70f);
			Logging<Plugin>.Info((object)"Resize the progress bar to fit the new button shape", 0);
			RectTransform val3 = (RectTransform)instance.m_craftProgressPanel;
			val3.anchoredPosition = Vector2.zero;
			sizeDelta = val3.offsetMax;
			sizeDelta.x = 0f;
			val3.offsetMax = sizeDelta;
			sizeDelta = val3.offsetMin;
			sizeDelta.x = 0f;
			val3.offsetMin = sizeDelta;
			sizeDelta = val3.sizeDelta;
			sizeDelta.x = 180f;
			val3.sizeDelta = sizeDelta;
			instance.m_craftProgressBar.SetWidth(180f);
			Logging<Plugin>.Info((object)"Move the requirements panel down and align the right margin", 0);
			RectTransform val4 = (RectTransform)((Transform)instance.m_crafting).Find("Decription/requirements");
			((HorizontalOrVerticalLayoutGroup)ExposedGameObjectExtension.GetOrAddComponent<HorizontalLayoutGroup>(((Component)val4).gameObject)).spacing = 0f;
			val4.anchoredPosition = new Vector2(0f, -48f);
			val4.anchorMax = new Vector2(1f, 0f);
			val4.anchorMin = new Vector2(0f, 0f);
			sizeDelta = val4.sizeDelta;
			sizeDelta.x = 0f;
			val4.sizeDelta = sizeDelta;
			foreach (Transform item in (Transform)val4)
			{
				((Behaviour)((Component)item).GetComponent<Image>()).enabled = true;
			}
			Logging<Plugin>.Info((object)"Save the original upgrade notice position", 0);
			_craftTypeTextOrigPos = ((RectTransform)instance.m_itemCraftType.transform).anchoredPosition;
		}

		private static void SetRepairPanelPosition(InventoryGui gui)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			Logging<Plugin>.Info((object)"Move the repair panel to compensate for the resized crafting panel", 0);
			RectTransform val = (RectTransform)((Component)gui.m_repairButton).transform;
			Vector2 anchoredPosition = val.anchoredPosition;
			anchoredPosition.y = 185.5f;
			val.anchoredPosition = anchoredPosition;
		}

		private static bool TryGetCurrentGroup(out CraftGroup group)
		{
			group = _currentGroup.GetValueOrDefault((CraftGroup)(-1));
			return _currentGroup.HasValue;
		}

		private static void ScrollChanged(float value)
		{
			if (TryGetCurrentGroup(out var group))
			{
				ScrollPositions[group] = value;
			}
		}

		internal static void ResetScrollCache()
		{
			Logging<Plugin>.Info((object)"Reset scroll position cached values for all groups", 0);
			foreach (CraftGroup value in Enum.GetValues(typeof(CraftGroup)))
			{
				ScrollPositions[value] = 1f;
			}
		}

		private static void Reset()
		{
			_currentStation = null;
			_currentGroup = null;
			_lastObjectDBRecipesCount = 0;
			_selectedItem = null;
			SelectItem(null);
			ResetScrollCache();
		}

		private static void ForceRefresh()
		{
			Reset();
			InventoryGui.instance.UpdateCraftingPanel(false);
		}

		private static void AssignRecipesToCraftGroups()
		{
			Logging<Plugin>.Message((object)"Assign all recipes to craft groups", 0);
			RecipeToGroups.Clear();
			foreach (Recipe item in ObjectDB.instance.m_recipes.Where((Recipe recipe) => Object.op_Implicit((Object)(object)recipe.m_item)))
			{
				AssignRecipeToCraftGroups(item);
			}
			_lastObjectDBRecipesCount = ObjectDB.instance.m_recipes.Count;
		}

		private static void AssignRecipeToCraftGroups(Recipe recipe)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			Recipe recipe2 = recipe;
			string itemPrefabName = ItemDataExt.GetPrefabName(recipe2.m_item);
			ItemType itemType = ItemDataExt.GetItemType(recipe2.m_item.m_itemData);
			IEnumerable<CraftGroup> enumerable = CraftGroups.Keys.Where((CraftGroup g) => g != CraftGroup.Everything);
			if (!AllKnownTypes.Contains(itemType))
			{
				Logging<Plugin>.Info((object)$"No known type: {itemType} for {itemPrefabName}", 0);
			}
			AddToGroup(CraftGroup.Everything);
			bool flag = false;
			foreach (CraftGroup item in enumerable)
			{
				if (IsRemovedFromGroupExplicitly(item))
				{
					continue;
				}
				if (IsWildcardFound(AllExplicitAssignmentPatterns))
				{
					if (IsAssignedToGroupExplicitly(item))
					{
						AddToGroup(item);
						flag = true;
					}
				}
				else if (CraftGroups[item].Types.Contains(itemType))
				{
					AddToGroup(item);
					flag = true;
				}
			}
			if (!flag)
			{
				AddToGroup(CraftGroup.Misc);
			}
			void AddToGroup(CraftGroup group)
			{
				Logging<Plugin>.Info((object)$"Add recipe: {itemPrefabName} to group: {group}", 0);
				IDictionaryExt.AddToList<Recipe, CraftGroup, HashSet<CraftGroup>>((IDictionary<Recipe, HashSet<CraftGroup>>)RecipeToGroups, recipe2, group);
			}
			bool EndsWith(string pattern)
			{
				if (pattern.EndsWith("*"))
				{
					return itemPrefabName.StartsWith(pattern.Substring(0, pattern.Length - 1));
				}
				return false;
			}
			bool IsAssignedToGroupExplicitly(CraftGroup group)
			{
				int num;
				if (ExplicitGroupAssignment.TryGetValue(group, out HashSet<string> value))
				{
					num = (IsWildcardFound(value) ? 1 : 0);
					if (num != 0)
					{
						Logging<Plugin>.Info((object)$"Explicit item: {itemPrefabName} in group {group}", 0);
					}
				}
				else
				{
					num = 0;
				}
				return (byte)num != 0;
			}
			bool IsRemovedFromGroupExplicitly(CraftGroup group)
			{
				int num2;
				if (ExplicitGroupAssignment.TryGetValue(group, out HashSet<string> value2))
				{
					num2 = (value2.Contains("-" + itemPrefabName) ? 1 : 0);
					if (num2 != 0)
					{
						Logging<Plugin>.Info((object)$"Remove item: {itemPrefabName} from group {group}", 0);
					}
				}
				else
				{
					num2 = 0;
				}
				return (byte)num2 != 0;
			}
			bool IsWildcardFound(HashSet<string> list)
			{
				if (!list.Contains(itemPrefabName))
				{
					return list.Any((string pattern) => StartsWith(pattern) || EndsWith(pattern));
				}
				return true;
			}
			bool StartsWith(string pattern)
			{
				if (pattern.StartsWith("*"))
				{
					return itemPrefabName.EndsWith(pattern.Substring(1));
				}
				return false;
			}
		}

		private static void UpdateGamepad()
		{
			if (ZInput.IsGamepadActive() && ((InventoryGrid)_craftingGrid).m_uiGroup.IsActive && InventoryGui.instance.InCraftTab() && ActiveGroups.Count != 0)
			{
				CraftGroup group = _currentGroup ?? ActiveGroups.First();
				int item = IEnumerableExt.WithIndex<CraftGroup>((IEnumerable<CraftGroup>)ActiveGroups).FirstOrDefault<(CraftGroup, int)>(((CraftGroup Item, int Index) idx) => idx.Item == group).Item2;
				if (ZInput.GetButtonDown("JoyDPadUp"))
				{
					group = ActiveGroups.ElementAt(Mathf.Max(item - 1, 0));
				}
				if (ZInput.GetButtonDown("JoyDPadDown"))
				{
					group = ActiveGroups.ElementAt(Mathf.Min(item + 1, ActiveGroups.Count - 1));
				}
				if (group != _currentGroup)
				{
					SelectGroup(group);
				}
			}
		}

		private static ItemData GetRecipeItemClone(Recipe recipe, int variant)
		{
			if (!RecipeItemCloneCache.TryGetValue((recipe, variant), out ItemData value))
			{
				Logging<Plugin>.Info((object)$"Adding recipe item to cache: {ItemDataExt.GetPrefabName(recipe.m_item)} variant: {variant}", 0);
				value = recipe.m_item.m_itemData.Clone();
				RecipeItemCloneCache.Add((recipe, variant), value);
			}
			value.m_stack = recipe.GetAmount();
			value.m_durability = value.GetMaxDurability();
			value.m_variant = variant;
			return value;
		}

		internal static int GetCraftMultiplier()
		{
			InventoryGui instance = InventoryGui.instance;
			if (instance.m_craftUpgradeItem != null || (!ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyLStick")))
			{
				return 1;
			}
			return instance.m_multiCraftAmount;
		}

		private static int GetAmount(this Recipe recipe)
		{
			int num = default(int);
			ItemData val = default(ItemData);
			return recipe.GetAmount(1, ref num, ref val, 1);
		}

		private static void UpdateGridData()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			Logging<Plugin>.Info((object)"Update grid data", 0);
			Inventory inventory = ((InventoryGrid)_craftingGrid).GetInventory();
			inventory.m_inventory.Clear();
			ItemRecipeData.Clear();
			Stopwatch.Restart();
			int num = 0;
			foreach (RecipeDataPair activeRecipe in ActiveRecipes)
			{
				RecipeDataPair current = activeRecipe;
				Recipe recipe = ((RecipeDataPair)(ref current)).Recipe;
				int num2 = ((Configs.CraftPanelHideUncraftableVariants.Value && !((RecipeDataPair)(ref current)).CanCraft && !IsNoCraftCost) ? 1 : recipe.m_item.m_itemData.m_shared.m_icons.Length);
				for (int i = 0; i < num2; i++)
				{
					ItemData recipeItemClone = GetRecipeItemClone(recipe, i);
					recipeItemClone.m_gridPos = new Vector2i(num % 5, num / 5);
					Logging<Plugin>.Debug((object)$"Item: {ItemDataExt.GetPrefabName(recipeItemClone)} Index: {num} Variant: {i} GridPos: {recipeItemClone.m_gridPos} Icons: {recipeItemClone.m_shared.m_icons.Length}", 0);
					inventory.m_inventory.Add(recipeItemClone);
					ItemRecipeData.Add(recipeItemClone, current);
					num++;
				}
			}
			Stopwatch.Stop();
			Logging<Plugin>.Info((object)$"Time: {Stopwatch.ElapsedMilliseconds}ms, count: {inventory.NrOfItems()}", 0);
			inventory.m_height = Mathf.Max(7, Mathf.CeilToInt((float)inventory.NrOfItems() / 5f));
			Logging<Plugin>.Info((object)$"Inventory size: {inventory.m_width}x{inventory.m_height}", 0);
			inventory.Changed();
		}

		private static void RestoreScrollPosition()
		{
			Logging<Plugin>.Info((object)"Restore scroll position", 0);
			if (TryGetCurrentGroup(out var group))
			{
				_craftingGrid.ScrollRect.verticalNormalizedPosition = ScrollPositions[group];
			}
		}

		public static void Shutdown()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_craftingGrid))
			{
				if (Object.op_Implicit((Object)(object)InventoryGui.instance))
				{
					InventoryGui.instance.m_itemCraftType.rectTransform.anchoredPosition = _craftTypeTextOrigPos;
				}
				ActivateOnCopy.Shutdown();
				Object.Destroy((Object)(object)((Component)_craftingGrid).gameObject);
			}
		}

		private static bool ShowCraftingGrid(bool show)
		{
			Logging<Plugin>.Debug((object)$"Show the crafting grid: {show}", 0);
			((Component)_craftingGrid).gameObject.SetActive(show);
			if (Object.op_Implicit((Object)(object)_itemInfoTooltipKBM))
			{
				_itemInfoTooltipKBM.SetActive(show);
			}
			ShowVanillaUI(!show);
			return show;
		}

		private static void ShowVanillaUI(bool isVanilla)
		{
			Logging<Plugin>.Debug((object)$"Show vanilla crafting panel UI elements: {isVanilla}", 0);
			InventoryGui instance = InventoryGui.instance;
			((Component)instance.m_recipeDecription).gameObject.SetActive(isVanilla);
			((Component)instance.m_recipeIcon).gameObject.SetActive(isVanilla);
			((Component)instance.m_recipeName).gameObject.SetActive(isVanilla);
			((Behaviour)((Component)_rightPanel).GetComponent<Image>()).enabled = isVanilla;
			OtherModUI.Show((Transform)(object)_rightPanel, isVanilla);
		}

		private static void ClearLeftPanel()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Logging<Plugin>.Info((object)"Clear left panel", 0);
			foreach (Transform item in (Transform)InventoryGui.instance.m_recipeListRoot)
			{
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			_isLeftPanelDirty = false;
		}

		private static void UpdateCraftingGroupsUI()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			_isLeftPanelDirty = true;
			UpdateGroupListSizeRect(ActiveGroups.Count);
			ItemDrop val2 = default(ItemDrop);
			Piece val3 = default(Piece);
			foreach (var item2 in IEnumerableExt.WithIndex<CraftGroup>((IEnumerable<CraftGroup>)ActiveGroups))
			{
				CraftGroup group = item2.Item1;
				int item = item2.Item2;
				GameObject val = Object.Instantiate<GameObject>(instance.m_recipeElementPrefab, (Transform)(object)instance.m_recipeListRoot);
				val.SetActive(true);
				((Object)val).name = group.ToString();
				((RectTransform)val.transform).anchoredPosition = new Vector2(0f, (float)item * (0f - instance.m_recipeListSpace));
				((Component)val.transform.Find("name")).GetComponent<TMP_Text>().text = StringExt.Localize($"$CraftGroup_{group}");
				Image component = ((Component)val.transform.Find("icon")).GetComponent<Image>();
				GameObject prefab = ZNetScene.instance.GetPrefab(CraftGroups[group].IconPrefabName);
				if (prefab.TryGetComponent<ItemDrop>(ref val2))
				{
					component.sprite = ItemDataExt.GetIcon(val2);
				}
				else if (prefab.TryGetComponent<Piece>(ref val3))
				{
					component.sprite = val3.m_icon;
				}
				((Component)val.transform.Find("Durability")).gameObject.SetActive(false);
				Transform obj = val.transform.Find("QualityLevel");
				((Component)obj).GetComponent<TMP_Text>().text = "";
				((Component)obj).gameObject.SetActive(false);
				((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					SelectGroup(group);
				});
				((Component)val.transform.Find("selected")).gameObject.SetActive(((Object)val).name == _currentGroup.ToString());
			}
		}

		private static void UpdateGroupListSizeRect(int count)
		{
			InventoryGui instance = InventoryGui.instance;
			instance.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(instance.m_recipeListBaseSize, (float)count * instance.m_recipeListSpace));
		}

		private static IEnumerable<RecipeDataPair> SortCraftRecipes(this IEnumerable<RecipeDataPair> recipes)
		{
			Logging<Plugin>.Info((object)"Sort crafting group recipes", 0);
			return recipes.OrderByDescending(IsCraftable).ThenBy(CraftGroupOrder).ThenBy(SkillTypeOrder)
				.ThenBy(AttackAnimationOrder)
				.ThenBy(ItemTypeOrder)
				.ThenBy(AmmoTypeOrder)
				.ThenBy(DamageOrder)
				.ThenBy(ArmorOrder)
				.ThenBy(ShieldOrder)
				.ThenBy(FoodOrder)
				.ThenBy((RecipeDataPair data) => ((RecipeDataPair)(ref data)).Recipe.m_item.m_itemData.m_shared.m_consumeStatusEffect?.m_category)
				.ThenBy((RecipeDataPair data) => ((RecipeDataPair)(ref data)).Recipe.m_item.m_itemData.m_shared.m_attackStatusEffect?.m_category)
				.ThenBy((RecipeDataPair data) => ((RecipeDataPair)(ref data)).Recipe.m_item.m_itemData.m_shared.m_equipStatusEffect?.m_category)
				.ThenBy(StationOrder)
				.ThenBy(NameOrder)
				.ThenBy(DebugLog);
			static string AmmoTypeOrder(RecipeDataPair recipeData)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				if (!recipeData.IsInGroups(CraftGroup.Ammo))
				{
					return string.Empty;
				}
				return ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.m_shared.m_ammoType;
			}
			static float ArmorOrder(RecipeDataPair recipeData)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				if (!recipeData.IsInGroups(CraftGroup.Armor))
				{
					return 0f;
				}
				return ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.GetArmor();
			}
			static string AttackAnimationOrder(RecipeDataPair recipeData)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Invalid comparison between Unknown and I4
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Invalid comparison between Unknown and I4
				if (!recipeData.IsInGroups(CraftGroup.Weapons, CraftGroup.Magic))
				{
					return string.Empty;
				}
				string attackAnimation2 = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.m_shared.m_attack.m_attackAnimation;
				SkillType skillType2 = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.m_shared.m_skillType;
				string text;
				if ((int)skillType2 != 1)
				{
					if ((int)skillType2 != 2 || attackAnimation2 == "knife_stab" || attackAnimation2 == "dual_knives")
					{
						goto IL_00a7;
					}
					text = "knife_stab";
				}
				else
				{
					if (attackAnimation2 == "swing_longsword" || attackAnimation2 == "greatsword")
					{
						goto IL_00a7;
					}
					text = "swing_longsword";
				}
				goto IL_00a9;
				IL_00a7:
				text = attackAnimation2;
				goto IL_00a9;
				IL_00a9:
				attackAnimation2 = text;
				int num = attackAnimation2 switch
				{
					"knife_stab" => 1, 
					"dual_knives" => 2, 
					"swing_longsword" => 3, 
					"greatsword" => 4, 
					_ => 0, 
				};
				if (num <= 0)
				{
					return attackAnimation2;
				}
				return num.ToString("00");
			}
			static CraftGroup CraftGroupOrder(RecipeDataPair recipeData)
			{
				return RecipeToGroups[((RecipeDataPair)(ref recipeData)).Recipe].First((CraftGroup g) => g != CraftGroup.Everything);
			}
			static (float, float, int) DamageOrder(RecipeDataPair recipeData)
			{
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: 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_001a: Unknown result type (might be due to invalid IL or missing references)
				ItemData itemData4 = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData;
				if (!itemData4.IsWeapon() && !recipeData.IsInGroups(CraftGroup.Ammo))
				{
					return (0f, 0f, 0);
				}
				DamageTypes damages = itemData4.m_shared.m_damages;
				float item3 = ((DamageTypes)(ref damages)).GetTotalPhysicalDamage() + damages.m_chop + damages.m_pickaxe;
				float item4 = ((DamageTypes)(ref damages)).GetTotalElementalDamage() + damages.m_spirit + damages.m_poison;
				int minStationLevel = ((RecipeDataPair)(ref recipeData)).Recipe.m_minStationLevel;
				return (item3, item4, minStationLevel);
			}
			static int DebugLog(RecipeDataPair recipeData)
			{
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				if (!Logging<Plugin>.IsEnabled)
				{
					return 0;
				}
				ItemData itemData = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData;
				string attackAnimation = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.m_shared.m_attack.m_attackAnimation;
				SkillType skillType = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.m_shared.m_skillType;
				Logging<Plugin>.Message((object)$"Sort: {ItemDataExt.GetPrefabName(itemData)} anim: {attackAnimation} skill: {skillType}", 0);
				return 0;
			}
			static (FoodPanel.FoodType, float) FoodOrder(RecipeDataPair recipeData)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				if (!recipeData.IsInGroups(CraftGroup.Food))
				{
					return (FoodPanel.FoodType.Default, 0f);
				}
				ItemData itemData2 = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData;
				FoodPanel.FoodType foodType = itemData2.GetFoodType();
				float item2 = itemData2.m_shared.m_food + itemData2.m_shared.m_foodStamina + itemData2.m_shared.m_foodEitr;
				return (foodType, item2);
			}
			static bool IsCraftable(RecipeDataPair recipeData)
			{
				if (((RecipeDataPair)(ref recipeData)).CanCraft && Configs.CraftPanelSortCraftable.Value)
				{
					return !IsNoCraftCost;
				}
				return false;
			}
			static ItemType ItemTypeOrder(RecipeDataPair recipeData)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				return ItemDataExt.GetItemType(((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData);
			}
			static (string, int) NameOrder(RecipeDataPair recipeData)
			{
				string item = StringExt.Localize(ItemDataExt.GetName(((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData));
				int amount = ((RecipeDataPair)(ref recipeData)).Recipe.m_amount;
				return (item, amount);
			}
			static (bool, float, float, float) ShieldOrder(RecipeDataPair recipeData)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				if (!recipeData.IsInGroups(CraftGroup.Shields, CraftGroup.Weapons, CraftGroup.Magic))
				{
					return (false, 0f, 0f, 0f);
				}
				ItemData itemData3 = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData;
				float deflectionForce = itemData3.GetDeflectionForce();
				float baseBlockPower = itemData3.GetBaseBlockPower();
				float timedBlockBonus = itemData3.m_shared.m_timedBlockBonus;
				return (timedBlockBonus == 0f, 0f - timedBlockBonus, baseBlockPower, deflectionForce);
			}
			static float SkillTypeOrder(RecipeDataPair recipeData)
			{
				//IL_0000: 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_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Invalid comparison between Unknown and I4
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Invalid comparison between Unknown and I4
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Invalid comparison between Unknown and I4
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				if (recipeData.IsInGroups(CraftGroup.Ammo))
				{
					return 0f;
				}
				SkillType skillType3 = ((RecipeDataPair)(ref recipeData)).Recipe.m_item.m_itemData.m_shared.m_skillType;
				if ((int)skillType3 == 2)
				{
					return 0.9f;
				}
				if ((int)skillType3 == 11)
				{
					return 0.5f;
				}
				if ((int)skillType3 == 14)
				{
					return 8.1f;
				}
				return (float)skillType3;
			}
			static string StationOrder(RecipeDataPair recipeData)
			{
				CraftingStation craftingStation = ((RecipeDataPair)(ref recipeData)).Recipe.m_craftingStation;
				return ((craftingStation != null) ? craftingStation.GetHoverName() : null) ?? string.Empty;
			}
		}

		private static void SelectGroup(CraftGroup? group)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			Logging<Plugin>.Info((object)$"Selected group: {group}", 0);
			_isGroupChanged = _currentGroup != group;
			_currentGroup = group;
			UpdateGridData();
			foreach (Transform item in (Transform)InventoryGui.instance.m_recipeListRoot)
			{
				Transform val = item;
				((Component)val.Find("selected")).gameObject.SetActive(((Object)val).name == group.ToString());
			}
		}

		internal static bool IsSelectedItem(ItemData item)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if (!Object.op_Implicit((Object)(object)((RecipeDataPair)(ref instance.m_selectedRecipe)).Recipe))
			{
				return false;
			}
			Recipe recipe = ((RecipeDataPair)(ref instance.m_selectedRecipe)).Recipe;
			RecipeDataPair val = ItemRecipeData[item];
			if ((Object)(object)recipe == (Object)(object)((RecipeDataPair)(ref val)).Recipe)
			{
				return instance.m_selectedVariant == item.m_variant;
			}
			return false;
		}

		internal static void SelectItem(ItemData? item)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (!ZInput.IsGamepadActive() && item != null && IsSame(item))
			{
				item = null;
			}
			Logging<Plugin>.Info((object)("Selected Item: " + (((item != null) ? ItemDataExt.GetPrefabName(item) : null) ?? "(none)")), 0);
			InventoryGui.instance.m_selectedRecipe = (RecipeDataPair)((item == null) ? default(RecipeDataPair) : ItemRecipeData[item]);
			InventoryGui.instance.m_selectedVariant = item?.m_variant ?? 0;
			_selectedItem = item;
			HideSelectedItemInfo_KBM();
			if (!ZInput.IsGamepadActive())
			{
				ShowSelectedItemInfo_KBM(item);
			}
			static bool IsSame(ItemData? itm)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				if (itm == null)
				{
					return false;
				}
				Recipe recipe = ((RecipeDataPair)(ref InventoryGui.instance.m_selectedRecipe)).Recipe;
				int selectedVariant = InventoryGui.instance.m_selectedVariant;
				RecipeDataPair val = ItemRecipeData[itm];
				if ((Object)(object)recipe == (Object)(object)((RecipeDataPair)(ref val)).Recipe)
				{
					return selectedVariant == itm.m_variant;
				}
				return false;
			}
		}

		private static void HideSelectedItemInfo_KBM()
		{
			if (Object.op_Implicit((Object)(object)_itemInfoTooltipKBM))
			{
				Object.Destroy((Object)(object)_itemInfoTooltipKBM);
			}
		}

		private static void ShowSelectedItemInfo_KBM(ItemData? item)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (item != null)
			{
				_itemInfoTooltipKBM = Object.Instantiate<GameObject>(((InventoryGrid)_craftingGrid).m_elements[0].m_tooltip.m_tooltipPrefab, (Transform)(object)((InventoryGrid)_craftingGrid).m_tooltipAnchor);
				_itemInfoTooltipKBM.transform.localPosition = Vector2.op_Implicit(Configs.CraftPanelInfoPosition.Value);
				Transform val = Utils.FindChild(_itemInfoTooltipKBM.transform, "Text", (IterativeSearchType)0);
				if (Object.op_Implicit((Object)(object)val))
				{
					((Component)val).GetComponent<TMP_Text>().text = StringExt.Localize(item.GetTooltip(-1));
				}
				Transform val2 = Utils.FindChild(_itemInfoTooltipKBM.transform, "Topic", (IterativeSearchType)0);
				if (Object.op_Implicit((Object)(object)val2))
				{
					((Component)val2).GetComponent<TMP_Text>().text = StringExt.Localize(ItemDataExt.GetName(item));
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Game), "Start")]
		internal static void Game_Start()
		{
			if (Configs.CraftPanelEnabled.Value)
			{
				InitPanel();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "OnDestroy")]
		private static void InventoryGui_OnDestroy(InventoryGui __instance)
		{
			if (Configs.CraftPanelEnabled.Value)
			{
				Shutdown();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")]
		private static void InventoryGui_AddRecipeToList(InventoryGui __instance, Recipe recipe, ItemData item, bool canCraft, ref bool __runOriginal)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.CraftPanelEnabled.Value && __instance.InCraftTab())
			{
				__runOriginal = false;
				RecipeDataPair item2 = default(RecipeDataPair);
				((RecipeDataPair)(ref item2))..ctor(recipe, item, (GameObject)null, canCraft);
				__instance.m_availableRecipes.Add(item2);
			}
		}

		internal static void UpdateRecipeList()
		{
			Stopwatch.Restart();
			Logging<Plugin>.Info((object)"Update Recipe List", 0);
			ClearLeftPanel();
			SelectDefaultGroup();
			UpdateCraftingGroupsUI();
			Logging<Plugin>.Info((object)$"Time: {Stopwatch.ElapsedMilliseconds}ms", 0);
		}

		private static void SelectDefaultGroup()
		{
			if (ActiveGroups.Count == 0)
			{
				SelectGroup(null);
			}
			else if (IsStationChanged || (!_currentGroup.HasValue && ActiveGroups.Count > 0))
			{
				SelectGroup(ActiveGroups.First());
			}
			else
			{
				SelectGroup(_currentGroup);
			}
		}

		private static bool FocusOn(ItemData? item)
		{
			if (!InCurrentGroup(item))
			{
				return false;
			}
			_craftingGrid.CenterOn(item);
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Update")]
		private static void InventoryGui_Update(InventoryGui __instance)
		{
			if (Configs.CraftPanelEnabled.Value && Object.op_Implicit((Object)(object)_craftingGrid) && InventoryGui.IsVisible() && ShowCraftingGrid(__instance.InCraftTab()))
			{
				UpdateGamepad();
				_craftingGrid.UpdateGui();
				UpdateScrollPosition();
				_isGroupChanged = false;
				_currentStation = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetCurrentCraftingStation() : null);
			}
		}

		private static void UpdateScrollPosition()
		{
			bool isStationChanged = IsStationChanged;
			if ((_isGroupChanged || isStationChanged) && !FocusOn(_selectedItem))
			{
				SelectItem(null);
				if (isStationChanged)
				{
					ResetScrollCache();
				}
				RestoreScrollPosition();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "SetRecipe")]
		private static void InventoryGui_SetRecipe(InventoryGui __instance, ref bool __runOriginal)
		{
			if (Configs.CraftPanelEnabled.Value)
			{
				__runOriginal = !__instance.InCraftTab();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "ToggleNoPlacementCost")]
		private static void Player_ToggleNoPlacementCost(Player __instance)
		{
			if (Configs.CraftPanelEnabled.Value)
			{
				ForceRefresh();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "ResetCharacterKnownItems")]
		private static void Player_ResetCharacterKnownItems(Player __instance)
		{
			if (Configs.CraftPanelEnabled.Value)
			{
				ForceRefresh();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		[HarmonyPriority(800)]
		private static void InventoryGui_Awake(InventoryGui __instance)
		{
			if (Configs.CraftPanelEnabled.Value)
			{
				ActivateOnCopy.Add((MonoBehaviour)(object)__instance.m_recipeDecription);
				ActivateOnCopy.Add((MonoBehaviour)(object)__instance.m_recipeIcon);
				ActivateOnCopy.Add((MonoBehaviour)(object)__instance.m_recipeName);
				ActivateOnCopy.IsSetupComplete = true;
				SetRepairPanelPosition(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")]
		private static void InventoryGrid_CreateItemTooltip(InventoryGrid __instance, ItemData item, UITooltip tooltip, ref bool __runOriginal)
		{
			//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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.CraftPanelEnabled.Value && !((Object)(object)__instance != (Object)(object)_craftingGrid))
			{
				RecipeDataPair val = ItemRecipeData[item];
				if (((RecipeDataPair)(ref val)).Recipe.m_requireOnlyOneIngredient)
				{
					__runOriginal = false;
					string tooltip2 = item.GetTooltip(-1);
					tooltip2 += StringExt.Localize("\n\n<color=orange>$inventory_onlyoneingredient</color>");
					tooltip.Set(item.m_shared.m_name, tooltip2, __instance.m_tooltipAnchor, default(Vector2));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
		private static void InventoryGui_SetupRequirement(Transform elementRoot, Requirement req, bool __result)
		{
			if (Configs.CraftPanelTooltipReq.Value && Object.op_Implicit((Object)(object)InventoryGui.instance) && Object.op_Implicit((Object)(object)req.m_resItem))
			{
				InventoryGrid playerGrid = InventoryGui.instance.m_playerGrid;
				if (playerGrid.m_elements.Count != 0)
				{
					GameObject tooltipPrefab = playerGrid.m_elements[0].m_tooltip.m_tooltipPrefab;
					UITooltip component = ((Component)elementRoot).GetComponent<UITooltip>();
					component.m_tooltipPrefab = tooltipPrefab;
					component.m_topic = ItemDataExt.GetName(req.m_resItem);
					component.m_text = req.m_resItem.m_itemData.GetTooltip(-1);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "HideRequirement")]
		private static void InventoryGui_HideRequirement(Transform elementRoot)
		{
			if (Configs.CraftPanelTooltipReq.Value)
			{
				UITooltip component = ((Component)elementRoot).GetComponent<UITooltip>();
				component.m_topic = string.Empty;
				component.m_text = string.Empty;
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player), "GetAvailableRecipes")]
		private static IEnumerable<CodeInstruction> Player_GetAvailableRecipes(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "RequiredCraftingStation", (Type[])null, (Type[])null);
			Func<Player, Recipe, int, bool, bool> func = RequiredCraftingStation_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)func.Method);
		}

		private static bool RequiredCraftingStation_Intercept(Player player, Recipe recipe, int qualityLevel, bool checkLevel)
		{
			if (!Configs.CraftPanelShowAnyKnownStation.Value || Object.op_Implicit((Object)(object)player.GetCurrentCraftingStation()))
			{
				return player.RequiredCraftingStation(recipe, qualityLevel, checkLevel);
			}
			if (!Object.op_Implicit((Object)(object)recipe.GetRequiredStation(qualityLevel)))
			{
				return true;
			}
			if (!checkLevel)
			{
				return true;
			}
			if (player.m_currentStation.GetLevel(true) < recipe.GetRequiredStationLevel(qualityLevel))
			{
				return false;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
		private static void InventoryGui_UpdateRecipe(InventoryGui __instance)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.CraftPanelShowAnyKnownStation.Value)
			{
				ShowAnyKnownStation(__instance);
			}
			if (Configs.CraftPanelEnabled.Value)
			{
				((Component)__instance.m_variantButton).gameObject.SetActive(false);
				float y = (__instance.InCraftTab() ? (-150f) : 20f);
				RectTransform rectTransform = __instance.m_itemCraftType.rectTransform;
				Vector2 craftTypeTextOrigPos = _craftTypeTextOrigPos;
				craftTypeTextOrigPos.y = y;
				rectTransform.anchoredPosition = craftTypeTextOrigPos;
			}
		}

		private static void ShowAnyKnownStation(InventoryGui gui)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer.GetCurrentCraftingStation()))
			{
				gui.m_craftingStationIcon.overrideSprite = null;
				((Component)gui.m_craftingStationIcon).gameObject.SetActive(true);
			}
			else
			{
				CraftingStation val = ((RecipeDataPair)(ref gui.m_selectedRecipe)).Recipe?.m_craftingStation;
				gui.m_craftingStationIcon.overrideSprite = val?.m_icon;
				((Component)gui.m_craftingStationIcon).gameObject.SetActive(Object.op_Implicit((Object)(object)val));
			}
			ItemData? selectedItem = _selectedItem;
			string arg = ((selectedItem != null) ? StringExt.Localize(ItemDataExt.GetName(selectedItem)) : null);
			TMP_Text craftingStationName = gui.m_craftingStationName;
			craftingStationName.text += $"\n<size=21><color={UIColor.Gray}>{arg}</color></size>";
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static void InventoryGui_Hide(InventoryGui __instance)
		{
			HideSelectedItemInfo_KBM();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "OnTabCraftPressed")]
		private static void InventoryGui_OnTabCraftPressed(InventoryGui __instance)
		{
			SelectItem(_selectedItem);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static void InventoryGui_Show(InventoryGui __instance)
		{
			if (!Configs.EnableSlideAnimation.Value)
			{
				__instance.UpdateContainer(Player.m_localPlayer);
				__instance.UpdateRecipe(Player.m_localPlayer, Time.deltaTime);
				__instance.UpdateRepair();
				if (!IsStationChanged)
				{
					FocusOn(_selectedItem);
				}
			}
		}
	}
	internal class CraftingPanelGrid : InventoryGrid
	{
		private class CacheData
		{
			public readonly int ID = grid._cache.Count;

			public readonly RectTransform Root = ((InventoryGrid)grid).m_gridRoot;

			public readonly List<Element> Elements = ((InventoryGrid)grid).m_elements;

			public readonly int Width = ((InventoryGrid)grid).m_width;

			public readonly int Height = ((InventoryGrid)grid).m_height;

			public CacheData(CraftingPanelGrid grid)
			{
			}
		}

		private static readonly Color BlackAndWhite = Hud.s_colorRedBlueZeroAlpha;

		private readonly Stopwatch _stopwatch = new Stopwatch();

		private readonly Dictionary<(int Width, int Height), CacheData> _cache = new Dictionary<(int, int), CacheData>();

		private RectTransform _originalGridRoot;

		private ScrollRectEnsureVisible _scrollRectEnsureVisible;

		public ScrollRect ScrollRect { get; private set; }

		public event Action<ItemData?>? OnSelectedItem;

		public event Action<float>? OnScrollChanged;

		internal void Init(int width, int height)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0091: 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_00a6: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: 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_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			Logging<Plugin>.Info((object)"Set the default grid root", 0);
			InitGridRoot();
			Logging<Plugin>.Info((object)"Set the element prefab", 0);
			base.m_elementPrefab = instance.m_playerGrid.m_elementPrefab;
			Logging<Plugin>.Info((object)"Set the element space", 0);
			base.m_elementSpace = instance.m_playerGrid.m_elementSpace;
			Logging<Plugin>.Info((object)"Setup the position defaults", 0);
			RectTransform val = (RectTransform)((Component)this).transform;
			val.anchoredPosition = Vector2.zero;
			val.anchorMax = Vector2.one;
			val.anchorMin = Vector2.zero;
			val.offsetMax = new Vector2(0f, -5f);
			val.offsetMin = new Vector2(0f, -5f);
			val.sizeDelta = Vector2.zero;
			val.pivot = Vector2.one * 0.5f;
			Logging<Plugin>.Info((object)"Setup the tooltip anchor", 0);
			base.m_tooltipAnchor = Object.Instantiate<RectTransform>(instance.m_playerGrid.m_tooltipAnchor, (Transform)(object)instance.m_crafting, false);
			((Object)base.m_tooltipAnchor).name = "TooltipAnchor_ZenUI";
			base.m_tooltipAnchor.anchoredPosition = new Vector2(-1000f, -70f);
			Logging<Plugin>.Info((object)"Setup the UIGroupHandler", 0);
			base.m_uiGroup = ((Component)instance.m_crafting).GetComponent<UIGroupHandler>();
			Logging<Plugin>.Info((object)"Setup the inventory for the grid", 0);
			base.m_inventory = new Inventory("$hud_crafting", (Sprite)null, width, height);
			Logging<Plugin>.Info((object)"Clone the scrollbar", 0);
			GameObject val2 = Object.Instantiate<GameObject>(((Component)instance.ContainerGrid.m_scrollbar).gameObject, ((Component)this).transform, false);
			((Object)val2).name = "ScrollBar";
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchoredPosition = new Vector2(0f, 0f);
			val3.anchorMax = new Vector2(1f, 1f);
			val3.anchorMin = new Vector2(1f, 0f);
			val3.offsetMax = new Vector2(4f, 0f);
			val3.offsetMin = new Vector2(-4f, 0f);
			Logging<Plugin>.Info((object)"Add event handler for SelectedItem", 0);
			base.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Combine(base.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(InvokeOnSelectedItem));
			Logging<Plugin>.Info((object)"Fixup the scrollbar", 0);
			base.m_scrollbar = val2.GetComponent<Scrollbar>();
			base.m_scrollbar.handleRect = (RectTransform)val2.transform.Find("Sliding Area/Handle");
			((UnityEvent<float>)(object)base.m_scrollbar.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				this.OnScrollChanged?.Invoke(v);
			});
			Logging<Plugin>.Info((object)"Reassign the ScrollRect area to point to this crafting grid", 0);
			ScrollRect = ((Component)this).GetComponent<ScrollRect>();
			ScrollRect.verticalScrollbarVisibility = (ScrollbarVisibility)1;
			ScrollRect.content = base.m_gridRoot;
			ScrollRect.verticalScrollbar = base.m_scrollbar;
			ScrollRect.scrollSensitivity = 10f;
			_scrollRectEnsureVisible = ((Component)ScrollRect).gameObject.AddComponent<ScrollRectEnsureVisible>();
		}

		private void OnDestroy()
		{
			Object.Destroy((Object)(object)((Component)base.m_scrollbar).gameObject);
			Object.Destroy((Object)(object)((Component)base.m_tooltipAnchor).gameObject);
			foreach (CacheData value in _cache.Values)
			{
				Object.Destroy((Object)(object)((Component)value.Root).gameObject);
			}
		}

		private void InvokeOnSelectedItem(InventoryGrid grid, ItemData? item, Vector2i pos, Modifier modifier)
		{
			//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)
			this.OnSelectedItem?.Invoke(item);
			if (!ZInput.IsGamepadActive())
			{
				InventoryGui.instance.m_moveItemEffects.Create(((Component)this).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
			}
		}

		private void InitGridRoot()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			_originalGridRoot = (RectTransform)((Component)this).transform.Find("Root");
			base.m_gridRoot = _originalGridRoot;
			foreach (Transform item in (Transform)_originalGridRoot)
			{
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			((Component)_originalGridRoot).gameObject.SetActive(false);
		}

		private (int Width, int Height) GetKey()
		{
			return (((InventoryGrid)this).GetInventory().m_width, ((InventoryGrid)this).GetInventory().m_height);
		}

		private bool IsSame(CacheData cache)
		{
			if (base.m_elements == cache.Elements && base.m_inventory.m_width == cache.Width)
			{
				return base.m_inventory.m_height == cache.Height;
			}
			return false;
		}

		private void CreateCache()
		{
			base.m_elements = new List<Element>();
			base.m_width = base.m_inventory.m_width;
			base.m_height = base.m_inventory.m_height;
			RectTransform val = Object.Instantiate<RectTransform>(_originalGridRoot, ((Component)thi