Decompiled source of Recycle N Reclaim v1.3.5

Recycle_N_Reclaim.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Auga;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Jewelcrafting;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using Recycle_N_Reclaim.GamePatches.MarkAsTrash;
using Recycle_N_Reclaim.GamePatches.Recycling;
using Recycle_N_Reclaim.GamePatches.UI;
using Recycle_N_Reclaim.YAMLStuff;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: AssemblyDescription("")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyProduct("Recycle_N_Reclaim")]
[assembly: AssemblyCompany("Azumatt")]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyConfiguration("")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyTitle("Recycle_N_Reclaim")]
[assembly: AssemblyFileVersion("1.3.5")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.5.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[<59ee7180-282a-4211-9143-92bdb4a1f8d1>Embedded]
	[CompilerGenerated]
	internal sealed class <59ee7180-282a-4211-9143-92bdb4a1f8d1>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<59ee7180-282a-4211-9143-92bdb4a1f8d1>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <3f607022-9496-490a-85e6-01cde9ffb3e4>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <3f607022-9496-490a-85e6-01cde9ffb3e4>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <3f607022-9496-490a-85e6-01cde9ffb3e4>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[<59ee7180-282a-4211-9143-92bdb4a1f8d1>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace LocalizationManager
{
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[PublicAPI]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(2)]
		private static BaseUnityPlugin _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out var value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out var value2))
			{
				text = value2.Aggregate(text, [<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null)
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += [<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (object _, EventArgs _) =>
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage());
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string text = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' })[1];
				if (dictionary.ContainsKey(text))
				{
					Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
				}
				else
				{
					dictionary[text] = item;
				}
			}
			byte[] array = LoadTranslationFromAssembly("English");
			if (array == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml.");
			}
			Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array));
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.ContainsKey(language))
				{
					text2 = File.ReadAllText(dictionary[language]);
				}
				else
				{
					byte[] array2 = LoadTranslationFromAssembly(language);
					if (array2 != null)
					{
						text2 = Encoding.UTF8.GetString(array2);
					}
				}
			}
			if (text2 == null && dictionary.ContainsKey("English"))
			{
				text2 = File.ReadAllText(dictionary["English"]);
			}
			if (text2 != null)
			{
				foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string> { ".json", ".yml" };
			new Harmony("org.bepinex.helpers.LocalizationManager").Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		[return: <3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(2)]
		private static byte[] LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(2)]
		public static byte[] ReadEmbeddedFileBytes([<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(1)] string resourceFileName, Assembly containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
}
namespace Recycle_N_Reclaim
{
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[BepInPlugin("Azumatt.Recycle_N_Reclaim", "Recycle_N_Reclaim", "1.3.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Recycle_N_ReclaimPlugin : BaseUnityPlugin
	{
		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)]
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[UsedImplicitly]
			public string Category;

			[UsedImplicitly]
			public Action<ConfigEntryBase> CustomDrawer;
		}

		[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
		private class AcceptableShortcuts : AcceptableValueBase
		{
			public AcceptableShortcuts()
				: base(typeof(KeyboardShortcut))
			{
			}

			public override object Clamp(object value)
			{
				return value;
			}

			public override bool IsValid(object value)
			{
				return true;
			}

			public override string ToDescriptionString()
			{
				return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes);
			}
		}

		internal const string ModName = "Recycle_N_Reclaim";

		internal const string ModVersion = "1.3.5";

		internal const string Author = "Azumatt";

		private const string ModGUID = "Azumatt.Recycle_N_Reclaim";

		private static string ConfigFileName = "Azumatt.Recycle_N_Reclaim.cfg";

		private static string ConfigFileFullPath;

		[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(2)]
		internal static Assembly epicLootAssembly;

		internal static string ConnectionError;

		public static bool HasAuga;

		private ContainerRecyclingButtonHolder _containerRecyclingButton;

		private readonly Harmony _harmony = new Harmony("Azumatt.Recycle_N_Reclaim");

		public static readonly ManualLogSource Recycle_N_ReclaimLogger;

		internal static readonly ConfigSync ConfigSyncVar;

		internal static readonly string yamlFileName;

		internal static readonly string yamlPath;

		internal static readonly CustomSyncedValue<string> RNRExcludeListData;

		internal static Root yamlData;

		internal static Dictionary<string, HashSet<string>> predefinedGroups;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		public static ConfigEntry<KeyboardShortcut> hotKey;

		public static ConfigEntry<Toggle> discardInvEnabled;

		public static ConfigEntry<Toggle> lockToAdmin;

		public static ConfigEntry<Toggle> returnUnknownResources;

		public static ConfigEntry<Toggle> returnEnchantedResources;

		public static ConfigEntry<float> returnResources;

		private ConfigEntry<string> _stationFilterListString;

		public static List<string> StationFilterList;

		public static ConfigEntry<Toggle> StationFilterEnabled;

		public static ConfigEntry<Toggle> EnableExperimentalCraftingTabUI;

		public static ConfigEntry<Toggle> NotifyOnSalvagingImpediments;

		public static ConfigEntry<Toggle> PreventZeroResourceYields;

		public static ConfigEntry<Toggle> UnstackableItemsAlwaysReturnAtLeastOneResource;

		public static ConfigEntry<float> RecyclingRate;

		public static ConfigEntry<Toggle> ContainerRecyclingEnabled;

		public static ConfigEntry<Toggle> IgnoreItemsOnHotbar;

		public static ConfigEntry<Vector3> ContainerRecyclingButtonPositionJsonString;

		public static ConfigEntry<Toggle> AllowRecyclingUnknownRecipes;

		public static ConfigEntry<Toggle> DebugAlwaysDumpAnalysisContext;

		public static ConfigEntry<Toggle> DebugAllowSpammyLogs;

		public static ConfigEntry<Toggle> HideEquippedItemsInRecyclingTab;

		public static ConfigEntry<Toggle> RequireExactCraftingStationForRecycling;

		public static ConfigEntry<Toggle> returnEnchantedResourcesReclaiming;

		public static ConfigEntry<Color> BorderColorTrashedItem;

		public static ConfigEntry<Color> BorderColorTrashedSlot;

		public static ConfigEntry<bool> DisplayTooltipHint;

		public static ConfigEntry<KeyboardShortcut> TrashingModifierKeybind1;

		public static ConfigEntry<KeyboardShortcut> TrashingKeybind;

		public static ConfigEntry<string> TrashedSlotTooltip;

		public static StationRecyclingTabHolder RecyclingTabButtonHolder { get; private set; }

