Decompiled source of OdinsReclaim v1.0.0

OdinsReclaim.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OdinsReclaim
{
	internal static class Banner
	{
		private const float Seconds = 4f;

		private const float FadeSeconds = 0.5f;

		private static GameObject s_root;

		private static CanvasGroup s_group;

		private static TMP_Text s_text;

		private static float s_until;

		internal static bool Show(string text)
		{
			InventoryGui instance = InventoryGui.instance;
			if (!Object.op_Implicit((Object)(object)instance) || !InventoryGui.IsVisible())
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)s_root) && !Build(instance))
			{
				return false;
			}
			s_text.text = text;
			s_root.SetActive(true);
			s_group.alpha = 1f;
			s_until = Time.unscaledTime + 4f;
			return true;
		}

		internal static void Tick()
		{
			if (Object.op_Implicit((Object)(object)s_root) && s_root.activeSelf)
			{
				float num = s_until - Time.unscaledTime;
				if (num <= 0f || !InventoryGui.IsVisible())
				{
					s_root.SetActive(false);
				}
				else
				{
					s_group.alpha = Mathf.Clamp01(num / 0.5f);
				}
			}
		}

		private static bool Build(InventoryGui gui)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			Canvas componentInParent = ((Component)gui).GetComponentInParent<Canvas>();
			Transform val = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent.rootCanvas).transform : ((Component)gui).transform);
			TMP_Text recipeName = gui.m_recipeName;
			if (!Object.op_Implicit((Object)(object)recipeName))
			{
				return false;
			}
			s_root = new GameObject("OdinsReclaim_Banner", new Type[1] { typeof(RectTransform) });
			s_root.transform.SetParent(val, false);
			Canvas obj = s_root.AddComponent<Canvas>();
			obj.overrideSorting = true;
			obj.sortingOrder = 30000;
			s_group = s_root.AddComponent<CanvasGroup>();
			s_group.blocksRaycasts = false;
			s_group.interactable = false;
			RectTransform val2 = (RectTransform)s_root.transform;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 1f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(0.5f, 1f);
			Place();
			val2.sizeDelta = new Vector2(1100f, 46f);
			Image obj2 = s_root.AddComponent<Image>();
			((Graphic)obj2).color = new Color(0f, 0f, 0f, 0.8f);
			((Graphic)obj2).raycastTarget = false;
			GameObject val4 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(s_root.transform, false);
			RectTransform val5 = (RectTransform)val4.transform;
			val5.anchorMin = Vector2.zero;
			val5.anchorMax = Vector2.one;
			val5.offsetMin = new Vector2(18f, 4f);
			val5.offsetMax = new Vector2(-18f, -4f);
			TextMeshProUGUI obj3 = val4.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj3).font = recipeName.font;
			((TMP_Text)obj3).fontSharedMaterial = recipeName.fontSharedMaterial;
			((TMP_Text)obj3).enableAutoSizing = true;
			((TMP_Text)obj3).fontSizeMin = 14f;
			((TMP_Text)obj3).fontSizeMax = 24f;
			((TMP_Text)obj3).alignment = (TextAlignmentOptions)514;
			((Graphic)obj3).color = new Color(1f, 0.92f, 0.75f);
			((TMP_Text)obj3).richText = true;
			((Graphic)obj3).raycastTarget = false;
			s_text = (TMP_Text)(object)obj3;
			s_root.SetActive(false);
			return true;
		}

		internal static void Place()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			if (Object.op_Implicit((Object)(object)s_root))
			{
				((RectTransform)s_root.transform).anchoredPosition = new Vector2(0f, -24f) + Settings.BannerOffset.Value;
			}
		}
	}
	[HarmonyPatch]
	internal static class ChestButton
	{
		private const float ConfirmSeconds = 4f;

		private static Button s_button;

		private static float s_armedUntil = -1f;

		private static Container s_armedFor;

		private static bool s_hooked;

		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		[HarmonyPostfix]
		private static void AfterAwake(InventoryGui __instance)
		{
			Disarm();
			if (!GuiAccess.Ok || !Object.op_Implicit((Object)(object)__instance.m_stackAllButton))
			{
				return;
			}
			try
			{
				s_button = GuiAccess.CloneButton(__instance.m_stackAllButton, "OdinsReclaim_ReclaimAll", "", OnClick);
				MakeIcon(s_button);
				UITooltip component = ((Component)s_button).GetComponent<UITooltip>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.m_text = "Reclaim all: break every item in this chest back into materials (drag to move)";
				}
				((Component)s_button).gameObject.AddComponent<DragMover>().Moved = delegate(Vector2 pos)
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					Settings.ChestButtonPos.Value = pos;
				};
				Place(__instance);
				if (!s_hooked)
				{
					s_hooked = true;
					Settings.ChestButtonPos.SettingChanged += delegate
					{
						Place(InventoryGui.instance);
					};
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Couldn't add the Reclaim all button: " + ex));
				s_button = null;
			}
		}

		private static void MakeIcon(Button button)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)((Component)button).transform;
			Rect rect = val.rect;
			float num;
			if (!(((Rect)(ref rect)).height > 1f))
			{
				num = val.sizeDelta.y;
			}
			else
			{
				rect = val.rect;
				num = ((Rect)(ref rect)).height;
			}
			float num2 = Mathf.Max(36f, num);
			val.sizeDelta = new Vector2(num2, num2);
			GameObject val2 = new GameObject("Icon", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(((Component)button).transform, false);
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = new Vector2(4f, 4f);
			val3.offsetMax = new Vector2(-4f, -4f);
			Image obj = val2.AddComponent<Image>();
			obj.sprite = Ui.Icon("ui_recycle.png");
			obj.preserveAspect = true;
			((Graphic)obj).raycastTarget = false;
		}

		private static void Place(InventoryGui gui)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0056: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)gui) || !Object.op_Implicit((Object)(object)s_button))
			{
				return;
			}
			RectTransform val = (RectTransform)((Component)s_button).transform;
			Vector2 value = Settings.ChestButtonPos.Value;
			if (value != Vector2.zero)
			{
				val.anchoredPosition = value;
				return;
			}
			RectTransform val2 = (RectTransform)((Component)gui.m_takeAllButton).transform;
			RectTransform val3 = (RectTransform)((Component)gui.m_stackAllButton).transform;
			Vector2 val4 = val3.anchoredPosition - val2.anchoredPosition;
			Vector2 anchoredPosition = val3.anchoredPosition;
			Vector2 normalized = ((Vector2)(ref val4)).normalized;
			Rect rect = val3.rect;
			float num = ((Rect)(ref rect)).width / 2f;
			rect = val.rect;
			val.anchoredPosition = anchoredPosition + normalized * (num + ((Rect)(ref rect)).width / 2f + 8f);
			if (((Vector2)(ref val4)).sqrMagnitude < 1f)
			{
				Vector2 anchoredPosition2 = val3.anchoredPosition;
				rect = val3.rect;
				val.anchoredPosition = anchoredPosition2 + new Vector2(((Rect)(ref rect)).width, 0f);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		[HarmonyPostfix]
		private static void AfterUpdateContainer(InventoryGui __instance)
		{
			if (Object.op_Implicit((Object)(object)s_button))
			{
				Container val = GuiAccess.CurrentContainer(__instance);
				bool flag = Settings.ChestEnabled.Value && Object.op_Implicit((Object)(object)val) && ((Component)__instance.m_stackAllButton).gameObject.activeInHierarchy;
				if (((Component)s_button).gameObject.activeSelf != flag)
				{
					((Component)s_button).gameObject.SetActive(flag);
				}
				if (s_armedUntil >= 0f && (Time.time > s_armedUntil || (Object)(object)val != (Object)(object)s_armedFor))
				{
					Disarm();
				}
			}
		}

		private static void Disarm()
		{
			s_armedUntil = -1f;
			s_armedFor = null;
		}

		private static string ChestPrefab(Container chest)
		{
			if (!Object.op_Implicit((Object)(object)chest))
			{
				return null;
			}
			return Utils.GetPrefabName(((Component)chest).gameObject);
		}

		private static void OnClick()
		{
			InventoryGui instance = InventoryGui.instance;
			Player p = Player.m_localPlayer;
			Container chest = (Object.op_Implicit((Object)(object)instance) ? GuiAccess.CurrentContainer(instance) : null);
			if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)chest) || !Settings.ChestEnabled.Value)
			{
				return;
			}
			try
			{
				if (s_armedUntil >= 0f && (Object)(object)s_armedFor == (Object)(object)chest && Time.time <= s_armedUntil)
				{
					Disarm();
					ReclaimAll(p, chest);
					return;
				}
				int num = 0;
				Dictionary<string, int> reasons = new Dictionary<string, int>();
				string chestPrefab = ChestPrefab(chest);
				foreach (ItemData allItem in chest.GetInventory().GetAllItems())
				{
					Plan plan = Yields.Make(allItem, p, Way.Chest, null, chestPrefab);
					if (plan.Ok)
					{
						num++;
					}
					else
					{
						Tally(reasons, plan.Problem);
					}
				}
				if (num == 0)
				{
					Plugin.Say(p, "Nothing in this chest can be reclaimed here" + Reasons(reasons), always: true);
					return;
				}
				float value = Settings.Rate.Value;
				string text = $"Break {num} item(s) in this chest back into materials? You get back about " + $"{Mathf.RoundToInt(value * 100f)}% of what they took to make. This can't be undone.";
				if (!Ui.Confirm("Reclaim all", text, delegate
				{
					ReclaimAll(p, chest);
				}))
				{
					s_armedUntil = Time.time + 4f;
					s_armedFor = chest;
					Plugin.Say(p, $"Click again to reclaim {num} item(s) from this chest", always: true);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Reclaim all failed: " + ex));
				Disarm();
			}
		}

		private static void ReclaimAll(Player p, Container chest)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)chest) || !Object.op_Implicit((Object)(object)instance) || (Object)(object)GuiAccess.CurrentContainer(instance) != (Object)(object)chest)
			{
				if (Object.op_Implicit((Object)(object)p))
				{
					Plugin.Say(p, "The chest was closed, nothing was reclaimed", always: true);
				}
				return;
			}
			Inventory inventory = chest.GetInventory();
			Vector3 dropAt = ((Component)chest).transform.position + Vector3.up;
			string chestPrefab = ChestPrefab(chest);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			Dictionary<string, int> reasons = new Dictionary<string, int>();
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				Plan plan = Yields.Make(item, p, Way.Chest, null, chestPrefab);
				if (!plan.Ok)
				{
					Tally(reasons, plan.Problem);
					continue;
				}
				if (!Moves.Fits(inventory, plan.Outputs, 1))
				{
					num2++;
					continue;
				}
				ItemData val = Moves.Take(inventory, item, null);
				if (val != null)
				{
					num3 += Moves.Give(inventory, plan.Outputs, val.m_cheated, dropAt, p);
					num++;
					if (Settings.LogActions.Value)
					{
						Plugin.Log.LogInfo((object)$"Reclaim all: {Yields.PrefabName(val)} q{val.m_quality} x{val.m_stack} -> {plan.OutputText()}");
					}
				}
			}
			if (num > 0)
			{
				CraftingStation craftingStation = CraftingStation.GetCraftingStation(((Component)p).transform.position);
				if (Object.op_Implicit((Object)(object)craftingStation))
				{
					craftingStation.m_craftItemDoneEffects.Create(((Component)p).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
			string text = $"Reclaimed {num} item(s)";
			if (num2 > 0)
			{
				text += $", {num2} skipped (chest full)";
			}
			if (num3 > 0)
			{
				text += $", {num3} material(s) fell next to the chest";
			}
			Plugin.Say(p, text + Reasons(reasons), always: true);
			if (ReclaimTab.Active && GuiAccess.Ok)
			{
				GuiAccess.RefreshCrafting(instance);
			}
		}

		private static void Tally(Dictionary<string, int> reasons, string why)
		{
			if (!string.IsNullOrEmpty(why))
			{
				reasons.TryGetValue(why, out var value);
				reasons[why] = value + 1;
			}
		}

		private static string Reasons(Dictionary<string, int> reasons)
		{
			if (reasons.Count == 0 || !Settings.ShowReasons.Value)
			{
				return "";
			}
			string arg = "";
			int num = 0;
			foreach (KeyValuePair<string, int> reason in reasons)
			{
				if (reason.Value > num)
				{
					num = reason.Value;
					arg = reason.Key;
				}
			}
			return $" ({num} item(s): {arg})";
		}
	}
	internal static class EpicLootBridge
	{
		private static bool s_looked;

		private static MethodInfo s_magicJson;

		private static MethodInfo s_costsJson;

		private static readonly string[] Rarities = new string[6] { "Magic", "Rare", "Epic", "Legendary", "Mythic", "Ancient" };

		private static ItemData s_lastItem;

		private static float s_lastTime = -10f;

		private static List<KeyValuePair<string, int>> s_last;

		internal static bool Present
		{
			get
			{
				if (!s_looked)
				{
					s_looked = true;
					Type type = AccessTools.TypeByName("EpicLoot.API");
					if (type != null)
					{
						s_magicJson = AccessTools.Method(type, "GetMagicItemJson", new Type[1] { typeof(ItemData) }, (Type[])null);
						s_costsJson = AccessTools.Method(type, "GetEnchantCostsJson", new Type[2]
						{
							typeof(ItemData),
							typeof(int)
						}, (Type[])null);
						if (s_magicJson == null || s_costsJson == null)
						{
							Plugin.Log.LogWarning((object)"Epic Loot is installed but its API has changed: enchanting materials aren't given back");
						}
					}
				}
				if (s_magicJson != null)
				{
					return s_costsJson != null;
				}
				return false;
			}
		}

		internal static List<KeyValuePair<string, int>> EnchantCosts(ItemData item)
		{
			if (item != null && item == s_lastItem && Time.unscaledTime - s_lastTime < 1f && s_last != null)
			{
				return s_last;
			}
			s_last = Read(item);
			s_lastItem = item;
			s_lastTime = Time.unscaledTime;
			return s_last;
		}

		private static List<KeyValuePair<string, int>> Read(ItemData item)
		{
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>();
			if (item == null || !Present)
			{
				return list;
			}
			try
			{
				string text = s_magicJson.Invoke(null, new object[1] { item }) as string;
				if (string.IsNullOrEmpty(text))
				{
					return list;
				}
				int num = -1;
				Match m = Regex.Match(text, "\"Rarity\"\\s*:\\s*(\\d+)");
				if (m.Success)
				{
					num = int.Parse(m.Groups[1].Value);
				}
				else
				{
					m = Regex.Match(text, "\"Rarity\"\\s*:\\s*\"(\\w+)\"");
					if (m.Success)
					{
						num = Array.FindIndex(Rarities, (string r) => string.Equals(r, m.Groups[1].Value, StringComparison.OrdinalIgnoreCase));
					}
				}
				if (num < 0)
				{
					return list;
				}
				string text2 = s_costsJson.Invoke(null, new object[2] { item, num }) as string;
				if (string.IsNullOrEmpty(text2))
				{
					return list;
				}
				foreach (Match item2 in Regex.Matches(text2, "\\{[^{}]*\\}"))
				{
					Match match = Regex.Match(item2.Value, "\"Item\"\\s*:\\s*\"([^\"]*)\"");
					Match match2 = Regex.Match(item2.Value, "\"Amount\"\\s*:\\s*(-?\\d+)");
					if (match.Success && match2.Success && int.TryParse(match2.Groups[1].Value, out var result) && result > 0)
					{
						list.Add(new KeyValuePair<string, int>(match.Groups[1].Value, result));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Epic Loot enchant costs failed: " + (ex.InnerException?.Message ?? ex.Message)));
				list.Clear();
			}
			return list;
		}
	}
	internal static class Groups
	{
		private static readonly HashSet<string> BossTrophies = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "TrophyEikthyr", "TrophyTheElder", "TrophyBonemass", "TrophyDragonQueen", "TrophyGoblinKing", "TrophySeekerQueen", "TrophyFader" };

		private static Dictionary<string, List<string>> s_custom;

		private static HashSet<string> s_ores;

		private static HashSet<string> s_metals;

		private static HashSet<string> s_woods;

		private static HashSet<string> s_seeds;

		private static HashSet<string> s_crops;

		private static ObjectDB s_builtFor;

		internal static void ResetCustom()
		{
			s_custom = null;
		}

		internal static bool Matches(string entry, ItemData item, int depth = 0)
		{
			if (string.IsNullOrEmpty(entry) || item?.m_shared == null || depth > 4)
			{
				return false;
			}
			if (string.Equals(entry, Yields.PrefabName(item), StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (Custom().TryGetValue(entry, out var value))
			{
				foreach (string item2 in value)
				{
					if (Matches(item2, item, depth + 1))
					{
						return true;
					}
				}
				return false;
			}
			return BuiltIn(entry, item);
		}

		internal static bool AnyMatch(List<string> entries, ItemData item)
		{
			foreach (string entry in entries)
			{
				if (Matches(entry, item))
				{
					return true;
				}
			}
			return false;
		}

		private static Dictionary<string, List<string>> Custom()
		{
			if (s_custom != null)
			{
				return s_custom;
			}
			s_custom = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
			string[] array = (Settings.CustomGroups.Value ?? "").Split(';');
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num > 0)
				{
					string text2 = text.Substring(0, num).Trim();
					List<string> list = Settings.SplitList(text.Substring(num + 1));
					if (text2.Length > 0 && list.Count > 0)
					{
						s_custom[text2] = list;
					}
				}
			}
			return s_custom;
		}

		private static bool BuiltIn(string group, ItemData item)
		{
			//IL_0008: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_06c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c4: Invalid comparison between Unknown and I4
			//IL_06da: Unknown result type (might be due to invalid IL or missing references)
			//IL_06dd: Invalid comparison between Unknown and I4
			//IL_06e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e3: Invalid comparison between Unknown and I4
			//IL_066a: Unknown result type (might be due to invalid IL or missing references)
			//IL_066c: Invalid comparison between Unknown and I4
			//IL_0685: Unknown result type (might be due to invalid IL or missing references)
			//IL_0688: Invalid comparison between Unknown and I4
			//IL_05cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d2: Invalid comparison between Unknown and I4
			//IL_066e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0671: Invalid comparison between Unknown and I4
			//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ad: Invalid comparison between Unknown and I4
			//IL_0665: Unknown result type (might be due to invalid IL or missing references)
			//IL_0667: Invalid comparison between Unknown and I4
			//IL_0680: Unknown result type (might be due to invalid IL or missing references)
			//IL_0682: Invalid comparison between Unknown and I4
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			//IL_0619: Invalid comparison between Unknown and I4
			//IL_06d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d7: Invalid comparison between Unknown and I4
			//IL_068a: Unknown result type (might be due to invalid IL or missing references)
			//IL_068d: Invalid comparison between Unknown and I4
			//IL_0673: Unknown result type (might be due to invalid IL or missing references)
			//IL_0676: Invalid comparison between Unknown and I4
			//IL_05f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fd: Invalid comparison between Unknown and I4
			//IL_069e: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a1: Invalid comparison between Unknown and I4
			//IL_05d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05df: Invalid comparison between Unknown and I4
			//IL_0606: Unknown result type (might be due to invalid IL or missing references)
			//IL_060c: Invalid comparison between Unknown and I4
			//IL_0692: Unknown result type (might be due to invalid IL or missing references)
			//IL_0695: Invalid comparison between Unknown and I4
			//IL_062c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0632: Invalid comparison between Unknown and I4
			//IL_0698: Unknown result type (might be due to invalid IL or missing references)
			//IL_069b: Invalid comparison between Unknown and I4
			//IL_0659: Unknown result type (might be due to invalid IL or missing references)
			//IL_0660: Invalid comparison between Unknown and I4
			//IL_06a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a7: Invalid comparison between Unknown and I4
			//IL_0678: Unknown result type (might be due to invalid IL or missing references)
			//IL_067b: Invalid comparison between Unknown and I4
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0641: Invalid comparison between Unknown and I4
			//IL_061e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0621: Invalid comparison between Unknown and I4
			//IL_05e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Invalid comparison between Unknown and I4
			//IL_064a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0650: Invalid comparison between Unknown and I4
			SharedData shared = item.m_shared;
			ItemType itemType = shared.m_itemType;
			bool flag = (int)itemType == 3 || (int)itemType == 14 || (int)itemType == 22 || (int)itemType == 4;
			bool flag2 = (int)itemType == 2;
			bool flag3 = shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f;
			string item2 = Yields.PrefabName(item) ?? "";
			switch (group.Replace(" ", "").ToLowerInvariant())
			{
			case "all":
				return true;
			case "food":
				return flag2 && flag3;
			case "potion":
			case "potions":
				if (flag2)
				{
					return !flag3;
				}
				return false;
			case "fish":
				return (int)itemType == 21;
			case "swords":
				if (flag)
				{
					return (int)shared.m_skillType == 1;
				}
				return false;
			case "axes":
				if (flag)
				{
					return (int)shared.m_skillType == 7;
				}
				return false;
			case "clubs":
				if (flag)
				{
					return (int)shared.m_skillType == 3;
				}
				return false;
			case "knives":
				if (flag)
				{
					return (int)shared.m_skillType == 2;
				}
				return false;
			case "pickaxes":
				if ((int)shared.m_skillType == 12)
				{
					if (!flag)
					{
						return (int)itemType == 19;
					}
					return true;
				}
				return false;
			case "polearms":
				if (flag)
				{
					return (int)shared.m_skillType == 4;
				}
				return false;
			case "spears":
				if (flag)
				{
					return (int)shared.m_skillType == 5;
				}
				return false;
			case "bows":
				if (flag)
				{
					return (int)shared.m_skillType == 8;
				}
				return false;
			case "crossbows":
				if (flag)
				{
					return (int)shared.m_skillType == 14;
				}
				return false;
			case "shields":
				return (int)itemType == 5;
			case "armour":
			case "armor":
				if ((int)itemType != 7 && (int)itemType != 11 && (int)itemType != 17)
				{
					return (int)itemType == 12;
				}
				return true;
			case "helmets":
				return (int)itemType == 6;
			case "ammo":
			case "ammunition":
				if ((int)itemType != 9)
				{
					return (int)itemType == 23;
				}
				return true;
			case "utility":
			case "utilities":
				return (int)itemType == 18;
			case "trinkets":
				return (int)itemType == 24;
			case "tools":
				return (int)itemType == 19;
			case "equipment":
				return (int)itemType == 15;
			case "trophy":
			case "trophies":
				if ((int)itemType == 13)
				{
					return !BossTrophies.Contains(item2);
				}
				return false;
			case "bosstrophy":
			case "bosstrophies":
				if ((int)itemType == 13)
				{
					return BossTrophies.Contains(item2);
				}
				return false;
			case "materials":
				return (int)itemType == 1;
			case "misc":
			case "miscellaneous":
				return (int)itemType == 16;
			case "customizations":
				return (int)itemType == 10;
			case "ores":
				Build();
				return s_ores.Contains(item2);
			case "metals":
				Build();
				return s_metals.Contains(item2);
			case "woods":
				Build();
				return s_woods.Contains(item2);
			case "seeds":
				Build();
				return s_seeds.Contains(item2);
			case "crops":
				Build();
				return s_crops.Contains(item2);
			default:
				return false;
			}
		}

		private static void Build()
		{
			if (s_ores != null && (Object)(object)s_builtFor == (Object)(object)ObjectDB.instance)
			{
				return;
			}
			s_builtFor = ObjectDB.instance;
			s_ores = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			s_metals = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			s_woods = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			s_seeds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			s_crops = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			try
			{
				ZNetScene instance = ZNetScene.instance;
				string[] array = new string[3] { "smelter", "blastfurnace", "charcoal_kiln" };
				foreach (string text in array)
				{
					object obj;
					if (!Object.op_Implicit((Object)(object)instance))
					{
						obj = null;
					}
					else
					{
						GameObject prefab = instance.GetPrefab(text);
						obj = ((prefab != null) ? prefab.GetComponent<Smelter>() : null);
					}
					Smelter val = (Smelter)obj;
					if (!Object.op_Implicit((Object)(object)val))
					{
						continue;
					}
					foreach (ItemConversion item in val.m_conversion)
					{
						if (!((Object)(object)item?.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null))
						{
							if (text == "charcoal_kiln")
							{
								s_woods.Add(((Object)((Component)item.m_from).gameObject).name);
								continue;
							}
							s_ores.Add(((Object)((Component)item.m_from).gameObject).name);
							s_metals.Add(((Object)((Component)item.m_to).gameObject).name);
						}
					}
				}
				object obj2;
				if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
				{
					obj2 = null;
				}
				else
				{
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Cultivator");
					obj2 = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				}
				ItemDrop val2 = (ItemDrop)obj2;
				PieceTable val3 = (Object.op_Implicit((Object)(object)val2) ? val2.m_itemData.m_shared.m_buildPieces : null);
				if (!((Object)(object)val3 != (Object)null))
				{
					return;
				}
				foreach (GameObject piece in val3.m_pieces)
				{
					Plant val4 = (Object.op_Implicit((Object)(object)piece) ? piece.GetComponent<Plant>() : null);
					Piece val5 = (Object.op_Implicit((Object)(object)piece) ? piece.GetComponent<Piece>() : null);
					if (!Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val5))
					{
						continue;
					}
					Requirement[] resources = val5.m_resources;
					foreach (Requirement val6 in resources)
					{
						if (Object.op_Implicit((Object)(object)val6?.m_resItem))
						{
							s_seeds.Add(((Object)((Component)val6.m_resItem).gameObject).name);
						}
					}
					GameObject[] grownPrefabs = val4.m_grownPrefabs;
					foreach (GameObject val7 in grownPrefabs)
					{
						Pickable val8 = (Object.op_Implicit((Object)(object)val7) ? val7.GetComponent<Pickable>() : null);
						if (Object.op_Implicit((Object)(object)val8) && Object.op_Implicit((Object)(object)val8.m_itemPrefab))
						{
							s_crops.Add(((Object)val8.m_itemPrefab).name);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't build the Ores/Metals/Woods/Seeds/Crops groups: " + ex.Message));
			}
		}
	}
	internal static class GuiAccess
	{
		private static FieldRef<InventoryGui, Container> s_container;

		private static FieldRef<InventoryGui, float> s_craftTimer;

		private static FieldRef<InventoryGui, float> s_listBaseSize;

		private static FieldInfo s_available;

		private static FieldInfo s_selected;

		private static MethodInfo s_pairRecipe;

		private static MethodInfo s_pairItem;

		private static MethodInfo s_pairElement;

		private static MethodInfo s_addRecipeToList;

		private static MethodInfo s_updateCraftingPanel;

		private static MethodInfo s_setRecipe;

		private static FieldRef<InventoryGrid, List<InventoryElement>> s_elements;

		private static FieldRef<InventoryGui, ItemData> s_dragItem;

		private static FieldRef<InventoryGui, Inventory> s_dragInventory;

		private static FieldRef<InventoryGui, int> s_dragAmount;

		private static MethodInfo s_setupDrag;

		internal static bool Ok { get; private set; }

		internal static bool DragOk { get; private set; }

		internal static void Init()
		{
			try
			{
				s_container = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");
				s_craftTimer = AccessTools.FieldRefAccess<InventoryGui, float>("m_craftTimer");
				s_listBaseSize = AccessTools.FieldRefAccess<InventoryGui, float>("m_recipeListBaseSize");
				s_available = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");
				s_selected = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");
				Type type = AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair");
				s_pairRecipe = AccessTools.PropertyGetter(type, "Recipe");
				s_pairItem = AccessTools.PropertyGetter(type, "ItemData");
				s_pairElement = AccessTools.PropertyGetter(type, "InterfaceElement");
				s_addRecipeToList = AccessTools.Method(typeof(InventoryGui), "AddRecipeToList", new Type[4]
				{
					typeof(Player),
					typeof(Recipe),
					typeof(ItemData),
					typeof(bool)
				}, (Type[])null);
				s_updateCraftingPanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null);
				s_setRecipe = AccessTools.Method(typeof(InventoryGui), "SetRecipe", new Type[2]
				{
					typeof(int),
					typeof(bool)
				}, (Type[])null);
				s_elements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements");
				s_dragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem");
				s_dragInventory = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory");
				s_dragAmount = AccessTools.FieldRefAccess<InventoryGui, int>("m_dragAmount");
				s_setupDrag = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3]
				{
					typeof(ItemData),
					typeof(Inventory),
					typeof(int)
				}, (Type[])null);
				DragOk = s_setupDrag != null;
				Ok = s_available != null && s_selected != null && s_pairRecipe != null && s_pairItem != null && s_pairElement != null && s_addRecipeToList != null && s_updateCraftingPanel != null && s_setRecipe != null;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Couldn't find parts of the game's inventory screen (game update?): " + ex.Message));
				Ok = false;
			}
			if (!Ok)
			{
				Plugin.Log.LogError((object)"The Reclaim tab is off: the game's crafting list code has changed.");
			}
		}

		internal static Container CurrentContainer(InventoryGui gui)
		{
			if (s_container == null)
			{
				return null;
			}
			return s_container.Invoke(gui);
		}

		internal static float CraftTimer(InventoryGui gui)
		{
			if (s_craftTimer == null)
			{
				return -1f;
			}
			return s_craftTimer.Invoke(gui);
		}

		internal static bool Dragging(InventoryGui gui, out ItemData item, out Inventory inv, out int amount)
		{
			item = (DragOk ? s_dragItem.Invoke(gui) : null);
			inv = (DragOk ? s_dragInventory.Invoke(gui) : null);
			amount = (DragOk ? s_dragAmount.Invoke(gui) : 0);
			if (item != null)
			{
				return inv != null;
			}
			return false;
		}

		internal static void StopDragging(InventoryGui gui)
		{
			if (DragOk)
			{
				s_setupDrag.Invoke(gui, new object[3] { null, null, 1 });
			}
		}

		internal static List<InventoryElement> Elements(InventoryGrid grid)
		{
			if (s_elements == null)
			{
				return null;
			}
			return s_elements.Invoke(grid);
		}

		internal static void Selected(InventoryGui gui, out Recipe recipe, out ItemData item)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			object value = s_selected.GetValue(gui);
			recipe = (Recipe)s_pairRecipe.Invoke(value, null);
			item = (ItemData)s_pairItem.Invoke(value, null);
		}

		internal static void ClearList(InventoryGui gui)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			IList list = (IList)s_available.GetValue(gui);
			foreach (object item in list)
			{
				GameObject val = (GameObject)s_pairElement.Invoke(item, null);
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
			}
			list.Clear();
		}

		internal static GameObject LastElement(InventoryGui gui)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			IList list = (IList)s_available.GetValue(gui);
			if (list.Count <= 0)
			{
				return null;
			}
			return (GameObject)s_pairElement.Invoke(list[list.Count - 1], null);
		}

		internal static void ClearSelection(InventoryGui gui)
		{
			s_setRecipe.Invoke(gui, new object[2] { -1, false });
		}

		internal static int ListCount(InventoryGui gui)
		{
			return ((IList)s_available.GetValue(gui)).Count;
		}

		internal static void AddToList(InventoryGui gui, Player p, Recipe recipe, ItemData item, bool canCraft)
		{
			s_addRecipeToList.Invoke(gui, new object[4] { p, recipe, item, canCraft });
		}

		internal static void SizeList(InventoryGui gui)
		{
			float num = Mathf.Max(s_listBaseSize.Invoke(gui), (float)ListCount(gui) * gui.m_recipeListSpace);
			gui.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, num);
		}

		internal static void RefreshCrafting(InventoryGui gui)
		{
			s_updateCraftingPanel.Invoke(gui, new object[1] { false });
		}

		internal static Button CloneButton(Button original, string name, string label, Action onClick)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(((Component)original).gameObject, ((Component)original).transform.parent);
			((Object)val).name = name;
			UIGamePad[] componentsInChildren = val.GetComponentsInChildren<UIGamePad>(true);
			foreach (UIGamePad val2 in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val2.m_hint))
				{
					Object.Destroy((Object)(object)val2.m_hint);
				}
				Object.Destroy((Object)(object)val2);
			}
			Button component = val.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				onClick();
			});
			SetLabel(component, label);
			return component;
		}

		internal static void SetLabel(Button button, string label)
		{
			TMP_Text[] componentsInChildren = ((Component)button).GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = label;
			}
		}
	}
	[HarmonyPatch]
	internal static class InventoryKeys
	{
		private static readonly HashSet<ItemData> s_marked = new HashSet<ItemData>();

		private static bool s_painting;

		private static bool s_paintMark;

		private static readonly HashSet<Vector2i> s_markedPos = new HashSet<Vector2i>();

		private static float s_nextDelete;

		private const float DeleteCooldown = 0.3f;

		private static readonly Dictionary<InventoryElement, Image> s_outlines = new Dictionary<InventoryElement, Image>();

		private static int s_outlinesShown;

		private static Sprite s_border;

		internal static void Tick()
		{
			//IL_0033: 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)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !InventoryGui.IsVisible() || Typing() || Covered(InventoryGui.instance))
			{
				ClearMarks();
				return;
			}
			if (Settings.Down(Settings.UndoShortcut.Value))
			{
				Undo.Run(localPlayer);
				Refresh();
				return;
			}
			Trash(localPlayer);
			if (Settings.KeyEnabled.Value && Settings.Down(Settings.KeyShortcut.Value))
			{
				DeleteKey(localPlayer);
			}
		}

		private static bool Covered(InventoryGui gui)
		{
			if (Object.op_Implicit((Object)(object)gui) && !gui.IsSkillsPanelOpen && !gui.IsTextPanelOpen && !gui.IsTrophisPanelOpen && !gui.IsAchievementsPanelOpen && (!Object.op_Implicit((Object)(object)gui.m_splitDialog) || !gui.m_splitDialog.IsActive))
			{
				if (Object.op_Implicit((Object)(object)gui.m_variantDialog))
				{
					return ((Component)gui.m_variantDialog).gameObject.activeSelf;
				}
				return false;
			}
			return true;
		}

		private static bool Typing()
		{
			if (!Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !TextInput.IsVisible())
			{
				return Menu.IsVisible();
			}
			return true;
		}

		private static void DeleteKey(Player p)
		{
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < s_nextDelete)
			{
				return;
			}
			s_nextDelete = Time.unscaledTime + 0.3f;
			if (Settings.KeyAdminsOnly.Value && !SynchronizationManager.Instance.PlayerIsAdmin)
			{
				Plugin.Say(p, "Only admins can use the delete key on this server");
				return;
			}
			Inventory inventory = ((Humanoid)p).GetInventory();
			ItemData val = Hovered(inventory);
			if (val == null)
			{
				return;
			}
			string text = Localization.instance.Localize(val.m_shared.m_name);
			if (val.m_shared.m_questItem)
			{
				Plugin.Say(p, text + " can't be deleted");
				return;
			}
			if (Settings.ProtectEnchanted.Value && Yields.IsEnchanted(val))
			{
				Plugin.Say(p, text + " is enchanted and protected (Epic Loot's Sacrifice gives its materials back)");
				return;
			}
			Plan plan = Yields.Make(val, p, Way.Key);
			if (plan.Ok && !Moves.Fits(inventory, plan.Outputs, 1))
			{
				Plugin.Say(p, "Not enough room in your inventory for the materials");
				return;
			}
			ItemData val2 = Moves.Take(inventory, val, (Humanoid)(object)p);
			if (val2 == null)
			{
				return;
			}
			Undo.Entry e = Undo.Record(p, inventory, new List<ItemData> { val2 }, plan.Ok ? plan.Outputs : null, "deleted " + text);
			int num = 0;
			if (plan.Ok)
			{
				try
				{
					num = Moves.Give(inventory, plan.Outputs, val2.m_cheated, Moves.Feet(p), p);
				}
				catch (Exception arg)
				{
					Undo.Forget(e);
					Moves.PutBack(inventory, val2, Moves.Feet(p));
					Plugin.Log.LogError((object)$"Deleting {text} failed half-way, the item was put back: {arg}");
					Plugin.Say(p, "Something went wrong; " + text + " was put back", always: true);
					Refresh();
					return;
				}
			}
			if (num > 0)
			{
				Undo.Forget(e);
			}
			string text2 = (plan.Ok ? ("Deleted " + text + ", got back " + plan.OutputText()) : ("Deleted " + text + " (nothing back: " + plan.Problem + ")"));
			Plugin.Say(p, text2 + ((num > 0) ? " (some fell at your feet)" : Plugin.UndoHint()), always: true);
			if (Settings.LogActions.Value)
			{
				Plugin.Log.LogInfo((object)($"Delete key: {Yields.PrefabName(val2)} q{val2.m_quality} x{val2.m_stack} -> " + (plan.Ok ? plan.OutputText() : ("nothing (" + plan.Problem + ")"))));
			}
			Refresh();
		}

		private static bool Holding()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (Settings.TrashEnabled.Value && (int)Settings.TrashHoldKey.Value != 0)
			{
				return ZInput.GetKey(Settings.TrashHoldKey.Value, false);
			}
			return false;
		}

		private static void Trash(Player p)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (!Holding())
			{
				ClearMarks();
				return;
			}
			Inventory inv = ((Humanoid)p).GetInventory();
			s_marked.RemoveWhere((ItemData i) => !inv.ContainsItem(i));
			if (ZInput.GetMouseButtonDown(1))
			{
				ItemData val = Hovered(inv);
				if (val != null)
				{
					s_paintMark = !s_marked.Contains(val);
					s_painting = true;
					Mark(p, val, s_paintMark);
				}
			}
			else if (s_painting && ZInput.GetMouseButton(1))
			{
				ItemData val2 = Hovered(inv);
				if (val2 != null)
				{
					Mark(p, val2, s_paintMark);
				}
			}
			if (!ZInput.GetMouseButton(1))
			{
				s_painting = false;
			}
			if ((int)Settings.TrashDeleteKey.Value != 0 && ZInput.GetKeyDown(Settings.TrashDeleteKey.Value, false))
			{
				DeleteMarked(p, inv);
			}
		}

		private static void Mark(Player p, ItemData item, bool on)
		{
			//IL_0037: 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)
			if (on ? s_marked.Add(item) : s_marked.Remove(item))
			{
				Plugin.Say(p, $"Marked {s_marked.Count} item(s) to delete. {KeyName(Settings.TrashDeleteKey.Value)} " + "deletes them, let go of " + KeyName(Settings.TrashHoldKey.Value) + " to cancel", always: true);
			}
		}

		private static void DeleteMarked(Player p, Inventory inv)
		{
			if (s_marked.Count == 0)
			{
				return;
			}
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData item in new List<ItemData>(s_marked))
			{
				if (!item.m_shared.m_questItem)
				{
					ItemData val = Moves.Take(inv, item, (Humanoid)(object)p);
					if (val != null)
					{
						list.Add(val);
					}
				}
			}
			s_marked.Clear();
			s_painting = false;
			if (list.Count == 0)
			{
				return;
			}
			Undo.Record(p, inv, list, null, $"deleted {list.Count} marked item(s)");
			Plugin.Say(p, $"Deleted {list.Count} marked item(s)" + Plugin.UndoHint(), always: true);
			if (Settings.LogActions.Value)
			{
				foreach (ItemData item2 in list)
				{
					Plugin.Log.LogInfo((object)$"Trash: {Yields.PrefabName(item2)} q{item2.m_quality} x{item2.m_stack}");
				}
			}
			Refresh();
		}

		private static string KeyName(KeyCode k)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Settings.KeyText(k);
		}

		private static void ClearMarks()
		{
			s_marked.Clear();
			s_painting = false;
		}

		[HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")]
		[HarmonyPrefix]
		private static bool BeforeRightClick()
		{
			return !Holding();
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		[HarmonyPostfix]
		private static void AfterGridUpdate(InventoryGrid __instance)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || __instance.GetInventory() != ((Humanoid)localPlayer).GetInventory() || (s_marked.Count == 0 && s_outlinesShown == 0))
			{
				return;
			}
			List<InventoryElement> list = GuiAccess.Elements(__instance);
			if (list == null)
			{
				return;
			}
			s_markedPos.Clear();
			foreach (ItemData item in s_marked)
			{
				s_markedPos.Add(item.m_gridPos);
			}
			Color value = Settings.TrashColor.Value;
			int num = 0;
			foreach (InventoryElement item2 in list)
			{
				if (!Object.op_Implicit((Object)(object)item2))
				{
					continue;
				}
				bool flag = s_markedPos.Contains(item2.Position);
				s_outlines.TryGetValue(item2, out var value2);
				if (flag && !Object.op_Implicit((Object)(object)value2))
				{
					Image val = (s_outlines[item2] = MakeOutline(item2));
					value2 = val;
				}
				if (Object.op_Implicit((Object)(object)value2))
				{
					if (((Component)value2).gameObject.activeSelf != flag)
					{
						((Component)value2).gameObject.SetActive(flag);
					}
					if (flag)
					{
						((Graphic)value2).color = value;
						num++;
					}
				}
			}
			s_outlinesShown = num;
			if (num == 0)
			{
				s_outlines.Clear();
			}
		}

		private static Image MakeOutline(InventoryElement e)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("OdinsReclaim_Mark", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Component)e).transform, false);
			val.transform.SetAsLastSibling();
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			Vector2 offsetMin = (val2.offsetMax = Vector2.zero);
			val2.offsetMin = offsetMin;
			Image obj = val.AddComponent<Image>();
			obj.sprite = Border();
			obj.type = (Type)1;
			((Graphic)obj).raycastTarget = false;
			return obj;
		}

		private static Sprite Border()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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)
			if (Object.op_Implicit((Object)(object)s_border))
			{
				return s_border;
			}
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false)
			{
				name = "OdinsReclaim_Border",
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1
			};
			Color32[] array = (Color32[])(object)new Color32[1024];
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					array[i * 32 + j] = ((j < 3 || i < 3 || j >= 29 || i >= 29) ? new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue) : new Color32((byte)0, (byte)0, (byte)0, (byte)0));
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			((Object)val).hideFlags = (HideFlags)(((Object)val).hideFlags | 0x20);
			s_border = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(4f, 4f, 4f, 4f));
			((Object)s_border).name = "OdinsReclaim_Border";
			Sprite obj = s_border;
			((Object)obj).hideFlags = (HideFlags)(((Object)obj).hideFlags | 0x20);
			return s_border;
		}

		internal static bool IsMarked(ItemData item)
		{
			if (item != null)
			{
				return s_marked.Contains(item);
			}
			return false;
		}

		private static ItemData Hovered(Inventory inv)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return null;
			}
			Vector2 val = Vector2.op_Implicit(ZInput.pointerPosition);
			InventoryGrid[] componentsInChildren = ((Component)instance).GetComponentsInChildren<InventoryGrid>();
			foreach (InventoryGrid val2 in componentsInChildren)
			{
				if (val2.GetInventory() != inv)
				{
					continue;
				}
				List<InventoryElement> list = GuiAccess.Elements(val2);
				if (list == null)
				{
					continue;
				}
				foreach (InventoryElement item in list)
				{
					if (!Object.op_Implicit((Object)(object)item))
					{
						continue;
					}
					RectTransform elementRectTransform = item.GetElementRectTransform();
					if (Object.op_Implicit((Object)(object)elementRectTransform))
					{
						Rect rect = elementRectTransform.rect;
						if (((Rect)(ref rect)).Contains(((Transform)elementRectTransform).InverseTransformPoint(Vector2.op_Implicit(val))))
						{
							return inv.GetItemAt(item.Position.x, item.Position.y);
						}
					}
				}
			}
			return null;
		}

		private static void Refresh()
		{
			InventoryGui instance = InventoryGui.instance;
			if (Object.op_Implicit((Object)(object)instance) && InventoryGui.IsVisible() && GuiAccess.Ok)
			{
				GuiAccess.RefreshCrafting(instance);
			}
		}
	}
	[HarmonyPatch]
	internal static class KeyHints
	{
		private static RectTransform s_box;

		private static TMP_Text s_text;

		private static float s_nextText;

		private const string Key = "<color=#ffd84a>";

		private const string End = "</color>";

		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		[HarmonyPostfix]
		private static void AfterAwake(InventoryGui __instance)
		{
			s_box = null;
			if (!Object.op_Implicit((Object)(object)__instance.m_player) || !Object.op_Implicit((Object)(object)__instance.m_armor))
			{
				return;
			}
			try
			{
				Build(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Couldn't add the key hints: " + ex));
				if (Object.op_Implicit((Object)(object)s_box))
				{
					Object.Destroy((Object)(object)((Component)s_box).gameObject);
				}
				s_box = null;
			}
		}

		private static void Build(InventoryGui gui)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			Transform val = (Object.op_Implicit((Object)(object)gui.m_weight) ? TrashCan.TabOf(gui.m_armor.transform, gui.m_weight.transform) : null);
			GameObject val2 = new GameObject("OdinsReclaim_KeyHints", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent((Transform)(Object.op_Implicit((Object)(object)val) ? ((object)val.parent) : ((object)gui.m_player)), false);
			val2.transform.SetAsLastSibling();
			s_box = (RectTransform)val2.transform;
			s_box.pivot = new Vector2(0f, 1f);
			s_box.sizeDelta = new Vector2(380f, 100f);
			Image obj = val2.AddComponent<Image>();
			((Graphic)obj).color = new Color(0.08f, 0.06f, 0.04f, 0.78f);
			((Graphic)obj).raycastTarget = false;
			GameObject val3 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val3.transform.SetParent(val2.transform, false);
			RectTransform val4 = (RectTransform)val3.transform;
			val4.anchorMin = Vector2.zero;
			val4.anchorMax = Vector2.one;
			val4.offsetMin = new Vector2(12f, 6f);
			val4.offsetMax = new Vector2(-12f, -6f);
			TextMeshProUGUI obj2 = val3.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj2).font = gui.m_armor.font;
			((TMP_Text)obj2).fontSharedMaterial = gui.m_armor.fontSharedMaterial;
			((TMP_Text)obj2).enableAutoSizing = true;
			((TMP_Text)obj2).fontSizeMin = 11f;
			((TMP_Text)obj2).fontSizeMax = 17f;
			((TMP_Text)obj2).alignment = (TextAlignmentOptions)4097;
			((Graphic)obj2).color = new Color(0.93f, 0.88f, 0.76f);
			((TMP_Text)obj2).richText = true;
			((Graphic)obj2).raycastTarget = false;
			s_text = (TMP_Text)(object)obj2;
			val2.SetActive(false);
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateInventory")]
		[HarmonyPostfix]
		private static void AfterUpdateInventory(InventoryGui __instance)
		{
			//IL_007c: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)s_box))
			{
				return;
			}
			List<string> list = (Settings.ShowKeyHints.Value ? Lines() : null);
			bool flag = list != null && list.Count > 0;
			if (((Component)s_box).gameObject.activeSelf != flag)
			{
				((Component)s_box).gameObject.SetActive(flag);
				s_nextText = 0f;
			}
			if (flag)
			{
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				__instance.m_player.GetWorldCorners(array);
				((Transform)s_box).position = array[3];
				RectTransform obj = s_box;
				obj.anchoredPosition += new Vector2(8f, -8f) + Settings.KeyHintsOffset.Value;
				if (!(Time.unscaledTime < s_nextText))
				{
					s_nextText = Time.unscaledTime + 1f;
					s_text.text = string.Join("\n", list);
					s_box.sizeDelta = new Vector2(380f, 14f + 22f * (float)list.Count);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		[HarmonyPostfix]
		private static void AfterHide()
		{
			if (Object.op_Implicit((Object)(object)s_box))
			{
				((Component)s_box).gameObject.SetActive(false);
			}
		}

		private static List<string> Lines()
		{
			//IL_001a: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			if (Settings.TrashEnabled.Value && (int)Settings.TrashHoldKey.Value != 0)
			{
				string text = Settings.KeyText(Settings.TrashHoldKey.Value);
				list.Add("Hold <color=#ffd84a>" + text + "</color> + <color=#ffd84a>right-click</color>: mark items to delete");
				if ((int)Settings.TrashDeleteKey.Value != 0)
				{
					list.Add("Hold <color=#ffd84a>" + text + "</color> + <color=#ffd84a>" + Settings.KeyText(Settings.TrashDeleteKey.Value).ToLowerInvariant() + "</color>: delete the marked items");
				}
			}
			if (Settings.TrashCanEnabled.Value)
			{
				list.Add("Pick an item up, click the <color=#ffd84a>trash can</color>: delete it");
			}
			if (Settings.KeyEnabled.Value && (!Settings.KeyAdminsOnly.Value || SynchronizationManager.Instance.PlayerIsAdmin))
			{
				list.Add("<color=#ffd84a>" + Settings.ShortcutText(Settings.KeyShortcut.Value) + "</color>: delete the item under the mouse, get its materials");
			}
			if (Settings.UndoSeconds.Value > 0)
			{
				KeyboardShortcut value = Settings.UndoShortcut.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
				{
					list.Add("<color=#ffd84a>" + Settings.ShortcutText(Settings.UndoShortcut.Value) + "</color>: undo");
				}
			}
			return list;
		}
	}
	internal static class Moves
	{
		internal static bool Fits(Inventory inv, List<Output> outputs, int freedSlots)
		{
			int num = inv.GetEmptySlots() + freedSlots;
			foreach (Output output in outputs)
			{
				SharedData shared = output.Item.m_itemData.m_shared;
				int num2 = Mathf.Max(1, shared.m_maxStackSize);
				int num3 = output.Amount;
				if (num2 > 1)
				{
					num3 -= inv.FindFreeStackSpace(shared.m_name, (float)Game.m_worldLevel);
				}
				if (num3 > 0)
				{
					num -= (num3 + num2 - 1) / num2;
				}
			}
			return num >= 0;
		}

		internal static ItemData Take(Inventory inv, ItemData item, Humanoid owner)
		{
			if (inv == null || item == null || !inv.ContainsItem(item))
			{
				return null;
			}
			if (Object.op_Implicit((Object)(object)owner))
			{
				owner.RemoveEquipAction(item);
				if (item.m_equipped)
				{
					owner.UnequipItem(item, false);
				}
			}
			ItemData val = item.Clone();
			val.m_equipped = false;
			if (!inv.RemoveItem(item))
			{
				return null;
			}
			return val;
		}

		internal static ItemData TakeAmount(Inventory inv, ItemData item, int amount, Humanoid owner)
		{
			if (inv == null || item == null || !inv.ContainsItem(item) || amount <= 0)
			{
				return null;
			}
			if (amount >= item.m_stack)
			{
				return Take(inv, item, owner);
			}
			ItemData val = item.Clone();
			val.m_stack = amount;
			val.m_equipped = false;
			if (!inv.RemoveItem(item, amount))
			{
				return null;
			}
			return val;
		}

		internal static int Give(Inventory inv, List<Output> outputs, bool cheated, Vector3 dropAt, Player crafter = null)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			long crafterId = 0L;
			string crafterName = "";
			if (Object.op_Implicit((Object)(object)crafter) && Settings.ApplyCrafter.Value)
			{
				crafterId = crafter.GetPlayerID();
				crafterName = crafter.GetPlayerName();
			}
			int num = 0;
			foreach (Output output in outputs)
			{
				ItemData itemData = output.Item.m_itemData;
				int num2 = Mathf.Max(1, itemData.m_shared.m_maxStackSize);
				int num3 = output.Amount;
				while (num3 > 0)
				{
					int num4 = Mathf.Min(num3, num2);
					num3 -= num4;
					ItemData val = NewStack(output.Item, num4, cheated, crafterId, crafterName);
					if (!inv.AddItem(val) && val.m_stack > 0)
					{
						num += val.m_stack;
						ItemDrop.DropItem(val, val.m_stack, dropAt, Quaternion.identity);
					}
				}
			}
			return num;
		}

		private static ItemData NewStack(ItemDrop prefab, int amount, bool cheated, long crafterId, string crafterName)
		{
			ItemData val = prefab.m_itemData.Clone();
			val.m_dropPrefab = ((Component)prefab).gameObject;
			val.m_stack = amount;
			val.m_quality = Mathf.Max(1, val.m_quality);
			val.m_durability = val.GetMaxDurability();
			val.m_worldLevel = (byte)Game.m_worldLevel;
			val.m_equipped = false;
			val.m_cheated = cheated && !PlayerProfile.s_bypassCheatChecks;
			val.m_crafterID = crafterId;
			val.m_crafterName = crafterName ?? "";
			return val;
		}

		internal static bool TakeBack(Inventory inv, string sharedName, int amount)
		{
			List<ItemData> list = new List<ItemData>();
			int num = 0;
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (!(allItem.m_shared.m_name != sharedName) && !allItem.m_equipped)
				{
					list.Add(allItem);
					num += allItem.m_stack;
				}
			}
			if (num < amount)
			{
				return false;
			}
			list.Sort((ItemData a, ItemData b) => a.m_stack.CompareTo(b.m_stack));
			foreach (ItemData item in list)
			{
				if (amount <= 0)
				{
					break;
				}
				int num2 = Mathf.Min(item.m_stack, amount);
				if (inv.RemoveItem(item, num2))
				{
					amount -= num2;
				}
			}
			return amount <= 0;
		}

		internal static int Count(Inventory inv, string sharedName)
		{
			int num = 0;
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (allItem.m_shared.m_name == sharedName && !allItem.m_equipped)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		internal static void PutBack(Inventory inv, ItemData item, Vector3 dropAt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_004b: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			Vector2i gridPos = item.m_gridPos;
			if ((gridPos.x < 0 || gridPos.y < 0 || gridPos.x >= inv.GetWidth() || gridPos.y >= inv.GetHeight() || inv.GetItemAt(gridPos.x, gridPos.y) != null || !inv.AddItem(item, gridPos)) && !inv.AddItem(item) && item.m_stack > 0 && Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				ItemDrop.DropItem(item, item.m_stack, dropAt, Quaternion.identity);
				Plugin.Log.LogWarning((object)("Undo: no room for " + item.m_shared.m_name + ", dropped it at your feet"));
			}
		}

		internal static Vector3 Feet(Player p)
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)p).transform.position + Vector3.up;
		}
	}
	[BepInPlugin("com.odinthewise.odinsreclaim", "OdinsReclaim", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony _harmony;

		private float _nextErrorLog;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Settings.Bind(((BaseUnityPlugin)this).Config);
			GuiAccess.Init();
			_harmony = new Harmony("com.odinthewise.odinsreclaim");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"OdinsReclaim 1.0.0 loaded");
		}

		private void Update()
		{
			Banner.Tick();
			try
			{
				InventoryKeys.Tick();
			}
			catch (Exception ex)
			{
				if (!(Time.unscaledTime < _nextErrorLog))
				{
					_nextErrorLog = Time.unscaledTime + 10f;
					Log.LogError((object)("Inventory keys failed (check the keys in F1): " + ex));
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void Say(Player p, string text, bool always = false)
		{
			if (Object.op_Implicit((Object)(object)p) && (always || Settings.ShowReasons.Value) && !Banner.Show(text))
			{
				((Character)p).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		internal static string UndoHint()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (Settings.UndoSeconds.Value <= 0)
			{
				return "";
			}
			KeyboardShortcut value = Settings.UndoShortcut.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
			{
				return " (" + Settings.ShortcutText(value) + " to undo)";
			}
			return "";
		}
	}
	[HarmonyPatch]
	internal static class ReclaimTab
	{
		private static Button s_tab;

		private static bool s_hooked;

		private static float s_nextPress;

		private const float PressCooldown = 0.4f;

		internal static bool Active { get; private set; }

		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		[HarmonyPostfix]
		private static void AfterAwake(InventoryGui __instance)
		{
			Active = false;
			if (!GuiAccess.Ok || !Object.op_Implicit((Object)(object)__instance.m_tabUpgrade) || !Object.op_Implicit((Object)(object)__instance.m_tabCraft))
			{
				return;
			}
			try
			{
				s_tab = GuiAccess.CloneButton(__instance.m_tabUpgrade, "OdinsReclaim_Tab", "Reclaim", delegate
				{
					Open(__instance);
				});
				UITooltip component = ((Component)s_tab).GetComponent<UITooltip>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.m_text = "Break items back into materials";
				}
				Place(__instance);
				if (!s_hooked)
				{
					s_hooked = true;
					Settings.TabOffset.SettingChanged += delegate
					{
						Place(InventoryGui.instance);
					};
				}
				((Component)s_tab).gameObject.SetActive(false);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Couldn't add the Reclaim tab: " + ex));
				s_tab = null;
			}
		}

		private static void Place(InventoryGui gui)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)gui) && Object.op_Implicit((Object)(object)s_tab))
			{
				RectTransform val = (RectTransform)((Component)gui.m_tabUpgrade).transform;
				RectTransform val2 = (RectTransform)((Component)gui.m_tabCraft).transform;
				((RectTransform)((Component)s_tab).transform).anchoredPosition = val.anchoredPosition + (val.anchoredPosition - val2.anchoredPosition) + Settings.TabOffset.Value;
			}
		}

		private static bool Allowed(Player p)
		{
			if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)s_tab) || !GuiAccess.Ok || !Settings.TabEnabled.Value)
			{
				return false;
			}
			CraftingStation currentCraftingStation = p.GetCurrentCraftingStation();
			if (Object.op_Implicit((Object)(object)currentCraftingStation))
			{
				return currentCraftingStation.m_hasCraftTab;
			}
			return false;
		}

		private static void Open(InventoryGui gui)
		{
			if (Object.op_Implicit((Object)(object)gui) && Allowed(Player.m_localPlayer))
			{
				Active = true;
				((Selectable)gui.m_tabCraft).interactable = true;
				((Selectable)gui.m_tabUpgrade).interactable = true;
				((Selectable)s_tab).interactable = false;
				GuiAccess.RefreshCrafting(gui);
			}
		}

		private static void Leave(InventoryGui gui)
		{
			Active = false;
			((Selectable)gui.m_tabCraft).interactable = false;
			((Selectable)gui.m_tabUpgrade).interactable = true;
			if (Object.op_Implicit((Object)(object)s_tab))
			{
				((Selectable)s_tab).interactable = true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnTabCraftPressed")]
		[HarmonyPrefix]
		private static void BeforeCraftTab()
		{
			LeftByVanillaTab();
		}

		[HarmonyPatch(typeof(InventoryGui), "OnTabUpgradePressed")]
		[HarmonyPrefix]
		private static void BeforeUpgradeTab()
		{
			LeftByVanillaTab();
		}

		private static void LeftByVanillaTab()
		{
			Active = false;
			if (Object.op_Implicit((Object)(object)s_tab))
			{
				((Selectable)s_tab).interactable = true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
		[HarmonyPrefix]
		private static void BeforeCraftingPanel(InventoryGui __instance)
		{
			if (Object.op_Implicit((Object)(object)s_tab))
			{
				bool flag = Allowed(Player.m_localPlayer);
				if (!flag && Active)
				{
					Leave(__instance);
				}
				((Component)s_tab).gameObject.SetActive(flag);
				((Selectable)s_tab).interactable = !Active;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		[HarmonyPrefix]
		private static bool BeforeRecipeList(InventoryGui __instance)
		{
			if (!Active)
			{
				return true;
			}
			try
			{
				BuildList(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Reclaim list failed: " + ex));
			}
			return false;
		}

		private static void BuildList(InventoryGui gui)
		{
			GuiAccess.ClearList(gui);
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			List<Plan> list = new List<Plan>();
			foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
			{
				if ((Settings.TabHideEquipped.Value && allItem.m_equipped) || (Settings.TabHideHotbar.Value && allItem.m_gridPos.y == 0) || allItem.m_shared.m_questItem || (Settings.IsExcluded(allItem) && !Settings.IsAlwaysAllowed(allItem)))
				{
					continue;
				}
				Recipe val = Yields.FindRecipe(allItem);
				if (Object.op_Implicit((Object)(object)val) && val.m_enabled && !val.m_requireOnlyOneIngredient && (!Object.op_Implicit((Object)(object)val.m_craftingStation) || !Settings.IsExcludedStation(((Object)((Component)val.m_craftingStation).gameObject).name)))
				{
					CraftingStation requiredStation = val.GetRequiredStation(Mathf.Clamp(allItem.m_quality, 1, Mathf.Max(1, allItem.m_shared.m_maxQuality)));
					if (!Settings.NeedStation.Value || !Object.op_Implicit((Object)(object)requiredStation) || (Object.op_Implicit((Object)(object)currentCraftingStation) && !(requiredStation.m_name != currentCraftingStation.m_name)))
					{
						list.Add(Yields.Make(allItem, localPlayer, Way.Tab, currentCraftingStation));
					}
				}
			}
			list.Sort(delegate(Plan a, Plan b)
			{
				int num = b.Ok.CompareTo(a.Ok);
				if (num == 0)
				{
					num = string.Compare(Localization.instance.Localize(a.Source.m_shared.m_name), Localization.instance.Localize(b.Source.m_shared.m_name), StringComparison.CurrentCulture);
				}
				if (num == 0)
				{
					num = b.Source.m_quality.CompareTo(a.Source.m_quality);
				}
				return num;
			});
			foreach (Plan item in list)
			{
				GuiAccess.AddToList(gui, localPlayer, item.Recipe, item.Source, item.Ok);
				GameObject obj = GuiAccess.LastElement(gui);
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					Transform obj3 = obj.transform.Find("name");
					obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
				}
				TMP_Text val2 = (TMP_Text)obj2;
				if (Object.op_Implicit((Object)(object)val2))
				{
					val2.text = Localization.instance.Localize(item.Source.m_shared.m_name) + ((item.Source.m_stack > 1) ? (" x" + item.Source.m_stack) : "");
				}
			}
			GuiAccess.SizeList(gui);
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupRequirementList")]
		[HarmonyPrefix]
		private static bool BeforeRequirementList()
		{
			return !Active;
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
		[HarmonyPostfix]
		private static void AfterRecipe(InventoryGui __instance, Player player)
		{
			if (!Active)
			{
				return;
			}
			try
			{
				if (!Allowed(player))
				{
					Leave(__instance);
					GuiAccess.RefreshCrafting(__instance);
				}
				else
				{
					ShowSelected(__instance, player);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Reclaim panel failed, back to the Craft tab: " + ex));
				Leave(__instance);
			}
		}

		private static void ShowSelected(InventoryGui gui, Player player)
		{
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			GuiAccess.Selected(gui, out var recipe, out var item);
			TMP_Text componentInChildren = ((Component)gui.m_craftButton).GetComponentInChildren<TMP_Text>();
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				componentInChildren.text = "Reclaim";
			}
			if (Object.op_Implicit((Object)(object)gui.m_variantButton))
			{
				((Component)gui.m_variantButton).gameObject.SetActive(false);
			}
			UITooltip component = ((Component)gui.m_craftButton).GetComponent<UITooltip>();
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (!Object.op_Implicit((Object)(object)recipe) || item == null || !inventory.ContainsItem(item))
			{
				((Selectable)gui.m_craftButton).interactable = false;
				if (Object.op_Implicit((Object)(object)component))
				{
					component.m_text = "";
				}
				if (Object.op_Implicit((Object)(object)gui.m_itemCraftType))
				{
					((Component)gui.m_itemCraftType).gameObject.SetActive(false);
				}
				ShowOutputs(gui, null);
				return;
			}
			Plan plan = Yields.Make(item, player, Way.Tab, player.GetCurrentCraftingStation());
			bool flag = plan.Ok && Moves.Fits(inventory, plan.Outputs, 1);
			string text = ((!plan.Ok) ? plan.Problem : (flag ? null : "not enough room in your inventory for the materials"));
			string text2 = Localization.instance.Localize(item.m_shared.m_name);
			if (item.m_stack > 1)
			{
				text2 = text2 + " x" + item.m_stack;
			}
			gui.m_recipeName.text = text2;
			gui.m_recipeIcon.sprite = item.GetIcon();
			float num = Settings.RateFor(item, Settings.Rate.Value);
			if (item.m_shared.m_maxStackSize > 1)
			{
				num = Mathf.Min(num, Settings.StackRateCap.Value);
			}
			string text3 = $"<color=orange>Reclaim: get back {Mathf.RoundToInt(num * 100f)}% of what it took to make" + ((item.m_quality > 1) ? $" and upgrade it to level {item.m_quality}" : "") + ".</color>";
			if (text != null)
			{
				text3 = text3 + "\n<color=red>Can't reclaim: " + text + ".</color>";
			}
			gui.m_recipeDecription.text = text3 + "\n\n" + Localization.instance.Localize(ItemData.GetTooltip(item, item.m_quality, false, (float)Game.m_worldLevel, -1, false));
			if (Object.op_Implicit((Object)(object)gui.m_itemCraftType))
			{
				((Component)gui.m_itemCraftType).gameObject.SetActive(true);
				gui.m_itemCraftType.text = ((text == null) ? "Reclaim" : "Can't reclaim");
			}
			if (Object.op_Implicit((Object)(object)gui.m_minStationLevelIcon))
			{
				bool flag2 = Object.op_Implicit((Object)(object)plan.NeedStation) && plan.NeedLevel > 1;
				((Component)gui.m_minStationLevelIcon).gameObject.SetActive(flag2);
				if (flag2 && Object.op_Implicit((Object)(object)gui.m_minStationLevelText))
				{
					CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
					gui.m_minStationLevelText.text = plan.NeedLevel.ToString();
					((Graphic)gui.m_minStationLevelText).color = ((Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.GetLevel(true) >= plan.NeedLevel) ? Color.white : Color.red);
				}
			}
			ShowOutputs(gui, plan.Ok ? plan.Outputs : null);
			((Selectable)gui.m_craftButton).interactable = text == null && GuiAccess.CraftTimer(gui) < 0f;
			if (Object.op_Implicit((Object)(object)component))
			{
				component.m_text = text ?? "";
			}
		}

		private static void ShowOutputs(InventoryGui gui, List<Output> outputs)
		{
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			GameObject[] recipeRequirementList = gui.m_recipeRequirementList;
			int num = outputs?.Count ?? 0;
			int num2 = 0;
			if (num > recipeRequirementList.Length && recipeRequirementList.Length != 0)
			{
				int num3 = (num + recipeRequirementList.Length - 1) / recipeRequirementList.Length;
				num2 = (int)Time.fixedTime % num3 * recipeRequirementList.Length;
			}
			for (int i = 0; i < recipeRequirementList.Length; i++)
			{
				Transform transform = recipeRequirementList[i].transform;
				Transform obj = transform.Find("res_icon");
				Image val = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
				Transform obj2 = transform.Find("res_name");
				TMP_Text val2 = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null);
				Transform obj3 = transform.Find("res_amount");
				TMP_Text val3 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
				UITooltip component = ((Component)transform).GetComponent<UITooltip>();
				int num4 = num2 + i;
				bool flag = num4 < num;
				if (Object.op_Implicit((Object)(object)val))
				{
					((Component)val).gameObject.SetActive(flag);
				}
				if (Object.op_Implicit((Object)(object)val2))
				{
					((Component)val2).gameObject.SetActive(flag);
				}
				if (Object.op_Implicit((Object)(object)val3))
				{
					((Component)val3).gameObject.SetActive(flag);
				}
				if (!flag)
				{
					if (Object.op_Implicit((Object)(object)component))
					{
						component.m_text = "";
					}
					continue;
				}
				Output output = outputs[num4];
				string text = Localization.instance.Localize(output.Name);
				if (Object.op_Implicit((Object)(object)val))
				{
					val.sprite = output.Item.m_itemData.GetIcon();
					((Graphic)val).color = Color.white;
				}
				if (Object.op_Implicit((Object)(object)val2))
				{
					val2.text = text;
				}
				if (Object.op_Implicit((Object)(object)val3))
				{
					val3.text = "+" + output.Amount;
					((Graphic)val3).color = Color.green;
				}
				if (Object.op_Implicit((Object)(object)component))
				{
					component.m_text = text;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")]
		[HarmonyPrefix]
		private static bool BeforeCraftPressed(InventoryGui __instance)
		{
			if (!Active)
			{
				return true;
			}
			try
			{
				ReclaimSelected(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Reclaim failed: " + ex));
			}
			return false;
		}

		private static void ReclaimSelected(InventoryGui gui)
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || GuiAccess.CraftTimer(gui) >= 0f || Time.unscaledTime < s_nextPress)
			{
				return;
			}
			s_nextPress = Time.unscaledTime + 0.4f;
			GuiAccess.Selected(gui, out var _, out var item);
			if (item == null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			Plan plan = Yields.Make(item, localPlayer, Way.Tab, currentCraftingStation);
			if (!plan.Ok)
			{
				Plugin.Say(localPlayer, "Can't reclaim: " + plan.Problem);
				return;
			}
			if (!Moves.Fits(inventory, plan.Outputs, 1))
			{
				Plugin.Say(localPlayer, "Not enough room in your inventory for the materials");
				return;
			}
			string text = Localization.instance.Localize(item.m_shared.m_name);
			ItemData val = Moves.Take(inventory, item, (Humanoid)(object)localPlayer);
			if (val == null)
			{
				GuiAccess.RefreshCrafting(gui);
				return;
			}
			Undo.Entry e = Undo.Record(localPlayer, inventory, new List<ItemData> { val }, plan.Outputs, "reclaimed " + text);
			int num;
			try
			{
				num = Moves.Give(inventory, plan.Outputs, val.m_cheated, Moves.Feet(localPlayer), localPlayer);
			}
			catch (Exception arg)
			{
				Undo.Forget(e);
				Moves.PutBack(inventory, val, Moves.Feet(localPlayer));
				Plugin.Log.LogError((object)$"Reclaiming {text} failed half-way, the item was put back: {arg}");
				Plugin.Say(localPlayer, "Something went wrong; " + text + " was put back", always: true);
				Refresh(gui);
				return;
			}
			if (num > 0)
			{
				Undo.Forget(e);
			}
			if (Object.op_Implicit((Object)(object)currentCraftingStation))
			{
				currentCraftingStation.m_craftItemDoneEffects.Create(((Component)localPlayer).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			}
			Plugin.Say(localPlayer, "Reclaimed " + text + ": " + plan.OutputText() + ((num > 0) ? " (some fell at your feet)" : Plugin.UndoHint()), always: true);
			if (Settings.LogActions.Value)
			{
				Plugin.Log.LogInfo((object)($"Reclaim tab: {Yields.PrefabName(val)} q{val.m_quality} x{val.m_stack} -> {plan.OutputText()}" + ((num > 0) ? $" ({num} dropped)" : "")));
			}
			Refresh(gui);
		}

		private static void Refresh(InventoryGui gui)
		{
			GuiAccess.RefreshCrafting(gui);
			GuiAccess.ClearSelection(gui);
		}
	}
	internal static class Settings
	{
		internal static ConfigEntry<float> Rate;

		internal static ConfigEntry<string> RateOverrides;

		internal static ConfigEntry<string> ExcludeItems;

		internal static ConfigEntry<string> ExcludeStations;

		internal static ConfigEntry<bool> AllowUnknownRecipes;

		internal static ConfigEntry<bool> AtLeastOne;

		internal static ConfigEntry<bool> ProtectEnchanted;

		internal static ConfigEntry<bool> NeedStationLevel;

		internal static ConfigEntry<float> StackRateCap;

		internal static ConfigEntry<string> AlwaysAllow;

		internal static ConfigEntry<string> CustomGroups;

		internal static ConfigEntry<bool> NeedStation;

		internal static ConfigEntry<bool> EpicLootRefund;

		internal static ConfigEntry<bool> ApplyCrafter;

		internal static ConfigEntry<bool> TabEnabled;

		internal static ConfigEntry<bool> TabHideEquipped;

		internal static ConfigEntry<bool> TabHideHotbar;

		internal static ConfigEntry<Vector2> TabOffset;

		internal static ConfigEntry<bool> ChestEnabled;

		internal static ConfigEntry<Vector2> ChestButtonPos;

		internal static ConfigEntry<bool> ChestSingleOnly;

		internal static ConfigEntry<string> ChestRules;

		internal static ConfigEntry<bool> KeyEnabled;

		internal static ConfigEntry<bool> KeyAdminsOnly;

		internal static ConfigEntry<float> KeyRate;

		internal static ConfigEntry<bool> KeyRefundUnknown;

		internal static ConfigEntry<KeyboardShortcut> KeyShortcut;

		internal static ConfigEntry<bool> TrashEnabled;

		internal static ConfigEntry<KeyCode> TrashHoldKey;

		internal static ConfigEntry<KeyCode> TrashDeleteKey;

		internal static ConfigEntry<Color> TrashColor;

		internal static ConfigEntry<bool> TrashCanEnabled;

		internal static ConfigEntry<bool> TrashCanConfirm;

		internal static ConfigEntry<Vector2> TrashCanOffset;

		internal static ConfigEntry<int> UndoSeconds;

		internal static ConfigEntry<KeyboardShortcut> UndoShortcut;

		internal static ConfigEntry<bool> ShowReasons;

		internal static ConfigEntry<bool> TooltipYield;

		internal static ConfigEntry<bool> LogActions;

		internal static ConfigEntry<Vector2> BannerOffset;

		internal static ConfigEntry<bool> ShowKeyHints;

		internal static ConfigEntry<Vector2> KeyHintsOffset;

		private const string GroupNote = " Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups.";

		private static List<string> s_itemCache;

		private static List<string> s_allowCache;

		private static HashSet<string> s_stationCache;

		private static List<KeyValuePair<string, float>> s_rateCache;

		private static Dictionary<string, List<string>> s_chestCache;

		public static void Bind(ConfigFile cfg)
		{
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_047c: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0555: Unknown result type (might be due to invalid IL or missing references)
			Rate = Synced(cfg, "1 - Rules", "Return rate", 0.5f, "Share of the materials you get back when you reclaim at a crafting station (Reclaim tab and the chest button). 0.5 = half. Amounts round down. Upgraded items give back their upgrade materials too.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f));
			RateOverrides = Synced(cfg, "1 - Rules", "Return rate per item", "", "Optional rates for items or groups: SwordIron=1, Armor=0.75. They replace the return rate for those items (every way of reclaiming). An item's own name wins over a group; otherwise the first matching group counts. Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups.");
			ExcludeItems = Synced(cfg, "1 - Rules", "Never reclaim these items", "", "Items or groups, separated by commas (for example: Hammer, Hoe, Tools, Metals). These are never broken down. The Delete key and the trash can still delete them, without giving anything back. Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups.");
			AlwaysAllow = Synced(cfg, "1 - Rules", "Always allow these items", "", "Items or groups that may always be reclaimed, even when the never list or a chest rule covers them (for example: never Armor, but always ArmorBronzeChest). Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups.");
			CustomGroups = Synced(cfg, "1 - Rules", "Custom groups", "", "Your own groups for the lists above, separated by semicolons: Tier 2 = Bronze, PickaxeBronze, ArmorBronzeChest; Starter = Club, Torch. A group may name other groups.");
			ExcludeStations = Synced(cfg, "1 - Rules", "Never reclaim items made at", "piece_cauldron, piece_preptable, piece_MeadCauldron", "Crafting stations by prefab name; everything made there is left alone (by default food and meads). Others: piece_workbench, forge, piece_stonecutter, piece_artisanstation, blackforge, piece_magetable.");
			AllowUnknownRecipes = Synced(cfg, "1 - Rules", "Allow items whose recipe you do not know", def: false, "Off: you can only reclaim items you could craft yourself (you know the recipe). On: any item with a recipe.");
			AtLeastOne = Synced(cfg, "1 - Rules", "Single items give back at least 1 of each material", def: true, "A non-stacking item (weapon, armour, tool) gives at least 1 of every material in its recipe, even when the return rate rounds it down to 0.");
			ProtectEnchanted = Synced(cfg, "1 - Rules", "Protect Epic Loot items", def: false, "On: items enchanted with Epic Loot are never reclaimed, and the Delete key and trash can won't delete them (trash marking still does, on purpose). Off: they can be reclaimed like any item.");
			EpicLootRefund = Synced(cfg, "1 - Rules", "Epic Loot: give back enchanting materials", def: true, "Reclaiming an item enchanted with Epic Loot also gives back what enchanting it at its rarity costs (Epic Loot's own enchant costs), at the same return rate. Off: only the item's recipe comes back.");
			NeedStation = Synced(cfg, "1 - Rules", "Need the right crafting station", def: true, "On: the Reclaim tab only shows items made at the station you are using, and Reclaim all needs that station nearby. Off: crafting stations don't matter at all.");
			ApplyCrafter = Synced(cfg, "1 - Rules", "You are the crafter of returned materials", def: true, "On: materials you get back carry your name as their crafter. Off: no crafter, like picked-up materials.");
			NeedStationLevel = Synced(cfg, "1 - Rules", "Need the station level the item needs", def: true, "On: reclaiming an item needs the sam