		private ConfigEntry<string> StationFilterListString
		{
			get
			{
				return _stationFilterListString;
			}
			set
			{
				_stationFilterListString = value;
				value.SettingChanged += [<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (object sender, EventArgs args) =>
				{
					SplitNewValueAndSetProperty();
				};
				SplitNewValueAndSetProperty();
				void SplitNewValueAndSetProperty()
				{
					StationFilterList = (from entry in value.Value.Split(new char[1] { ',' })
						select entry.Trim()).ToList();
				}
			}
		}

		public void Awake()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00bb: 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_00da: Expected O, but got Unknown
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			Game.isModded = true;
			Localizer.Load();
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSyncVar.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			string group = "2 - Inventory Recycle";
			discardInvEnabled = config(group, "Enabled", Toggle.On, new ConfigDescription("If on, you'll be able to discard things inside of the player inventory.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 2
				}
			}));
			lockToAdmin = config(group, "Lock to Admin", Toggle.On, new ConfigDescription("If on, only admin's can use this feature.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1
				}
			}));
			hotKey = config<KeyboardShortcut>(group, "DiscardHotkey(s)", new KeyboardShortcut((KeyCode)127, Array.Empty<KeyCode>()), new ConfigDescription("The hotkey to discard an item or regain resources. Must be enabled", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()), synchronizedSetting: false);
			returnUnknownResources = config(group, "ReturnUnknownResources", Toggle.Off, "If on, discarding an item in the inventory will return resources if recipe is unknown");
			returnEnchantedResources = config(group, "ReturnEnchantedResources", Toggle.On, "If on and Epic Loot or Jewelcrafting is installed, discarding an item in the inventory will return resources for Epic Loot enchantments or Jewelcrafting gems");
			returnResources = config(group, "ReturnResources", 1f, "Fraction of resources to return (0.0 - 1.0). This setting is forced to be between 0 and 1. Any higher or lower values will be set to 0 or 1 respectively.");
			returnResources.SettingChanged += [<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (object sender, EventArgs args) =>
			{
				if (returnResources.Value > 1f)
				{
					returnResources.Value = 1f;
				}
				if (returnResources.Value < 0f)
				{
					returnResources.Value = 0f;
				}
			};
			string text = "While this & right click are held, hovering over items marks them for trashing. Releasing this will cancel trashing for all items.";
			BorderColorTrashedSlot = config<Color>(group, "BorderColorTrashedItem", new Color(1f, 0f, 0f), "Color of the border for slots containing Trashed items.", synchronizedSetting: false);
			DisplayTooltipHint = config(group, "DisplayTooltipHint", value: true, "Whether to add additional info the item tooltip of a Trashed or trash flagged item.", synchronizedSetting: false);
			TrashingKeybind = config<KeyboardShortcut>(group, "TrashingKeybind", new KeyboardShortcut((KeyCode)325, Array.Empty<KeyCode>()), "Key(s) that when pressed while holding your modifier key will trash all items marked as trash. Default setting is middle mouse click", synchronizedSetting: false);
			TrashingModifierKeybind1 = config<KeyboardShortcut>(group, "TrashingModifierKeybind1", new KeyboardShortcut((KeyCode)120, Array.Empty<KeyCode>()), text + ".", synchronizedSetting: false);
			TrashedSlotTooltip = config(group, "TrashedSlotTooltip", "Slot is Trashed and will be a part of the bulk delete", string.Empty, synchronizedSetting: false);
			RecyclingRate = config("3 - Reclaiming", "RecyclingRate", 0.5f, "Rate at which the resources are recycled. Value must be between 0 and 1.\nThe mod always rolls *down*, so if you were supposed to get 2.5 items, you would only receive 2. If the recycling rate is 0.5 (50%), the player will receive half of the resources they would usually need to craft the item, assuming a single item in a stack and the item is of quality level 1. If the item is of higher quality, the resulting yield would be higher as well.");
			RecyclingRate.SettingChanged += [<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (object sender, EventArgs args) =>
			{
				if (RecyclingRate.Value > 1f)
				{
					RecyclingRate.Value = 1f;
				}
				if (RecyclingRate.Value < 0f)
				{
					RecyclingRate.Value = 0f;
				}
			};
			UnstackableItemsAlwaysReturnAtLeastOneResource = config("3 - Reclaiming", "UnstackableItemsAlwaysReturnAtLeastOneResource", Toggle.On, "If enabled and recycling a specific _unstackable_ item would yield 0 of a material,\ninstead you will receive 1. If disabled, you get nothing.");
			RequireExactCraftingStationForRecycling = config("3 - Reclaiming", "RequireExactCraftingStationForRecycling", Toggle.On, "If enabled, recycling will also check for the required crafting station type and level.\nIf disabled, will ignore all crafting station requirements altogether.\nEnabled by default, to keep things close to how Valheim operates.");
			returnEnchantedResourcesReclaiming = config("3 - Reclaiming", "ReturnEnchantedResources", Toggle.On, "If on and Epic Loot or Jewelcrafting is installed, discarding an item in the inventory will return resources for Epic Loot enchantments or Jewelcrafting gems");
			PreventZeroResourceYields = config("3 - Reclaiming", "PreventZeroResourceYields", Toggle.On, "If enabled and recycling an item that would yield 0 of any material,\ninstead you will receive 1. If disabled, you get nothing.");
			AllowRecyclingUnknownRecipes = config("3 - Reclaiming", "AllowRecyclingUnknownRecipes", Toggle.Off, "If enabled, it will allow you to recycle items that you do not know the recipe for yet.\nDisabled by default as this can be cheaty, but sometimes required due to people losing progress.");
			ContainerRecyclingButtonPositionJsonString = config<Vector3>("4 - UI", "ContainerButtonPosition", new Vector3(496f, -374f, -1f), "The last saved recycling button position stored in JSON");
			ContainerRecyclingEnabled = config("4 - UI", "ContainerRecyclingEnabled", Toggle.On, "If enabled, the mod will display the container recycling button");
			NotifyOnSalvagingImpediments = config("4 - UI", "NotifyOnSalvagingImpediments", Toggle.On, "If enabled and recycling a specific item runs into any issues, the mod will print a message\nin the center of the screen (native Valheim notification). At the time of implementation,\nthis happens in the following cases:\n - not enough free slots in the inventory to place the resulting resources\n - player does not know the recipe for the item\n - if enabled, cases when `PreventZeroResourceYields` kicks in and prevent the crafting");
			EnableExperimentalCraftingTabUI = config("4 - UI", "EnableExperimentalCraftingTabUI", Toggle.On, "If enabled, will display the experimental work in progress crafting tab UI\nEnabled by default.");
			HideEquippedItemsInRecyclingTab = config("4 - UI", "HideRecipesForEquippedItems", Toggle.On, "If enabled, it will hide equipped items in the crafting tab.\nThis does not make the item recyclable and only influences whether or not it's shown.\nEnabled by default.");
			IgnoreItemsOnHotbar = config("4 - UI", "IgnoreItemsOnHotbar", Toggle.On, "If enabled, it will hide hotbar items in the crafting tab.\nEnabled by default.");
			StationFilterEnabled = config("4 - UI", "StationFilterEnabled", Toggle.On, "If enabled, will filter all recycling recipes based on the crafting station\nused to produce said item. Main purpose of this is to prevent showing food\nas a recyclable item, but can be extended further if needed.\nEnabled by default");
			StationFilterListString = config("4 - UI", "StationFilterList", "piece_cauldron", "Comma separated list of crafting stations (by their \"prefab name\")\nrecipes from which should be ignored in regards to recycling.\nMain purpose of this is to prevent showing food as a recyclable item,\nbut can be extended further if needed.\n\nFull list of stations used in recipes as of 0.216.9:\n- identifier: `forge` in game name: Forge\n- identifier: `blackforge` in game name: Black Forge\n- identifier: `piece_workbench` in game name: Workbench\n- identifier: `piece_cauldron` in game name: Cauldron\n- identifier: `piece_stonecutter` in game name: Stonecutter\n- identifier: `piece_artisanstation` in game name: Artisan table\n- identifier: `piece_magetable` in game name: Galdr table\n");
			DebugAlwaysDumpAnalysisContext = config("zDebug", "DebugAlwaysDumpAnalysisContext", Toggle.Off, "If enabled will dump a complete detailed recycling report every time. This is taxing in terms\nof performance and should only be used when debugging issues. ");
			DebugAllowSpammyLogs = config("zDebug", "DebugAllowSpammyLogs", Toggle.Off, "If enabled, will spam recycling checks to the console.\nVERY. VERY. SPAMMY. Influences performance. ");
			if (!File.Exists(yamlPath))
			{
				YAMLUtils.WriteConfigFileFromResource(yamlPath);
			}
			RNRExcludeListData.ValueChanged += OnValChangedUpdate;
			RNRExcludeListData.AssignLocalValue(File.ReadAllText(yamlPath));
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
		}

		private void Start()
		{
			InventoryGridUpdateGuiPatch.border = loadSprite("trashingborder.png");
			AutoDoc();
			HasAuga = Auga.API.IsLoaded();
			_containerRecyclingButton = ((Component)this).gameObject.AddComponent<ContainerRecyclingButtonHolder>();
			_containerRecyclingButton.OnRecycleAllTriggered += ContainerRecyclingTriggered;
			RecyclingTabButtonHolder = ((Component)this).gameObject.AddComponent<StationRecyclingTabHolder>();
			if (Chainloader.PluginInfos.ContainsKey("randyknapp.mods.epicloot"))
			{
				epicLootAssembly = ((object)Chainloader.PluginInfos["randyknapp.mods.epicloot"].Instance).GetType().Assembly;
				Recycle_N_ReclaimLogger.LogDebug((object)"Epic Loot found, providing compatibility");
			}
		}

		internal static Sprite loadSprite(string name)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = loadTexture(name);
			if ((Object)(object)val != (Object)null)
			{
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero);
			}
			return null;
		}

		private static Texture2D loadTexture(string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_001f: Expected O, but got Unknown
			Texture2D val = new Texture2D(0, 0);
			ImageConversion.LoadImage(val, ReadEmbeddedFileBytes("Assets." + name));
			return val;
		}

		private static byte[] ReadEmbeddedFileBytes(string name)
		{
			using MemoryStream memoryStream = new MemoryStream();
			Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + "." + name).CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private void AutoDoc()
		{
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
			FileSystemWatcher fileSystemWatcher2 = new FileSystemWatcher(Paths.ConfigPath, yamlFileName);
			fileSystemWatcher2.Changed += ReadYamlFiles;
			fileSystemWatcher2.Created += ReadYamlFiles;
			fileSystemWatcher2.Renamed += ReadYamlFiles;
			fileSystemWatcher2.IncludeSubdirectories = true;
			fileSystemWatcher2.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher2.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				Recycle_N_ReclaimLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				Recycle_N_ReclaimLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				Recycle_N_ReclaimLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private void ReadYamlFiles(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(yamlPath))
			{
				return;
			}
			try
			{
				Recycle_N_ReclaimLogger.LogDebug((object)"ReadConfigValues called");
				RNRExcludeListData.AssignLocalValue(File.ReadAllText(yamlPath));
			}
			catch
			{
				Recycle_N_ReclaimLogger.LogError((object)("There was an issue loading your " + yamlFileName));
				Recycle_N_ReclaimLogger.LogError((object)"Please check your entries for spelling and format!");
			}
		}

		private static void OnValChangedUpdate()
		{
			Recycle_N_ReclaimLogger.LogDebug((object)"OnValChanged called");
			try
			{
				YAMLUtils.ReadYaml(RNRExcludeListData.Value);
			}
			catch (Exception arg)
			{
				Recycle_N_ReclaimLogger.LogError((object)$"Failed to deserialize {yamlFileName}: {arg}");
			}
		}

		public static string Localize(string text)
		{
			return Localization.instance.Localize(text);
		}

		public static string Localize(string text, params string[] words)
		{
			return Localization.instance.Localize(text, words);
		}

		private void ContainerRecyclingTriggered()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			Container val = (Container)AccessTools.Field(typeof(InventoryGui), "m_currentContainer").GetValue(InventoryGui.instance);
			if (!((Object)(object)val == (Object)null))
			{
				Recycle_N_ReclaimLogger.LogDebug((object)("Player " + localPlayer.GetPlayerName() + " triggered recycling"));
				Reclaimer.RecycleInventoryForAllRecipes(val.GetInventory(), GroupUtils.GetPrefabName(((Object)((Component)val).transform).name), localPlayer);
			}
		}

		private ConfigEntry<T> config<[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			ConfigSyncVar.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static Recycle_N_ReclaimPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			Recycle_N_ReclaimLogger = Logger.CreateLogSource("Recycle_N_Reclaim");
			ConfigSyncVar = new ConfigSync("Azumatt.Recycle_N_Reclaim")
			{
				DisplayName = "Recycle_N_Reclaim",
				CurrentVersion = "1.3.5",
				MinimumRequiredVersion = "1.3.5"
			};
			yamlFileName = "Azumatt.Recycle_N_Reclaim_ExcludeLists.yml";
			string configPath2 = Paths.ConfigPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			yamlPath = configPath2 + directorySeparatorChar + yamlFileName;
			RNRExcludeListData = new CustomSyncedValue<string>(ConfigSyncVar, "RNR_YamlData", "");
			yamlData = new Root();
			predefinedGroups = new Dictionary<string, HashSet<string>>();
			_serverConfigLocked = null;
			hotKey = null;
			discardInvEnabled = null;
			lockToAdmin = null;
			returnUnknownResources = null;
			returnEnchantedResources = null;
			returnResources = null;
			StationFilterList = new List<string>();
			StationFilterEnabled = null;
			EnableExperimentalCraftingTabUI = null;
			NotifyOnSalvagingImpediments = null;
			PreventZeroResourceYields = null;
			UnstackableItemsAlwaysReturnAtLeastOneResource = null;
			RecyclingRate = null;
			ContainerRecyclingEnabled = null;
			IgnoreItemsOnHotbar = null;
			ContainerRecyclingButtonPositionJsonString = null;
			AllowRecyclingUnknownRecipes = null;
			DebugAlwaysDumpAnalysisContext = null;
			DebugAllowSpammyLogs = null;
			HideEquippedItemsInRecyclingTab = null;
			RequireExactCraftingStationForRecycling = null;
			returnEnchantedResourcesReclaiming = null;
			BorderColorTrashedItem = null;
			BorderColorTrashedSlot = null;
			DisplayTooltipHint = null;
			TrashingModifierKeybind1 = null;
			TrashingKeybind = null;
			TrashedSlotTooltip = null;
		}
	}
	public static class KeyboardExtensions
	{
		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}
	}
}
namespace Recycle_N_Reclaim.YAMLStuff
{
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	[HarmonyPriority(0)]
	internal static class PredefinedGroupGrab
	{
		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
		private static void Postfix(ObjectDB __instance)
		{
			if (Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				GroupUtils.CreatePredefinedGroups(__instance);
			}
		}
	}
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public class GroupUtils
	{
		public static List<string> GetExcludedGroups(string container)
		{
			if (Recycle_N_ReclaimPlugin.yamlData.Containers.TryGetValue(container, out var value))
			{
				return value.Exclude.Where([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (string excludeItem) => Recycle_N_ReclaimPlugin.yamlData.Groups.ContainsKey(excludeItem)).ToList();
			}
			return new List<string>();
		}

		public static bool IsGroupDefined(string groupName)
		{
			return Recycle_N_ReclaimPlugin.yamlData.Groups.ContainsKey(groupName);
		}

		public static bool GroupExists(string groupName)
		{
			return Recycle_N_ReclaimPlugin.yamlData.Groups.ContainsKey(groupName);
		}

		public static List<string> GetAllGroups()
		{
			return Recycle_N_ReclaimPlugin.yamlData.Groups.Keys.ToList();
		}

		public static List<string> GetItemsInGroup(string groupName)
		{
			if (Recycle_N_ReclaimPlugin.yamlData.Groups.TryGetValue(groupName, out var value))
			{
				return value.ToList();
			}
			return new List<string>();
		}

		public static string GetPrefabName(string name)
		{
			char[] anyOf = new char[2] { '(', ' ' };
			int num = name.IndexOfAny(anyOf);
			if (num >= 0)
			{
				return name.Substring(0, num);
			}
			return name;
		}

		[return: <3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(2)]
		internal static GameObject GetItemPrefabFromGameObject(ItemDrop itemDropComponent, GameObject inputGameObject)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(GetPrefabName(((Object)inputGameObject).name));
			itemDropComponent.m_itemData.m_dropPrefab = itemPrefab;
			if (!((Object)(object)itemPrefab != (Object)null))
			{
				return null;
			}
			return itemPrefab;
		}

		internal static bool CheckItemDropIntegrity(ItemDrop itemDropComp)
		{
			if (itemDropComp.m_itemData == null)
			{
				return false;
			}
			return itemDropComp.m_itemData.m_shared != null;
		}

		internal static void CreatePredefinedGroups(ObjectDB __instance)
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Invalid comparison between Unknown and I4
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected I4, but got Unknown
			//IL_018e: 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)
			//IL_0195: 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_01d6: Expected I4, but got Unknown
			foreach (GameObject item in __instance.m_items.Where([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (GameObject x) => (Object)(object)x.GetComponentInChildren<ItemDrop>() != (Object)null))
			{
				ItemDrop componentInChildren = item.GetComponentInChildren<ItemDrop>();
				if (!CheckItemDropIntegrity(componentInChildren))
				{
					continue;
				}
				GameObject itemPrefabFromGameObject = GetItemPrefabFromGameObject(componentInChildren, item);
				componentInChildren.m_itemData.m_dropPrefab = ((Component)componentInChildren).gameObject;
				if (!((Object)(object)itemPrefabFromGameObject != (Object)null))
				{
					continue;
				}
				SharedData sharedData = componentInChildren.m_itemData.m_shared;
				string text = "";
				if ((double)sharedData.m_food > 0.0 && (double)sharedData.m_foodStamina > 0.0)
				{
					text = "Food";
				}
				if ((double)sharedData.m_food > 0.0 && (double)sharedData.m_foodStamina == 0.0)
				{
					text = "Potion";
				}
				else if ((int)sharedData.m_itemType == 21)
				{
					text = "Fish";
				}
				ItemType itemType = sharedData.m_itemType;
				switch (itemType - 1)
				{
				case 2:
				case 3:
				case 13:
				case 21:
				{
					SkillType skillType = sharedData.m_skillType;
					switch (skillType - 1)
					{
					case 0:
						text = "Swords";
						break;
					case 7:
						text = "Bows";
						break;
					case 13:
						text = "Crossbows";
						break;
					case 6:
						text = "Axes";
						break;
					case 2:
						text = "Clubs";
						break;
					case 1:
						text = "Knives";
						break;
					case 11:
						text = "Pickaxes";
						break;
					case 3:
						text = "Polearms";
						break;
					case 4:
						text = "Spears";
						break;
					}
					break;
				}
				case 14:
					text = "Equipment";
					break;
				case 12:
					text = (new string[6] { "eikthyr", "elder", "bonemass", "dragonqueen", "goblinking", "SeekerQueen" }.Any(sharedData.m_name.EndsWith) ? "Boss Trophy" : "Trophy");
					break;
				case 0:
				{
					GameObject val = ((IEnumerable<GameObject>)ObjectDB.instance.GetItemPrefab("Cultivator").GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces.m_pieces).FirstOrDefault((Func<GameObject, bool>)([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (GameObject p) =>
					{
						Requirement[] resources = p.GetComponent<Piece>().m_resources;
						return resources.Length == 1 && resources[0].m_resItem.m_itemData.m_shared.m_name == sharedData.m_name;
					}));
					if (val != null)
					{
						Plant component = val.GetComponent<Plant>();
						text = ((component != null && component.m_grownPrefabs[0].GetComponent<Pickable>()?.m_amount > 1) ? "Crops" : "Seeds");
					}
					if (ZNetScene.instance.GetPrefab("smelter").GetComponent<Smelter>().m_conversion.Any([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemConversion c) => c.m_from.m_itemData.m_shared.m_name == sharedData.m_name))
					{
						text = "Ores";
					}
					if (ZNetScene.instance.GetPrefab("smelter").GetComponent<Smelter>().m_conversion.Any([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemConversion c) => c.m_to.m_itemData.m_shared.m_name == sharedData.m_name))
					{
						text = "Metals";
					}
					if (ZNetScene.instance.GetPrefab("blastfurnace").GetComponent<Smelter>().m_conversion.Any([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemConversion c) => c.m_from.m_itemData.m_shared.m_name == sharedData.m_name))
					{
						text = "Ores";
					}
					if (ZNetScene.instance.GetPrefab("blastfurnace").GetComponent<Smelter>().m_conversion.Any([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemConversion c) => c.m_to.m_itemData.m_shared.m_name == sharedData.m_name))
					{
						text = "Metals";
					}
					if (ZNetScene.instance.GetPrefab("charcoal_kiln").GetComponent<Smelter>().m_conversion.Any([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemConversion c) => c.m_from.m_itemData.m_shared.m_name == sharedData.m_name))
					{
						text = "Woods";
					}
					if (sharedData.m_name == "$item_elderbark")
					{
						text = "Woods";
					}
					break;
				}
				case 5:
					text = "Helmets";
					break;
				case 6:
				case 10:
				case 11:
				case 16:
					text = "Armor";
					break;
				case 8:
				case 22:
					text = "Ammunition";
					break;
				case 17:
					text = "Utilities";
					break;
				case 18:
					text = "Tools";
					break;
				case 15:
					text = "Miscellaneous";
					break;
				case 9:
					text = "Customizations";
					break;
				}
				if (!string.IsNullOrEmpty(text))
				{
					AddItemToGroup(text, componentInChildren);
				}
				if (sharedData != null)
				{
					text = "All";
					AddItemToGroup(text, componentInChildren);
				}
			}
		}

		private static void AddItemToGroup(string groupName, ItemDrop itemDrop)
		{
			if (!GroupExists(groupName))
			{
				Recycle_N_ReclaimPlugin.yamlData.Groups[groupName] = new List<string>();
				Recycle_N_ReclaimPlugin.predefinedGroups[groupName] = new HashSet<string>();
			}
			string prefabName = Utils.GetPrefabName(itemDrop.m_itemData.m_dropPrefab);
			if (!Recycle_N_ReclaimPlugin.yamlData.Groups[groupName].Contains(prefabName))
			{
				Recycle_N_ReclaimPlugin.yamlData.Groups[groupName].Add(prefabName);
				Recycle_N_ReclaimPlugin.predefinedGroups[groupName].Add(prefabName);
			}
		}

		public static bool IsPrefabExcludedInReclaiming(string prefabName)
		{
			return IsPrefabExcludedInEntity(Recycle_N_ReclaimPlugin.yamlData.Reclaiming, prefabName);
		}

		public static bool IsPrefabExcludedInInventory(string prefabName)
		{
			return IsPrefabExcludedInEntity(Recycle_N_ReclaimPlugin.yamlData.Inventory, prefabName);
		}

		public static bool IsPrefabExcludedInContainer(string containerName, string prefabName)
		{
			if (Recycle_N_ReclaimPlugin.yamlData.Containers.TryGetValue(containerName, out var value))
			{
				return IsPrefabExcludedInEntity(value, prefabName);
			}
			return false;
		}

		private static bool IsPrefabExcludedInEntity(object entity, string prefabName)
		{
			bool flag = ((entity is excludeContainer || entity is Reclaiming || entity is Inventory) ? true : false);
			if (!flag)
			{
				throw new ArgumentException("The entity type is not supported.");
			}
			List<string> list = null;
			List<string> list2 = null;
			if (!(entity is excludeContainer excludeContainer2))
			{
				if (!(entity is Reclaiming reclaiming))
				{
					if (entity is Inventory inventory)
					{
						list2 = inventory.Exclude;
						list = inventory.IncludeOverride;
					}
				}
				else
				{
					list = reclaiming.IncludeOverride;
					list2 = reclaiming.Exclude;
				}
			}
			else
			{
				list = excludeContainer2.IncludeOverride;
				list2 = excludeContainer2.Exclude;
			}
			if (list != null)
			{
				foreach (string item in list)
				{
					if (item == prefabName)
					{
						flag = false;
					}
					else
					{
						if (!Recycle_N_ReclaimPlugin.yamlData.Groups.TryGetValue(item, out var value) || !value.Contains(prefabName))
						{
							continue;
						}
						flag = false;
					}
					goto IL_014b;
				}
			}
			if (list2 != null)
			{
				foreach (string item2 in list2)
				{
					if (item2 == prefabName)
					{
						flag = true;
					}
					else
					{
						if (!Recycle_N_ReclaimPlugin.yamlData.Groups.TryGetValue(item2, out var value2) || !value2.Contains(prefabName))
						{
							continue;
						}
						flag = true;
					}
					goto IL_014b;
				}
			}
			return false;
			IL_014b:
			return flag;
		}
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public class Root
	{
		[YamlMember(Alias = "groups")]
		public Dictionary<string, List<string>> Groups { get; set; }

		[YamlMember(Alias = "containers")]
		public Dictionary<string, excludeContainer> Containers { get; set; }

		[YamlMember(Alias = "reclaiming")]
		public Reclaiming Reclaiming { get; set; }

		[YamlMember(Alias = "inventory")]
		public Inventory Inventory { get; set; }
	}
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public class excludeContainer
	{
		[YamlMember(Alias = "exclude")]
		public List<string> Exclude { get; set; }

		[YamlMember(Alias = "includeOverride")]
		public List<string> IncludeOverride { get; set; }
	}
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public class Reclaiming
	{
		[YamlMember(Alias = "exclude")]
		public List<string> Exclude { get; set; }

		[YamlMember(Alias = "includeOverride")]
		public List<string> IncludeOverride { get; set; }
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public class Inventory
	{
		[YamlMember(Alias = "exclude")]
		public List<string> Exclude { get; set; }

		[YamlMember(Alias = "includeOverride")]
		public List<string> IncludeOverride { get; set; }
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public class YAMLUtils
	{
		internal static void WriteConfigFileFromResource(string configFilePath)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = "Recycle_N_Reclaim.YAMLStuff.Example.yml";
			using Stream stream = executingAssembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				throw new FileNotFoundException("Resource '" + text + "' not found in the assembly.");
			}
			using StreamReader streamReader = new StreamReader(stream);
			string contents = streamReader.ReadToEnd();
			File.WriteAllText(configFilePath, contents);
		}

		internal static void ReadYaml(string yamlInput)
		{
			Recycle_N_ReclaimPlugin.yamlData = new DeserializerBuilder().Build().Deserialize<Root>(yamlInput);
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)("yamlData:\n" + yamlInput));
			foreach (KeyValuePair<string, HashSet<string>> predefinedGroup in Recycle_N_ReclaimPlugin.predefinedGroups)
			{
				Recycle_N_ReclaimPlugin.yamlData.Groups[predefinedGroup.Key] = predefinedGroup.Value.ToList();
			}
		}

		internal static void ParseGroups()
		{
			if (Recycle_N_ReclaimPlugin.yamlData == null)
			{
				Recycle_N_ReclaimPlugin.yamlData.Groups = new Dictionary<string, List<string>>();
			}
			if (!Recycle_N_ReclaimPlugin.yamlData.Groups.Any())
			{
				return;
			}
			foreach (KeyValuePair<string, List<string>> group in Recycle_N_ReclaimPlugin.yamlData.Groups)
			{
				string key = group.Key;
				List<string> value = group.Value;
				if (value == null)
				{
					continue;
				}
				List<string> list = new List<string>();
				foreach (string item in value)
				{
					list.Add(item);
				}
				Recycle_N_ReclaimPlugin.yamlData.Groups[key] = list;
			}
		}

		public static void WriteYaml(string filePath)
		{
			ISerializer serializer = new SerializerBuilder().Build();
			using StreamWriter writer = new StreamWriter(filePath);
			serializer.Serialize(writer, Recycle_N_ReclaimPlugin.yamlData);
			string contents = serializer.Serialize(Recycle_N_ReclaimPlugin.yamlData);
			File.AppendAllText(filePath, contents);
		}
	}
}
namespace Recycle_N_Reclaim.GamePatches
{
	[HarmonyPatch(typeof(InventoryGui), "UpdateItemDrag")]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(2)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public static class UpdateItemDragPatch
	{
		internal static readonly Type epicLootType = Recycle_N_ReclaimPlugin.epicLootAssembly?.GetType("EpicLoot.ItemDataExtensions");

		internal static readonly MethodInfo isMagicMethod = epicLootType?.GetMethod("IsMagic", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null);

		internal static readonly MethodInfo getRarityMethod = epicLootType?.GetMethod("GetRarity", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null);

		internal static readonly Type enchantTabControllerType = Recycle_N_ReclaimPlugin.epicLootAssembly?.GetType("EpicLoot.Crafting.EnchantHelper");

		internal static readonly MethodInfo getEnchantCostsMethod = enchantTabControllerType?.GetMethod("GetEnchantCosts", BindingFlags.Static | BindingFlags.Public);

		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
		private static void Postfix(InventoryGui __instance, ItemData ___m_dragItem, Inventory ___m_dragInventory, int ___m_dragAmount, ref GameObject ___m_dragGo)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Recycle_N_ReclaimPlugin.lockToAdmin.Value != Recycle_N_ReclaimPlugin.Toggle.On || Recycle_N_ReclaimPlugin.ConfigSyncVar.IsAdmin) && Recycle_N_ReclaimPlugin.discardInvEnabled.Value != 0)
			{
				KeyboardShortcut value = Recycle_N_ReclaimPlugin.hotKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && ___m_dragItem != null && ___m_dragInventory.ContainsItem(___m_dragItem))
				{
					Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)$"Discarding {___m_dragAmount}/{___m_dragItem.m_stack} {((Object)___m_dragItem.m_dropPrefab).name}");
					Utils.InventoryRecycleItem(___m_dragItem, ___m_dragAmount, ___m_dragInventory, __instance, ___m_dragGo);
					Object.Destroy((Object)(object)___m_dragGo);
					___m_dragGo = null;
					__instance.UpdateCraftingPanel(false);
				}
			}
		}
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public class ObjectDumper
	{
		private readonly List<int> _hashListOfFoundElements;

		private readonly int _indentSize;

		private readonly StringBuilder _stringBuilder;

		private int _level;

		private ObjectDumper(int indentSize)
		{
			_indentSize = indentSize;
			_stringBuilder = new StringBuilder();
			_hashListOfFoundElements = new List<int>();
		}

		public static string Dump(object element, int indentSize = 2)
		{
			return new ObjectDumper(indentSize).DumpElement(element);
		}

		private string GetTypeName(Type type)
		{
			if (!IsAnonymousType(type))
			{
				return type.Name;
			}
			return "AnonymousType";
		}

		private string DumpElement(object element)
		{
			if ((element == null || element is ValueType || element is string) ? true : false)
			{
				Write(FormatValue(element));
			}
			else
			{
				Type type = element.GetType();
				if (!typeof(IEnumerable).IsAssignableFrom(type))
				{
					Write("{{{0}}}", GetTypeName(type));
					_hashListOfFoundElements.Add(element.GetHashCode());
					_level++;
				}
				if (element is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						if (item is IEnumerable enumerable2 && !(enumerable2 is string))
						{
							_level++;
							DumpElement(item);
							_level--;
						}
						else if (!AlreadyTouched(item))
						{
							DumpElement(item);
						}
						else
						{
							Write("{{{0}}} <-- bidirectional reference found", GetTypeName(item.GetType()));
						}
					}
				}
				else
				{
					MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public);
					foreach (MemberInfo memberInfo in members)
					{
						FieldInfo fieldInfo = memberInfo as FieldInfo;
						PropertyInfo propertyInfo = memberInfo as PropertyInfo;
						if (fieldInfo == null && propertyInfo == null)
						{
							continue;
						}
						Type type2 = ((fieldInfo != null) ? fieldInfo.FieldType : propertyInfo.PropertyType);
						object obj = ((fieldInfo != null) ? fieldInfo.GetValue(element) : propertyInfo.GetValue(element, null));
						if (type2.IsValueType || type2 == typeof(string))
						{
							Write("{0}: {1}", memberInfo.Name, FormatValue(obj));
							continue;
						}
						bool flag = typeof(IEnumerable).IsAssignableFrom(type2);
						Write("{0}: {1}", memberInfo.Name, flag ? "..." : "{ }");
						bool num = !flag && AlreadyTouched(obj);
						_level++;
						if (!num)
						{
							DumpElement(obj);
						}
						else
						{
							Write("{{{0}}} <-- bidirectional reference found", GetTypeName(obj.GetType()));
						}
						_level--;
					}
				}
				if (!typeof(IEnumerable).IsAssignableFrom(type))
				{
					_level--;
				}
			}
			return _stringBuilder.ToString();
		}

		private bool AlreadyTouched(object value)
		{
			if (value == null)
			{
				return false;
			}
			int hashCode = value.GetHashCode();
			for (int i = 0; i < _hashListOfFoundElements.Count; i++)
			{
				if (_hashListOfFoundElements[i] == hashCode)
				{
					return true;
				}
			}
			return false;
		}

		private void Write(string value, params object[] args)
		{
			string text = new string(' ', _level * _indentSize);
			if (args != null)
			{
				value = string.Format(value, args);
			}
			_stringBuilder.AppendLine(text + value);
		}

		private string FormatValue(object o)
		{
			if (o != null)
			{
				if (!(o is DateTime dateTime))
				{
					if (!(o is string))
					{
						if (o is char)
						{
							if ((char)o == '\0')
							{
								return string.Empty;
							}
						}
						else if (!(o is ValueType))
						{
							if (o is IEnumerable)
							{
								return "...";
							}
							return "{ }";
						}
						return o.ToString();
					}
					return $"\"{o}\"";
				}
				return dateTime.ToShortDateString();
			}
			return "null";
		}

		private static bool IsAnonymousType(Type type)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), inherit: false) && type.IsGenericType && type.Name.Contains("AnonymousType") && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")))
			{
				return type.Attributes.HasFlag(TypeAttributes.NotPublic);
			}
			return false;
		}
	}
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public static class Utils
	{
		public static Texture2D LoadTextureFromResources(string pathName, string folderName = "Assets")
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			Stream manifestResourceStream = typeof(Recycle_N_ReclaimPlugin).Assembly.GetManifestResourceStream(typeof(Recycle_N_ReclaimPlugin).Namespace + "." + folderName + "." + pathName);
			Texture2D val = new Texture2D(2, 2);
			Texture2D result = new Texture2D(2, 2);
			if (manifestResourceStream == null)
			{
				return result;
			}
			byte[] array;
			using (BinaryReader binaryReader = new BinaryReader(manifestResourceStream))
			{
				array = binaryReader.ReadBytes((int)manifestResourceStream.Length);
			}
			if (!ImageConversion.LoadImage(val, array))
			{
				return result;
			}
			return val;
		}

		public static void InventoryRecycleItem(ItemData ___m_dragItem, int ___m_dragAmount, Inventory ___m_dragInventory, InventoryGui __instance, GameObject ___m_dragGo)
		{
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Expected O, but got Unknown
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0591: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_059d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Expected O, but got Unknown
			if (Recycle_N_ReclaimPlugin.returnResources.Value > 0f)
			{
				Recipe recipe = ObjectDB.instance.GetRecipe(___m_dragItem);
				if ((Object)(object)recipe != (Object)null && (Recycle_N_ReclaimPlugin.returnUnknownResources.Value == Recycle_N_ReclaimPlugin.Toggle.On || Player.m_localPlayer.IsRecipeKnown(___m_dragItem.m_shared.m_name)))
				{
					Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)$"Recipe stack: {recipe.m_amount} num of stacks: {___m_dragAmount / recipe.m_amount}");
					List<Requirement> list = recipe.m_resources.ToList();
					bool flag = false;
					bool flag2 = false;
					if (Recycle_N_ReclaimPlugin.epicLootAssembly != null && Recycle_N_ReclaimPlugin.returnEnchantedResources.Value == Recycle_N_ReclaimPlugin.Toggle.On)
					{
						MethodInfo isMagicMethod = UpdateItemDragPatch.isMagicMethod;
						object obj;
						if ((object)isMagicMethod == null)
						{
							obj = null;
						}
						else
						{
							object[] parameters = (object[])(object)new ItemData[1] { ___m_dragItem };
							obj = isMagicMethod.Invoke(null, parameters);
						}
						flag = (bool)obj;
					}
					if (flag)
					{
						MethodInfo getRarityMethod = UpdateItemDragPatch.getRarityMethod;
						object obj2;
						if ((object)getRarityMethod == null)
						{
							obj2 = null;
						}
						else
						{
							object[] parameters = (object[])(object)new ItemData[1] { ___m_dragItem };
							obj2 = getRarityMethod.Invoke(null, parameters);
						}
						int num = (int)obj2;
						foreach (KeyValuePair<ItemDrop, int> item in (List<KeyValuePair<ItemDrop, int>>)(UpdateItemDragPatch.getEnchantCostsMethod?.Invoke(null, new object[2] { ___m_dragItem, num })))
						{
							Recipe recipe2 = ObjectDB.instance.GetRecipe(item.Key.m_itemData);
							bool flag3 = (Object)(object)recipe2 != (Object)null && Player.m_localPlayer.IsRecipeKnown(item.Key.m_itemData.m_shared.m_name);
							bool flag4 = Player.m_localPlayer.m_knownMaterial.Contains(item.Key.m_itemData.m_shared.m_name);
							if (Recycle_N_ReclaimPlugin.returnUnknownResources.Value == Recycle_N_ReclaimPlugin.Toggle.Off && (!flag3 || !flag4))
							{
								((Character)Player.m_localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_no_material_recipes"), 0, (Sprite)null);
								return;
							}
							list.Add(new Requirement
							{
								m_amount = (((Object)(object)recipe2 != (Object)null) ? recipe2.m_amount : item.Value),
								m_resItem = item.Key
							});
						}
					}
					if (Jewelcrafting.API.IsLoaded() && Recycle_N_ReclaimPlugin.returnEnchantedResources.Value == Recycle_N_ReclaimPlugin.Toggle.On && Jewelcrafting.API.GetGems(___m_dragItem).Any())
					{
						foreach (KeyValuePair<ItemDrop, ItemData> item2 in (from gem in Jewelcrafting.API.GetGems(___m_dragItem)
							where gem != null
							select ObjectDB.instance.GetItemPrefab(gem.gemPrefab).GetComponent<ItemDrop>() into itemDrop
							where (Object)(object)itemDrop != (Object)null
							select itemDrop).ToDictionary([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemDrop itemDrop) => itemDrop, [<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (ItemDrop itemDrop) => itemDrop.m_itemData))
						{
							Recipe recipe3 = ObjectDB.instance.GetRecipe(item2.Value);
							bool flag5 = (Object)(object)recipe3 != (Object)null && Player.m_localPlayer.IsRecipeKnown(item2.Value.m_shared.m_name);
							bool flag6 = Player.m_localPlayer.m_knownMaterial.Contains(item2.Value.m_shared.m_name);
							if (Recycle_N_ReclaimPlugin.returnUnknownResources.Value == Recycle_N_ReclaimPlugin.Toggle.Off && (!flag5 || !flag6))
							{
								((Character)Player.m_localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_no_material_recipes"), 0, (Sprite)null);
								return;
							}
							list.Add(new Requirement
							{
								m_amount = (((Object)(object)recipe3 != (Object)null) ? recipe3.m_amount : item2.Value.m_stack),
								m_resItem = item2.Key
							});
						}
					}
					if (!flag2 && ___m_dragAmount / recipe.m_amount > 0)
					{
						for (int i = 0; i < ___m_dragAmount / recipe.m_amount; i++)
						{
							foreach (Requirement req in list)
							{
								for (int num2 = ___m_dragItem.m_quality; num2 > 0; num2--)
								{
									GameObject val = ((IEnumerable<GameObject>)ObjectDB.instance.m_items).FirstOrDefault((Func<GameObject, bool>)([<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)] (GameObject item) => item.GetComponent<ItemDrop>().m_itemData.m_shared.m_name == req.m_resItem.m_itemData.m_shared.m_name));
									ItemData itemData = val.GetComponent<ItemDrop>().m_itemData.Clone();
									int num3 = Mathf.RoundToInt((float)req.GetAmount(num2) * Recycle_N_ReclaimPlugin.returnResources.Value);
									Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)$"Returning {num3}/{req.GetAmount(num2)} {((Object)val).name}");
									while (num3 > 0)
									{
										int num4 = Mathf.Min(req.m_resItem.m_itemData.m_shared.m_maxStackSize, num3);
										num3 -= num4;
										if (!GroupUtils.IsPrefabExcludedInInventory(Utils.GetPrefabName(val)) && ((Humanoid)Player.m_localPlayer).GetInventory().AddItem(((Object)val).name, num4, req.m_resItem.m_itemData.m_quality, req.m_resItem.m_itemData.m_variant, 0L, "", false) == null)
										{
											Transform transform;
											ItemDrop component = Object.Instantiate<GameObject>(val, (transform = ((Component)Player.m_localPlayer).transform).position + transform.forward + transform.up, transform.rotation).GetComponent<ItemDrop>();
											component.m_itemData = itemData;
											component.m_itemData.m_dropPrefab = val;
											component.m_itemData.m_stack = num4;
											component.Save();
										}
									}
								}
							}
						}
					}
				}
			}
			if (___m_dragAmount == ___m_dragItem.m_stack)
			{
				((Humanoid)Player.m_localPlayer).RemoveEquipAction(___m_dragItem);
				((Humanoid)Player.m_localPlayer).UnequipItem(___m_dragItem, false);
				___m_dragInventory.RemoveItem(___m_dragItem);
			}
			else
			{
				___m_dragInventory.RemoveItem(___m_dragItem, ___m_dragAmount);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	public static class RegisterAndCheckVersion
	{
		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
		private static void Prefix(ZNetPeer peer, ref ZNet __instance)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)"Registering version RPC handler");
			peer.m_rpc.Register<ZPackage>("Recycle_N_Reclaim_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_Recycle_N_Reclaim_Version);
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogInfo((object)"Invoking version check");
			ZPackage val = new ZPackage();
			val.Write("1.3.5");
			val.Write(RpcHandlers.ComputeHashForMod().Replace("-", ""));
			peer.m_rpc.Invoke("Recycle_N_Reclaim_VersionCheck", new object[1] { val });
		}
	}
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public static class VerifyClient
	{
		private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance)
		{
			if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc))
			{
				return true;
			}
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting"));
			rpc.Invoke("Error", new object[1] { 3 });
			return false;
		}

		private static void Postfix(ZNet __instance)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "Recycle_N_ReclaimRequestAdminSync", new object[1] { (object)new ZPackage() });
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
	public class ShowConnectionError
	{
		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
		private static void Postfix(FejdStartup __instance)
		{
			if (__instance.m_connectionFailedPanel.activeSelf)
			{
				__instance.m_connectionFailedError.fontSizeMax = 25f;
				__instance.m_connectionFailedError.fontSizeMin = 15f;
				TMP_Text connectionFailedError = __instance.m_connectionFailedError;
				connectionFailedError.text = connectionFailedError.text + "\n" + Recycle_N_ReclaimPlugin.ConnectionError;
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Disconnect")]
	public static class RemoveDisconnectedPeerFromVerified
	{
		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
		private static void Prefix(ZNetPeer peer, ref ZNet __instance)
		{
			if (__instance.IsServer())
			{
				Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list"));
				RpcHandlers.ValidatedPeers.Remove(peer.m_rpc);
			}
		}
	}
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public static class RpcHandlers
	{
		public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>();

		public static void RPC_Recycle_N_Reclaim_Version(ZRpc rpc, ZPackage pkg)
		{
			string text = pkg.ReadString();
			string text2 = pkg.ReadString();
			string text3 = ComputeHashForMod().Replace("-", "");
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogInfo((object)("Hash/Version check, local: 1.3.5 " + text3 + " remote: " + text + " " + text2));
			if (text2 != text3 || text != "1.3.5")
			{
				Recycle_N_ReclaimPlugin.ConnectionError = "Recycle_N_Reclaim Installed: 1.3.5 " + text3 + "\n Needed: " + text + " " + text2;
				if (ZNet.instance.IsServer())
				{
					Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting..."));
					rpc.Invoke("Error", new object[1] { 3 });
				}
			}
			else if (!ZNet.instance.IsServer())
			{
				Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogInfo((object)"Received same version from server!");
			}
			else
			{
				Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogInfo((object)("Adding peer (" + rpc.m_socket.GetHostName() + ") to validated list"));
				ValidatedPeers.Add(rpc);
			}
		}

		public static string ComputeHashForMod()
		{
			using SHA256 sHA = SHA256.Create();
			byte[] array = sHA.ComputeHash(File.ReadAllBytes(Assembly.GetExecutingAssembly().Location));
			StringBuilder stringBuilder = new StringBuilder();
			byte[] array2 = array;
			foreach (byte b in array2)
			{
				stringBuilder.Append(b.ToString("X2"));
			}
			return stringBuilder.ToString();
		}
	}
}
namespace Recycle_N_Reclaim.GamePatches.UI
{
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	public class ContainerRecyclingButtonHolder : MonoBehaviour
	{
		[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(0)]
		public delegate void RecycleAllHandler();

		private Button _recycleAllButton;

		private bool _prefired;

		private TMP_Text _textComponent;

		private Image _imageComponent;

		public event RecycleAllHandler OnRecycleAllTriggered;

		private void Start()
		{
			((MonoBehaviour)this).InvokeRepeating("EnsureRecyclingButtonExistsIfPossible", 0f, 5f);
		}

		private void EnsureRecyclingButtonExistsIfPossible()
		{
			if (!((Object)(object)InventoryGui.instance == (Object)null))
			{
				if ((Object)(object)_recycleAllButton == (Object)null)
				{
					SetupButton();
				}
				((Component)_recycleAllButton).gameObject.SetActive(Recycle_N_ReclaimPlugin.ContainerRecyclingEnabled.Value == Recycle_N_ReclaimPlugin.Toggle.On);
			}
		}

		private void OnDestroy()
		{
			try
			{
				Object.Destroy((Object)(object)((Component)_recycleAllButton).gameObject);
			}
			catch
			{
			}
		}

		private void FixedUpdate()
		{
			if (Recycle_N_ReclaimPlugin.ContainerRecyclingEnabled.Value != 0 && !((Object)(object)_recycleAllButton == (Object)null) && !InventoryGui.instance.IsContainerOpen() && _prefired)
			{
				SetButtonState(showPrefire: false);
			}
		}

		private void SetupButton()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			if (!((Object)(object)_recycleAllButton != (Object)null))
			{
				if (Recycle_N_ReclaimPlugin.HasAuga)
				{
					_recycleAllButton = ((Component)((Transform)InventoryGui.instance.m_container).Find("RecycleAll")).GetComponent<Button>();
				}
				else
				{
					Vector3 savedButtonPosition = GetSavedButtonPosition();
					_recycleAllButton = Object.Instantiate<Button>(InventoryGui.instance.m_takeAllButton, ((Component)InventoryGui.instance.m_takeAllButton).transform);
					((Component)_recycleAllButton).transform.SetParent(((Component)InventoryGui.instance.m_takeAllButton).transform.parent);
					((Component)_recycleAllButton).transform.localPosition = savedButtonPosition;
				}
				_recycleAllButton.onClick = new ButtonClickedEvent();
				((UnityEvent)_recycleAllButton.onClick).AddListener(new UnityAction(OnRecycleAllPressed));
				_textComponent = ((Component)_recycleAllButton).GetComponentInChildren<TMP_Text>();
				_imageComponent = ((Component)_recycleAllButton).GetComponentInChildren<Image>();
				((Component)_recycleAllButton).gameObject.AddComponent<UIDragger>().OnUIDropped += delegate(object source, Vector3 position)
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					Recycle_N_ReclaimPlugin.ContainerRecyclingButtonPositionJsonString.Value = position;
				};
				SetButtonState(showPrefire: false);
			}
		}

		private Vector3 GetSavedButtonPosition()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Recycle_N_ReclaimPlugin.ContainerRecyclingButtonPositionJsonString.Value;
		}

		private void SetButtonState(bool showPrefire)
		{
			//IL_0070: 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 (showPrefire)
			{
				_prefired = true;
				_textComponent.text = Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_confirm");
				((Graphic)_imageComponent).color = new Color(1f, 0.5f, 0.5f);
			}
			else
			{
				_prefired = false;
				_textComponent.text = Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_reclaim_all");
				((Graphic)_imageComponent).color = new Color(0.5f, 1f, 0.5f);
			}
		}

		private void OnRecycleAllPressed()
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				if (!_prefired)
				{
					SetButtonState(showPrefire: true);
					return;
				}
				SetButtonState(showPrefire: false);
				this.OnRecycleAllTriggered?.Invoke();
			}
		}
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public static class InventoryGuiExtensions
	{
		public static float get_m_recipeListBaseSize(this InventoryGui instance)
		{
			return instance.m_recipeListBaseSize;
		}

		public static List<RecipeDataPair> get_m_recipeList(this InventoryGui instance)
		{
			return instance.m_availableRecipes;
		}

		public static List<RecipeDataPair> get_m_availableRecipes(this InventoryGui instance)
		{
			return instance.m_availableRecipes;
		}

		public static RecipeDataPair get_m_selectedRecipe(this InventoryGui instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return instance.m_selectedRecipe;
		}

		public static void set_m_selectedRecipe(this InventoryGui instance, RecipeDataPair value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			instance.m_selectedRecipe = value;
		}

		public static int get_m_selectedVariant(this InventoryGui instance)
		{
			return instance.m_selectedVariant;
		}

		public static void set_m_selectedVariant(this InventoryGui instance, int value)
		{
			instance.m_selectedVariant = value;
		}

		public static float get_m_craftTimer(this InventoryGui instance)
		{
			return instance.m_craftTimer;
		}

		public static void set_m_craftTimer(this InventoryGui instance, float value)
		{
			instance.m_craftTimer = value;
		}

		public static Color get_m_minStationLevelBasecolor(this InventoryGui instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return instance.m_minStationLevelBasecolor;
		}
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	[HarmonyPatch]
	public static class InventoryGuiPatches
	{
		[HarmonyPriority(600)]
		[HarmonyPatch(typeof(InventoryGui), "OnTabCraftPressed")]
		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "OnTabUpgradePressed")]
		private static void OnTabCraftPressedAlsoEnableRecycling1(InventoryGui __instance)
		{
			Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.SetInteractable(interactable: true);
			__instance.UpdateCraftingPanel(false);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
		private static bool UpdateCraftingPanelDetourOnRecyclingTab(InventoryGui __instance)
		{
			if (Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.InRecycleTab())
			{
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		[HarmonyPrefix]
		private static void OnHideSetToCraftingTab(InventoryGui __instance)
		{
			if (!((Object)(object)Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder == (Object)null) && Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.InRecycleTab())
			{
				InventoryGui.instance.OnTabCraftPressed();
				Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.SetActive(active: false);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
		[HarmonyPostfix]
		private static void UpdateCraftingPanelDetourOnOtherTabsEnableRecyclingButton(InventoryGui __instance)
		{
			if (!Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.InRecycleTab())
			{
				Player localPlayer = Player.m_localPlayer;
				Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.SetInteractable(interactable: true);
				if (!Object.op_Implicit((Object)(object)localPlayer.GetCurrentCraftingStation()) && !localPlayer.NoCostCheat())
				{
					Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.SetActive(active: false);
				}
				else
				{
					Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.SetActive(active: true);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe", new Type[]
		{
			typeof(Player),
			typeof(float)
		})]
		[HarmonyPrefix]
		private static bool UpdateRecipeOnRecyclingTab(InventoryGui __instance, Player player, float dt)
		{
			if (!Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.InRecycleTab())
			{
				return true;
			}
			Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.UpdateRecipe(player, dt);
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "Changed")]
		[HarmonyPostfix]
		private static void InventorySave(Inventory __instance)
		{
			if (!((Object)(object)Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder == (Object)null) && Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.InRecycleTab() && __instance == ((Humanoid)Player.m_localPlayer).GetInventory())
			{
				Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.UpdateRecyclingList();
				InventoryGui.instance.SetRecipe(-1, false);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Humanoid), "EquipItem", new Type[]
		{
			typeof(ItemData),
			typeof(bool)
		})]
		[HarmonyPatch(typeof(Humanoid), "UnequipItem", new Type[]
		{
			typeof(ItemData),
			typeof(bool)
		})]
		private static void HumanoidEquip(Humanoid __instance)
		{
			if (!((Object)(object)Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.InRecycleTab() && __instance.GetInventory() == ((Humanoid)Player.m_localPlayer).GetInventory())
			{
				Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.UpdateRecyclingList();
				InventoryGui.instance.SetRecipe(-1, false);
			}
		}
	}
	[<607bf95e-59f1-4e63-ab42-7b11f8515926>NullableContext(1)]
	[<3f607022-9496-490a-85e6-01cde9ffb3e4>Nullable(0)]
	public class StationRecyclingTabHolder : MonoBehaviour
	{
		private GameObject _recyclingTabButtonGameObject;

		private Button _recyclingTabButtonComponent;

		private List<RecyclingAnalysisContext> _recyclingAnalysisContexts = new List<RecyclingAnalysisContext>();

		private WorkbenchTabData _augaTabData;

		private GameObject _itemInfoGo;

		private GameObject _descriptionBoxGo;

		private void Start()
		{
			((MonoBehaviour)this).InvokeRepeating("EnsureRecyclingTabExists", 5f, 5f);
		}

		private void EnsureRecyclingTabExists()
		{
			if (!((Object)(object)InventoryGui.instance == (Object)null) && (Object)(object)_recyclingTabButtonComponent == (Object)null)
			{
				SetupTabButton();
			}
		}

		private void OnDestroy()
		{
			try
			{
				Object.Destroy((Object)(object)_recyclingTabButtonGameObject.gameObject);
			}
			catch
			{
			}
		}

		private void SetupTabButton()
		{
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_005f: 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)
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)"Creating Workbench Tab");
			if (Recycle_N_ReclaimPlugin.HasAuga)
			{
				if (!Auga.API.Workbench_HasWorkbenchTab("Reclaim"))
				{
					Texture2D val = Utils.LoadTextureFromResources("RecyclingPanel.png");
					Sprite tabIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0f, 0f), 100f);
					if (Recycle_N_ReclaimPlugin.epicLootAssembly != null)
					{
						_augaTabData = Auga.API.Workbench_AddWorkbenchTab("Reclaim", tabIcon, "Recycle_N_Reclaim".Replace("_", "-"), delegate
						{
							OnRecycleClick();
						});
					}
					else
					{
						_augaTabData = Auga.API.Workbench_AddVanillaWorkbenchTab("Reclaim", tabIcon, "Recycle_N_Reclaim".Replace("_", "-"), delegate
						{
							OnRecycleClick();
						});
					}
					_recyclingTabButtonComponent = (_recyclingTabButtonGameObject = _augaTabData.TabButtonGO).GetComponent<Button>();
					_itemInfoGo = _augaTabData.ItemInfoGO;
					Auga.API.ComplexTooltip_AddDivider(_itemInfoGo);
					_descriptionBoxGo = Auga.API.ComplexTooltip_AddTwoColumnTextBox(_itemInfoGo);
					Auga.API.ComplexTooltip_EnableDescription(_itemInfoGo, enabled: false);
				}
			}
			else
			{
				Transform transform = ((Component)InventoryGui.instance.m_tabUpgrade).transform;
				_recyclingTabButtonGameObject = Object.Instantiate<GameObject>(((Component)InventoryGui.instance.m_tabUpgrade).gameObject, transform.position, transform.rotation, transform.parent);
				((Object)_recyclingTabButtonGameObject).name = "RECLAIM";
				_recyclingTabButtonGameObject.transform.parent.Find("TabBorder").SetAsLastSibling();
				_recyclingTabButtonGameObject.transform.localPosition = new Vector3(-45f, -94f, 0f);
				_recyclingTabButtonComponent = _recyclingTabButtonGameObject.GetComponent<Button>();
				((Selectable)_recyclingTabButtonComponent).interactable = true;
				_recyclingTabButtonComponent.onClick = new ButtonClickedEvent();
				((UnityEvent)_recyclingTabButtonComponent.onClick).AddListener(new UnityAction(OnRecycleClick));
				TMP_Text componentInChildren = _recyclingTabButtonGameObject.GetComponentInChildren<TMP_Text>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_reclaim_tab");
				}
			}
			bool active = (Object)(object)Player.m_localPlayer.GetCurrentCraftingStation() != (Object)null;
			_recyclingTabButtonGameObject.SetActive(active);
		}

		private void OnRecycleClick()
		{
			((Selectable)_recyclingTabButtonComponent).interactable = false;
			((Selectable)InventoryGui.instance.m_tabCraft).interactable = true;
			((Selectable)InventoryGui.instance.m_tabUpgrade).interactable = true;
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)"OnRecycleClick");
			UpdateCraftingPanel();
		}

		public void UpdateCraftingPanel()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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)
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer.GetCurrentCraftingStation() == (Object)null && !localPlayer.NoCostCheat())
			{
				((Selectable)instance.m_tabCraft).interactable = false;
				((Selectable)instance.m_tabUpgrade).interactable = true;
				((Component)instance.m_tabUpgrade).gameObject.SetActive(false);
				((Selectable)_recyclingTabButtonComponent).interactable = true;
				((Component)_recyclingTabButtonComponent).gameObject.SetActive(false);
			}
			else
			{
				((Component)instance.m_tabUpgrade).gameObject.SetActive(true);
			}
			UpdateRecyclingList();
			RecipeDataPair val;
			if (instance.m_availableRecipes.Count > 0)
			{
				val = instance.get_m_selectedRecipe();
				if ((Object)(object)((RecipeDataPair)(ref val)).Recipe != (Object)null)
				{
					instance.SetRecipe(instance.GetSelectedRecipeIndex(false), true);
				}
				else
				{
					instance.SetRecipe(0, true);
				}
			}
			else
			{
				InventoryGui.instance.SetRecipe(-1, true);
			}
			if (Recycle_N_ReclaimPlugin.HasAuga)
			{
				GameObject itemInfoGo = _itemInfoGo;
				val = instance.get_m_selectedRecipe();
				Auga.API.ComplexTooltip_SetItem(itemInfoGo, ((RecipeDataPair)(ref val)).ItemData);
			}
		}

		public void UpdateRecyclingList()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			InventoryGui instance = InventoryGui.instance;
			List<RecipeDataPair> list = instance.get_m_recipeList();
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)$"Old recipe list had {list.Count} entries. Cleaning up");
			foreach (RecipeDataPair item in list)
			{
				RecipeDataPair current = item;
				Object.Destroy((Object)(object)((RecipeDataPair)(ref current)).InterfaceElement);
			}
			list.Clear();
			_recyclingAnalysisContexts.Clear();
			IEnumerable<RecyclingAnalysisContext> collection = from context in Reclaimer.GetRecyclingAnalysisForInventory(((Humanoid)localPlayer).GetInventory(), localPlayer)
				where (Object)(object)context.Recipe != (Object)null && context.DisplayImpediments.Count == 0
				select context;
			_recyclingAnalysisContexts.AddRange(collection);
			foreach (RecyclingAnalysisContext recyclingAnalysisContext in _recyclingAnalysisContexts)
			{
				if (!((Object)(object)recyclingAnalysisContext.Recipe == (Object)null))
				{
					AddRecipeToList(recyclingAnalysisContext, list);
				}
			}
			Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)$"Added {list.Count} entries");
			instance.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(instance.get_m_recipeListBaseSize(), (float)list.Count * instance.m_recipeListSpace));
		}

		private void AddRecipeToList(RecyclingAnalysisContext context, List<RecipeDataPair> m_recipeList)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			int count = m_recipeList.Count;
			InventoryGui igui = InventoryGui.instance;
			RectTransform recipeListRoot = igui.m_recipeListRoot;
			GameObject element = Object.Instantiate<GameObject>(igui.m_recipeElementPrefab, (Transform)(object)recipeListRoot);
			element.SetActive(true);
			((RectTransform)element.transform).anchoredPosition = new Vector2(0f, (float)count * (0f - igui.m_recipeListSpace));
			Image component = ((Component)element.transform.Find("icon")).GetComponent<Image>();
			component.sprite = context.Item.GetIcon();
			((Graphic)component).color = (Color)((context.RecyclingImpediments.Count == 0) ? Color.white : new Color(1f, 0f, 1f, 0f));
			TMP_Text component2 = ((Component)element.transform.Find("name")).GetComponent<TMP_Text>();
			string text = Recycle_N_ReclaimPlugin.Localize(context.Item.m_shared.m_name);
			if (context.Item.m_stack > 1 && context.Item.m_shared.m_maxStackSize > 1)
			{
				text = $"{text} x{context.Item.m_stack}";
			}
			component2.text = text;
			((Graphic)component2).color = (Color)((context.RecyclingImpediments.Count == 0) ? Color.white : new Color(0.66f, 0.66f, 0.66f, 1f));
			GuiBar component3 = ((Component)element.transform.Find("Durability")).GetComponent<GuiBar>();
			if (context.Item.m_shared.m_useDurability && (double)context.Item.m_durability < (double)context.Item.GetMaxDurability())
			{
				((Component)component3).gameObject.SetActive(true);
				component3.SetValue(context.Item.GetDurabilityPercentage());
			}
			else
			{
				((Component)component3).gameObject.SetActive(false);
			}
			TMP_Text component4 = ((Component)element.transform.Find("QualityLevel")).GetComponent<TMP_Text>();
			((Component)component4).gameObject.SetActive(true);
			component4.text = context.Item.m_quality.ToString();
			((UnityEvent)element.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				igui.OnSelectedRecipe(element);
			});
			bool globalKey = ZoneSystem.instance.GetGlobalKey((GlobalKeys)19);
			bool flag = (igui.InCraftTab() ? (Player.m_localPlayer.HaveRequirements(context.Recipe, false, 1, 1) || globalKey) : (context.Item.m_quality < context.Item.m_shared.m_maxQuality && (Player.m_localPlayer.HaveRequirements(context.Recipe, false, context.Item.m_quality + 1, 1) || globalKey)));
			m_recipeList.Add(new RecipeDataPair(context.Recipe, context.Item, element, flag));
		}

		public bool InRecycleTab()
		{
			if ((Object)(object)_recyclingTabButtonComponent == (Object)null)
			{
				return false;
			}
			return !((Selectable)_recyclingTabButtonComponent).interactable;
		}

		public void SetInteractable(bool interactable)
		{
			EnsureRecyclingTabExists();
			((Selectable)_recyclingTabButtonComponent).interactable = interactable;
		}

		public void SetActive(bool active)
		{
			if (Recycle_N_ReclaimPlugin.EnableExperimentalCraftingTabUI.Value != 0)
			{
				_recyclingTabButtonGameObject.SetActive(active);
			}
		}

		public void UpdateRecipe(Player player, float dt)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			int selectedRecipeIndex = instance.GetSelectedRecipeIndex(false);
			UpdateRecyclingAnalysisContexts(selectedRecipeIndex, player);
			UpdateCraftingStationUI(player);
			RecipeDataPair val = instance.get_m_selectedRecipe();
			if (Object.op_Implicit((Object)(object)((RecipeDataPair)(ref val)).Recipe))
			{
				UpdateRecipeUI(selectedRecipeIndex, instance);
			}
			else
			{
				ClearRecipeUI(instance);
			}
			UpdateCraftingTimer(dt, selectedRecipeIndex, player, instance);
		}

		private void UpdateRecyclingAnalysisContexts(int selectedRecipeIndex, Player player)
		{
			if (selectedRecipeIndex > -1 && _recyclingAnalysisContexts.Count > 0 && selectedRecipeIndex < _recyclingAnalysisContexts.Count)
			{
				RecyclingAnalysisContext recyclingAnalysisContext = new RecyclingAnalysisContext(_recyclingAnalysisContexts[selectedRecipeIndex].Item);
				Reclaimer.TryAnalyzeOneItem(recyclingAnalysisContext, ((Humanoid)player).GetInventory(), player);
				_recyclingAnalysisContexts[selectedRecipeIndex] = recyclingAnalysisContext;
			}
		}

		private void UpdateCraftingStationUI(Player player)
		{
			InventoryGui instance = InventoryGui.instance;
			CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
			if (Object.op_Implicit((Object)(object)currentCraftingStation))
			{
				SetActive(((Component)instance.m_craftingStationIcon).gameObject, isActive: true);
				SetActive(((Component)instance.m_craftingStationLevelRoot).gameObject, isActive: true);
				instance.m_craftingStationName.text = Recycle_N_ReclaimPlugin.Localize(currentCraftingStation.m_name);
				instance.m_craftingStationIcon.sprite = currentCraftingStation.m_icon;
				instance.m_craftingStationLevel.text = currentCraftingStation.GetLevel(true).ToString();
			}
			else
			{
				SetActive(((Component)instance.m_craftingStationIcon).gameObject, isActive: false);
				SetActive(((Component)instance.m_craftingStationLevelRoot).gameObject, isActive: false);
				instance.m_craftingStationName.text = Recycle_N_ReclaimPlugin.Localize("$hud_crafting");
			}
		}

		private void UpdateRecipeUI(int selectedRecipeIndex, InventoryGui igui)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			RecyclingAnalysisContext recyclingAnalysisContext = _recyclingAnalysisContexts[selectedRecipeIndex];
			RecipeDataPair val = igui.get_m_selectedRecipe();
			ItemData itemData = ((RecipeDataPair)(ref val)).ItemData;
			_ = itemData?.m_quality;
			((Behaviour)igui.m_recipeIcon).enabled = true;
			((Behaviour)igui.m_recipeName).enabled = true;
			((Behaviour)igui.m_recipeDecription).enabled = true;
			Image recipeIcon = igui.m_recipeIcon;
			val = igui.get_m_selectedRecipe();
			recipeIcon.sprite = ((RecipeDataPair)(ref val)).Recipe.m_item.m_itemData.m_shared.m_icons[itemData?.m_variant ?? igui.get_m_selectedVariant()];
			val = igui.get_m_selectedRecipe();
			string text = Recycle_N_ReclaimPlugin.Localize(((RecipeDataPair)(ref val)).Recipe.m_item.m_itemData.m_shared.m_name);
			if (recyclingAnalysisContext.Item.m_stack > 1)
			{
				text = text + " x" + recyclingAnalysisContext.Item.m_stack;
			}
			igui.m_recipeName.text = text;
			if (recyclingAnalysisContext.RecyclingImpediments.Count == 0)
			{
				igui.m_recipeDecription.text = "\n" + Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_requirements_fulfilled");
			}
			else
			{
				igui.m_recipeDecription.text = "\n" + Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_requirements_blocked") + ":\n\n<size=15>" + string.Join("\n", recyclingAnalysisContext.RecyclingImpediments) + "</size>";
			}
			if (itemData != null)
			{
				SetActive(((Component)igui.m_itemCraftType).gameObject, isActive: true);
				igui.m_itemCraftType.text = Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_reclaim_item_level", Recycle_N_ReclaimPlugin.Localize(itemData.m_shared.m_name), itemData.m_quality.ToString());
			}
			else
			{
				SetActive(((Component)igui.m_itemCraftType).gameObject, isActive: false);
			}
			if (Recycle_N_ReclaimPlugin.HasAuga)
			{
				if ((Object)(object)_descriptionBoxGo == (Object)null)
				{
					_descriptionBoxGo = Auga.API.ComplexTooltip_AddTwoColumnTextBox(_augaTabData.ItemInfoGO);
				}
				Auga.API.TooltipTextBox_AddLine(_descriptionBoxGo, (object)igui.m_recipeDecription.text, localize: true, overwrite: true);
			}
			GameObject gameObject = ((Component)igui.m_variantButton).gameObject;
			val = igui.get_m_selectedRecipe();
			int isActive;
			if (((RecipeDataPair)(ref val)).Recipe.m_item.m_itemData.m_shared.m_variants > 1)
			{
				val = igui.get_m_selectedRecipe();
				isActive = ((((RecipeDataPair)(ref val)).ItemData == null) ? 1 : 0);
			}
			else
			{
				isActive = 0;
			}
			SetActive(gameObject, (byte)isActive != 0);
			if (Recycle_N_ReclaimPlugin.epicLootAssembly == null)
			{
				SetupRequirementList(recyclingAnalysisContext);
			}
			else
			{
				SetupRequirementListEpicLoot(recyclingAnalysisContext);
			}
			SetActive(((Component)igui.m_minStationLevelIcon).gameObject, isActive: false);
			((Selectable)igui.m_craftButton).interactable = recyclingAnalysisContext.RecyclingImpediments.Count == 0;
			((Component)igui.m_craftButton).GetComponentInChildren<TMP_Text>().text = Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_reclaim_button");
			((Component)igui.m_craftButton).GetComponent<UITooltip>().m_text = ((recyclingAnalysisContext.RecyclingImpediments.Count == 0) ? "" : Recycle_N_ReclaimPlugin.Localize("$msg_missingrequirement"));
		}

		private void ClearRecipeUI(InventoryGui igui)
		{
			((Behaviour)igui.m_recipeIcon).enabled = false;
			((Behaviour)igui.m_recipeName).enabled = false;
			((Behaviour)igui.m_recipeDecription).enabled = false;
			SetActive(((Component)igui.m_qualityPanel).gameObject, isActive: false);
			SetActive(((Component)igui.m_minStationLevelIcon).gameObject, isActive: false);
			((Component)igui.m_craftButton).GetComponent<UITooltip>().m_text = "";
			SetActive(((Component)igui.m_variantButton).gameObject, isActive: false);
			((Component)igui.m_craftButton).GetComponentInChildren<TMP_Text>().text = Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_reclaim_button");
			SetActive(((Component)igui.m_itemCraftType).gameObject, isActive: false);
			for (int i = 0; i < igui.m_recipeRequirementList.Length; i++)
			{
				InventoryGui.HideRequirement(igui.m_recipeRequirementList[i].transform);
			}
			((Selectable)igui.m_craftButton).interactable = false;
		}

		private void UpdateCraftingTimer(float dt, int selectedRecipeIndex, Player player, InventoryGui igui)
		{
			if ((double)igui.get_m_craftTimer() < 0.0)
			{
				SetActive(((Component)igui.m_craftProgressPanel).gameObject, isActive: false);
				SetActive(((Component)igui.m_craftButton).gameObject, isActive: true);
				return;
			}
			SetActive(((Component)igui.m_craftButton).gameObject, isActive: false);
			SetActive(((Component)igui.m_craftProgressPanel).gameObject, isActive: true);
			igui.m_craftProgressBar.SetMaxValue(igui.m_craftDuration);
			igui.m_craftProgressBar.SetValue(igui.get_m_craftTimer());
			igui.set_m_craftTimer(igui.get_m_craftTimer() + dt);
			if ((double)igui.get_m_craftTimer() >= (double)igui.m_craftDuration)
			{
				Reclaimer.DoInventoryChanges(_recyclingAnalysisContexts[selectedRecipeIndex], ((Humanoid)player).GetInventory(), player);
				igui.set_m_craftTimer(-1f);
				igui.SetRecipe(-1, false);
				UpdateCraftingPanel();
			}
		}

		private void SetActive(GameObject gameObject, bool isActive)
		{
			if (Object.op_Implicit((Object)(object)gameObject))
			{
				gameObject.SetActive(isActive);
			}
		}

		private void SetupRequirementListEpicLoot(RecyclingAnalysisContext analysisContexts)
		{
			InventoryGui instance = InventoryGui.instance;
			List<RecyclingAnalysisContext.ReclaimingYieldEntry> list = analysisContexts.Entries.Where((RecyclingAnalysisContext.ReclaimingYieldEntry entry) => entry.Amount != 0).ToList();
			for (int i = 0; i < instance.m_recipeRequirementList.Length; i++)
			{
				Transform transform = instance.m_recipeRequirementList[i].transform;
				if (i < list.Count)
				{
					if (analysisContexts.Entries[i].Amount == 0)
					{
						InventoryGui.HideRequirement(transform);
					}
					else
					{
						SetupRequirementEpicLoot(transform, list[i]);
					}
				}
				else
				{
					InventoryGui.HideRequirement(transform);
				}
			}
		}

		public static void SetupRequirem