Decompiled source of Recycle N Reclaim v1.4.4

Recycle_N_Reclaim.dll

Decompiled 4 days 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 EpicLootAPI;
using HarmonyLib;
using JetBrains.Annotations;
using Jewelcrafting;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Recycle_N_Reclaim.GamePatches.MarkAsTrash;
using Recycle_N_Reclaim.GamePatches.Recycling;
using Recycle_N_Reclaim.GamePatches.UI;
using Recycle_N_Reclaim.Managers;
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: AssemblyProduct("Recycle_N_Reclaim")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyCompany("Azumatt")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyTitle("Recycle_N_Reclaim")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyDescription("")]
[assembly: AssemblyFileVersion("1.4.4")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.4.0")]
[module: UnverifiableCode]
[module: <5516dc4b-5b80-47c0-b813-37f9d549f2f5>RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[<de610467-5b91-4d42-bbe3-d3ce442dcce2>Embedded]
	[CompilerGenerated]
	internal sealed class <de610467-5b91-4d42-bbe3-d3ce442dcce2>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[<de610467-5b91-4d42-bbe3-d3ce442dcce2>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	internal sealed class <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[<de610467-5b91-4d42-bbe3-d3ce442dcce2>Embedded]
	[CompilerGenerated]
	internal sealed class <e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[<de610467-5b91-4d42-bbe3-d3ce442dcce2>Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class <5516dc4b-5b80-47c0-b813-37f9d549f2f5>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <5516dc4b-5b80-47c0-b813-37f9d549f2f5>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LocalizationManager
{
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[PublicAPI]
	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;

		[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(2)]
		[method: <e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(2)]
		[field: <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(2)]
		public static event Action OnLocalizationComplete;

		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, [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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, [<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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 += [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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()
		{
			_ = plugin;
		}

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

		public static void SafeCallLocalizeComplete()
		{
			Localizer.OnLocalizationComplete?.Invoke();
		}

		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[] array = Path.GetFileNameWithoutExtension(item).Split('.');
				if (array.Length >= 2)
				{
					string text = array[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[] array2 = LoadTranslationFromAssembly("English");
			if (array2 == 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(array2));
			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.TryGetValue(language, out var value))
				{
					text2 = File.ReadAllText(value);
				}
				else
				{
					byte[] array3 = LoadTranslationFromAssembly(language);
					if (array3 != null)
					{
						text2 = Encoding.UTF8.GetString(array3);
					}
				}
			}
			if (text2 == null && dictionary.TryGetValue("English", out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: 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>(2) { ".json", ".yml" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		[return: <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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;
		}

		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(2)]
		public static byte[] ReadEmbeddedFileBytes([<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(1)] string resourceFileName, Assembly containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
	public static class LocalizationManagerVersion
	{
		[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(1)]
		public const string Version = "1.4.1";
	}
}
namespace Recycle_N_Reclaim
{
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[BepInPlugin("Azumatt.Recycle_N_Reclaim", "Recycle_N_Reclaim", "1.4.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Recycle_N_ReclaimPlugin : BaseUnityPlugin
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)]
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[UsedImplicitly]
			public string Category;

			[UsedImplicitly]
			public Action<ConfigEntryBase> CustomDrawer;
		}

		[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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.4.4";

		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 = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName;

		internal static string ConnectionError = "";

		public static bool HasAuga;

		public static bool HasEpicLoot;

		private ContainerRecyclingButtonHolder _containerRecyclingButton;

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

		public static readonly ManualLogSource Recycle_N_ReclaimLogger = Logger.CreateLogSource("Recycle_N_Reclaim");

		internal static readonly ConfigSync ConfigSyncVar = new ConfigSync("Azumatt.Recycle_N_Reclaim")
		{
			DisplayName = "Recycle_N_Reclaim",
			CurrentVersion = "1.4.4",
			MinimumRequiredVersion = "1.4.4"
		};

		internal static readonly string yamlFileName = "Azumatt.Recycle_N_Reclaim_ExcludeLists.yml";

		internal static readonly string yamlPath = Paths.ConfigPath + Path.DirectorySeparatorChar + yamlFileName;

		internal static readonly CustomSyncedValue<string> RNRExcludeListData = new CustomSyncedValue<string>(ConfigSyncVar, "RNR_YamlData", "");

		internal static Root yamlData = new Root();

		internal static Dictionary<string, HashSet<string>> predefinedGroups = new Dictionary<string, HashSet<string>>();

		private static ConfigEntry<Toggle> _serverConfigLocked = null;

		public static ConfigEntry<Toggle> ApplyCraftedBy = null;

		public static ConfigEntry<KeyboardShortcut> hotKey = null;

		public static ConfigEntry<Toggle> discardInvEnabled = null;

		public static ConfigEntry<Toggle> lockToAdmin = null;

		public static ConfigEntry<Toggle> returnUnknownResources = null;

		public static ConfigEntry<Toggle> returnEnchantedResources = null;

		public static ConfigEntry<float> returnResources = null;

		private ConfigEntry<string> _stationFilterListString;

		public static List<string> StationFilterList = new List<string>();

		public static ConfigEntry<float> RecipeListScrollSpeedMultiplier = null;

		public static ConfigEntry<Toggle> StationFilterEnabled = null;

		public static ConfigEntry<Toggle> EnableExperimentalCraftingTabUI = null;

		public static ConfigEntry<Toggle> NotifyOnSalvagingImpediments = null;

		public static ConfigEntry<Toggle> PreventZeroResourceYields = null;

		public static ConfigEntry<Toggle> UnstackableItemsAlwaysReturnAtLeastOneResource = null;

		public static ConfigEntry<float> RecyclingRate = null;

		public static ConfigEntry<Toggle> ContainerRecyclingEnabled = null;

		public static ConfigEntry<Toggle> IgnoreItemsOnHotbar = null;

		public static ConfigEntry<Vector3> ContainerRecyclingButtonPositionJsonString = null;

		public static ConfigEntry<Toggle> AllowRecyclingUnknownRecipes = null;

		public static ConfigEntry<Toggle> DebugAlwaysDumpAnalysisContext = null;

		public static ConfigEntry<Toggle> DebugAllowSpammyLogs = null;

		public static ConfigEntry<Toggle> HideEquippedItemsInRecyclingTab = null;

		public static ConfigEntry<Toggle> RequireExactCraftingStationForRecycling = null;

		public static ConfigEntry<Toggle> returnEnchantedResourcesReclaiming = null;

		public static ConfigEntry<Color> BorderColorTrashedItem = null;

		public static ConfigEntry<Color> BorderColorTrashedSlot = null;

		public static ConfigEntry<bool> DisplayTooltipHint = null;

		public static ConfigEntry<bool> ShowRecycleYieldInTooltip = null;

		public static ConfigEntry<KeyboardShortcut> UndoRecycleKeybind = null;

		public static ConfigEntry<float> UndoRecycleGracePeriodSeconds = null;

		public static ConfigEntry<KeyboardShortcut> TrashingModifierKeybind1 = null;

		public static ConfigEntry<KeyboardShortcut> TrashingKeybind = null;

		public static ConfigEntry<string> TrashedSlotTooltip = null;

		public static StationRecyclingTabHolder RecyclingTabButtonHolder { get; private set; }

		private ConfigEntry<string> StationFilterListString
		{
			get
			{
				return _stationFilterListString;
			}
			set
			{
				_stationFilterListString = value;
				value.SettingChanged += [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (object sender, EventArgs args) =>
				{
					SplitNewValueAndSetProperty();
				};
				SplitNewValueAndSetProperty();
				void SplitNewValueAndSetProperty()
				{
					StationFilterList = (from entry in value.Value.Split(',')
						select entry.Trim()).ToList();
				}
			}
		}

		public void Awake()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			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);
			ApplyCraftedBy = config("1 - General", "Apply Crafted By", Toggle.On, "If on, the player will be the 'crafter' of each recycled item. If off, these values are empty");
			string text = "2 - Inventory Recycle";
			discardInvEnabled = config(text, "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(text, "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>(text, "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(text, "ReturnUnknownResources", Toggle.Off, "If on, discarding an item in the inventory will return resources if recipe is unknown");
			returnEnchantedResources = config(text, "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(text, "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 += [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (object sender, EventArgs args) =>
			{
				if (returnResources.Value > 1f)
				{
					returnResources.Value = 1f;
				}
				if (returnResources.Value < 0f)
				{
					returnResources.Value = 0f;
				}
			};
			string text2 = "While this & right click are held, hovering over items marks them for trashing. Releasing this will cancel trashing for all items.";
			BorderColorTrashedSlot = config<Color>(text, "BorderColorTrashedItem", new Color(1f, 0f, 0f), "Color of the border for slots containing Trashed items.", synchronizedSetting: false);
			DisplayTooltipHint = config(text, "DisplayTooltipHint", value: true, "Whether to add additional info the item tooltip of a Trashed or trash flagged item.", synchronizedSetting: false);
			ShowRecycleYieldInTooltip = config(text, "ShowRecycleYieldInTooltip", value: false, "If on, hovering an item will show what it would yield if recycled.", synchronizedSetting: false);
			TrashingKeybind = config<KeyboardShortcut>(text, "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>(text, "TrashingModifierKeybind1", new KeyboardShortcut((KeyCode)120, Array.Empty<KeyCode>()), text2 + ".", synchronizedSetting: false);
			TrashedSlotTooltip = config(text, "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 += [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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.");
			UndoRecycleKeybind = config<KeyboardShortcut>("3 - Reclaiming", "UndoRecycleKeybind", new KeyboardShortcut((KeyCode)122, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Keybind to undo the last reclaim from the Reclaim tab. Only works within the grace period.", synchronizedSetting: false);
			UndoRecycleGracePeriodSeconds = config("3 - Reclaiming", "UndoRecycleGracePeriodSeconds", 20f, "Number of seconds after a reclaim during which it can be undone. Set to 0 to disable undo entirely.");
			UndoRecycleGracePeriodSeconds.SettingChanged += [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (object sender, EventArgs args) =>
			{
				if (UndoRecycleGracePeriodSeconds.Value < 0f)
				{
					UndoRecycleGracePeriodSeconds.Value = 0f;
				}
			};
			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.");
			RecipeListScrollSpeedMultiplier = config("4 - UI", "RecipeListScrollSpeedMultiplier", 10f, "Multiplies how far the mouse wheel scrolls the crafting/reclaim recipe list.\nNewer Unity reports much smaller wheel deltas, which turned vanilla's 40 into a crawl.\n10 is the default. Set it to 1 for vanilla speed, or up to 20 if it still crawls (Linux\nand Proton are the worst for this).", synchronizedSetting: false);
			RecipeListScrollSpeedMultiplier.SettingChanged += [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (object _, EventArgs _) =>
			{
				RecipeListScroll.Apply();
			};
			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();
			HasEpicLoot = EpicLoot.IsLoaded();
			_containerRecyclingButton = ((Component)this).gameObject.AddComponent<ContainerRecyclingButtonHolder>();
			_containerRecyclingButton.OnRecycleAllTriggered += ContainerRecyclingTriggered;
			RecyclingTabButtonHolder = ((Component)this).gameObject.AddComponent<StationRecyclingTabHolder>();
			if (HasEpicLoot)
			{
				Recycle_N_ReclaimLogger.LogDebug((object)("Epic Loot " + EpicLoot.GetPluginVersion() + " 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<[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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<[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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);
		}
	}
	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;
		}
	}
	public static class ToggleExtensions
	{
		public static bool IsOn(this Recycle_N_ReclaimPlugin.Toggle toggle)
		{
			return toggle == Recycle_N_ReclaimPlugin.Toggle.On;
		}

		public static bool IsOff(this Recycle_N_ReclaimPlugin.Toggle toggle)
		{
			return toggle == Recycle_N_ReclaimPlugin.Toggle.Off;
		}
	}
}
namespace Recycle_N_Reclaim.YAMLStuff
{
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class PredefinedGroupGrab
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
		[HarmonyPriority(0)]
		private static void Postfix(ObjectDB __instance)
		{
			if (Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				GroupUtils.CreatePredefinedGroups(__instance);
				Reclaimer.BuildRecipeCache(__instance);
			}
		}
	}
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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: <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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>)([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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 float? GetRecycleRateOverride(string prefabName)
		{
			Dictionary<string, float> dictionary = Recycle_N_ReclaimPlugin.yamlData?.Reclaiming?.RecycleRates;
			if (dictionary == null || dictionary.Count == 0)
			{
				return null;
			}
			if (dictionary.TryGetValue(prefabName, out var value))
			{
				return Mathf.Clamp01(value);
			}
			foreach (KeyValuePair<string, float> item in dictionary)
			{
				if (Recycle_N_ReclaimPlugin.yamlData.Groups.TryGetValue(item.Key, out var value2) && value2.Contains(prefabName))
				{
					return Mathf.Clamp01(item.Value);
				}
			}
			return null;
		}

		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;
		}
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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; }
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	public class excludeContainer
	{
		[YamlMember(Alias = "exclude")]
		public List<string> Exclude { get; set; }

		[YamlMember(Alias = "includeOverride")]
		public List<string> IncludeOverride { get; set; }
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	public class Reclaiming
	{
		[YamlMember(Alias = "exclude")]
		public List<string> Exclude { get; set; }

		[YamlMember(Alias = "includeOverride")]
		public List<string> IncludeOverride { get; set; }

		[YamlMember(Alias = "recycleRates")]
		public Dictionary<string, float> RecycleRates { get; set; }
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	public class Inventory
	{
		[YamlMember(Alias = "exclude")]
		public List<string> Exclude { get; set; }

		[YamlMember(Alias = "includeOverride")]
		public List<string> IncludeOverride { get; set; }
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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));
			Root yamlData = Recycle_N_ReclaimPlugin.yamlData;
			if (yamlData.Groups == null)
			{
				Dictionary<string, List<string>> dictionary = (yamlData.Groups = new Dictionary<string, List<string>>());
			}
			yamlData = Recycle_N_ReclaimPlugin.yamlData;
			if (yamlData.Containers == null)
			{
				Dictionary<string, excludeContainer> dictionary3 = (yamlData.Containers = new Dictionary<string, excludeContainer>());
			}
			yamlData = Recycle_N_ReclaimPlugin.yamlData;
			if (yamlData.Reclaiming == null)
			{
				Reclaiming reclaiming = (yamlData.Reclaiming = new Reclaiming());
			}
			yamlData = Recycle_N_ReclaimPlugin.yamlData;
			if (yamlData.Inventory == null)
			{
				Inventory inventory = (yamlData.Inventory = new Inventory());
			}
			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.Managers
{
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	internal static class RecycleUndoManager
	{
		[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(2)]
		private static ItemData _lastItem;

		private static List<RecyclingAnalysisContext.ReclaimingYieldEntry> _lastEntries = new List<RecyclingAnalysisContext.ReclaimingYieldEntry>();

		private static float _recordedAt = float.MinValue;

		internal static bool CanUndo
		{
			get
			{
				if (_lastItem != null && Recycle_N_ReclaimPlugin.UndoRecycleGracePeriodSeconds.Value > 0f)
				{
					return Time.time - _recordedAt <= Recycle_N_ReclaimPlugin.UndoRecycleGracePeriodSeconds.Value;
				}
				return false;
			}
		}

		internal static void Record(ItemData item, List<RecyclingAnalysisContext.ReclaimingYieldEntry> entries)
		{
			_lastItem = item.Clone();
			_lastEntries = entries.Where((RecyclingAnalysisContext.ReclaimingYieldEntry e) => e.Amount > 0 && !e.InitialRecipeHadZero).ToList();
			_recordedAt = Time.time;
		}

		internal static void TryUndo()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (!CanUndo)
			{
				((Character)localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_undo_expired"), 0, (Sprite)null, false);
				Clear();
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			foreach (RecyclingAnalysisContext.ReclaimingYieldEntry lastEntry in _lastEntries)
			{
				if (inventory.CountItems(lastEntry.RecipeItemData.m_shared.m_name, -1, true) < lastEntry.Amount)
				{
					((Character)localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_undo_failed"), 0, (Sprite)null, false);
					Clear();
					return;
				}
			}
			List<RecyclingAnalysisContext.ReclaimingYieldEntry> list = new List<RecyclingAnalysisContext.ReclaimingYieldEntry>();
			foreach (RecyclingAnalysisContext.ReclaimingYieldEntry lastEntry2 in _lastEntries)
			{
				inventory.RemoveItem(lastEntry2.RecipeItemData.m_shared.m_name, lastEntry2.Amount, -1, true);
				list.Add(lastEntry2);
			}
			ItemData lastItem = _lastItem;
			if ((((Object)(object)lastItem.m_dropPrefab != (Object)null) ? inventory.AddItem(((Object)lastItem.m_dropPrefab).name, lastItem.m_stack, lastItem.m_quality, lastItem.m_variant, lastItem.m_crafterID, lastItem.m_crafterName, false, false) : null) == null)
			{
				bool flag = false;
				foreach (RecyclingAnalysisContext.ReclaimingYieldEntry item in list)
				{
					if (inventory.AddItem(((Object)item.Prefab).name, item.Amount, item.mQuality, item.mVariant, 0L, "", false, false) == null)
					{
						flag = true;
						Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogError((object)$"Undo rollback: failed to restore {item.Amount}x {((Object)item.Prefab).name} to inventory.");
					}
				}
				if (flag)
				{
					Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogError((object)"Undo rollback was incomplete. One or more resources could not be returned to inventory.");
				}
				((Character)localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_undo_failed"), 0, (Sprite)null, false);
				Clear();
			}
			else
			{
				((Character)localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_undo_success"), 0, (Sprite)null, false);
				Clear();
			}
		}

		internal static void Clear()
		{
			_lastItem = null;
			_lastEntries.Clear();
		}
	}
}
namespace Recycle_N_Reclaim.GamePatches
{
	[HarmonyPatch(typeof(InventoryGui), "UpdateItemDrag")]
	public static class UpdateItemDragPatch
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
		private static void Postfix(InventoryGui __instance, ItemData ___m_dragItem, Inventory ___m_dragInventory, int ___m_dragAmount, ref GameObject ___m_dragGo)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if ((!Recycle_N_ReclaimPlugin.lockToAdmin.Value.IsOn() || Recycle_N_ReclaimPlugin.ConfigSyncVar.IsAdmin) && !Recycle_N_ReclaimPlugin.discardInvEnabled.Value.IsOff())
			{
				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);
				}
			}
		}
	}
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	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;
		}
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	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;
		}

		[return: <7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(2)]
		public static GameObject FindItemPrefab(ItemData rItemData)
		{
			GameObject val = default(GameObject);
			if (ObjectDB.instance.TryGetItemPrefab(rItemData.m_shared, ref val) && (Object)(object)val != (Object)null)
			{
				return val;
			}
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if (!((Object)(object)item == (Object)null))
				{
					ItemDrop component = item.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && component.m_itemData?.m_shared != null && component.m_itemData.m_shared.m_name == rItemData.m_shared.m_name)
					{
						return item;
					}
				}
			}
			return null;
		}

		public static IEnumerable<int> SpentQualityLevels(Requirement req, ItemData item)
		{
			int maxQuality = item.m_shared.m_maxQuality;
			if (!req.m_upgraderResource)
			{
				return Enumerable.Range(1, Math.Max(0, Math.Min(item.m_quality, maxQuality)));
			}
			return Enumerable.Range(maxQuality + 1, Math.Max(0, item.m_quality - maxQuality));
		}

		public static void InventoryRecycleItem(ItemData ___m_dragItem, int ___m_dragAmount, Inventory ___m_dragInventory, InventoryGui __instance, GameObject ___m_dragGo)
		{
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Expected O, but got Unknown
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Expected O, but got Unknown
			//IL_05c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e0: Unknown result type (might be due to invalid IL or missing references)
			if (GroupUtils.IsPrefabExcludedInInventory(((Object)___m_dragItem.m_dropPrefab).name))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, ((Object)___m_dragItem.m_dropPrefab).name + " is blocked via ExcludeLists.yml file [inventory excludes]", 0, (Sprite)null, false);
				return;
			}
			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.IsOn() || 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();
					if (Recycle_N_ReclaimPlugin.HasEpicLoot && Recycle_N_ReclaimPlugin.returnEnchantedResources.Value.IsOn() && ___m_dragItem.IsMagicItem() && ___m_dragItem.TryGetRarity(out var rarity))
					{
						foreach (ItemAmount enchantCost in ___m_dragItem.GetEnchantCosts(rarity))
						{
							GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(enchantCost.Item);
							ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
							if (!((Object)(object)val == (Object)null))
							{
								Recipe recipe2 = ObjectDB.instance.GetRecipe(val.m_itemData);
								bool flag = (Object)(object)recipe2 != (Object)null && Player.m_localPlayer.IsRecipeKnown(val.m_itemData.m_shared.m_name);
								bool flag2 = Player.m_localPlayer.m_knownMaterial.Contains(val.m_itemData.m_shared.m_name);
								if (Recycle_N_ReclaimPlugin.returnUnknownResources.Value.IsOff() && (!flag || !flag2))
								{
									((Character)Player.m_localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_no_material_recipes"), 0, (Sprite)null, false);
									return;
								}
								list.Add(new Requirement
								{
									m_amount = (((Object)(object)recipe2 != (Object)null) ? recipe2.m_amount : enchantCost.Amount),
									m_resItem = val
								});
							}
						}
					}
					if (Jewelcrafting.API.IsLoaded() && Recycle_N_ReclaimPlugin.returnEnchantedResources.Value.IsOn() && Jewelcrafting.API.GetGems(___m_dragItem).Any())
					{
						foreach (KeyValuePair<ItemDrop, ItemData> item 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([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (ItemDrop itemDrop) => itemDrop, [<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (ItemDrop itemDrop) => itemDrop.m_itemData))
						{
							Recipe recipe3 = ObjectDB.instance.GetRecipe(item.Value);
							bool flag3 = (Object)(object)recipe3 != (Object)null && Player.m_localPlayer.IsRecipeKnown(item.Value.m_shared.m_name);
							bool flag4 = Player.m_localPlayer.m_knownMaterial.Contains(item.Value.m_shared.m_name);
							if (Recycle_N_ReclaimPlugin.returnUnknownResources.Value.IsOff() && (!flag3 || !flag4))
							{
								((Character)Player.m_localPlayer).Message((MessageType)2, Recycle_N_ReclaimPlugin.Localize("$azumatt_recycle_n_reclaim_no_material_recipes"), 0, (Sprite)null, false);
								return;
							}
							list.Add(new Requirement
							{
								m_amount = (((Object)(object)recipe3 != (Object)null) ? recipe3.m_amount : item.Value.m_stack),
								m_resItem = item.Key
							});
						}
					}
					if (___m_dragAmount / recipe.m_amount > 0)
					{
						for (int num = 0; num < ___m_dragAmount / recipe.m_amount; num++)
						{
							foreach (Requirement item2 in list)
							{
								foreach (int item3 in SpentQualityLevels(item2, ___m_dragItem))
								{
									GameObject val2 = FindItemPrefab(item2.m_resItem.m_itemData);
									if ((Object)(object)val2 == (Object)null)
									{
										continue;
									}
									ItemData itemData = val2.GetComponent<ItemDrop>().m_itemData.Clone();
									int num2 = Mathf.RoundToInt((float)item2.GetAmount(item3) * Recycle_N_ReclaimPlugin.returnResources.Value);
									Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogDebug((object)$"Returning {num2}/{item2.GetAmount(item3)} {((Object)val2).name}");
									while (num2 > 0)
									{
										int num3 = Mathf.Min(item2.m_resItem.m_itemData.m_shared.m_maxStackSize, num2);
										num2 -= num3;
										if (!GroupUtils.IsPrefabExcludedInInventory(Utils.GetPrefabName(val2)))
										{
											Player localPlayer = Player.m_localPlayer;
											Inventory inventory = ((Humanoid)localPlayer).GetInventory();
											if ((Recycle_N_ReclaimPlugin.ApplyCraftedBy.Value.IsOn() ? inventory.AddItem(((Object)val2).name, num3, item2.m_resItem.m_itemData.m_quality, item2.m_resItem.m_itemData.m_variant, localPlayer.GetPlayerID(), localPlayer.GetPlayerName(), false, false) : inventory.AddItem(((Object)val2).name, num3, item2.m_resItem.m_itemData.m_quality, item2.m_resItem.m_itemData.m_variant, 0L, "", false, false)) == null)
											{
												Transform transform;
												ItemDrop component = Object.Instantiate<GameObject>(val2, (transform = ((Component)Player.m_localPlayer).transform).position + transform.forward + transform.up, transform.rotation).GetComponent<ItemDrop>();
												component.m_itemData = itemData;
												component.m_itemData.m_dropPrefab = val2;
												component.m_itemData.m_stack = num3;
												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
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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.4.4");
			val.Write(RpcHandlers.ComputeHashForMod().Replace("-", ""));
			peer.m_rpc.Invoke("Recycle_N_Reclaim_VersionCheck", new object[1] { val });
		}
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	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
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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);
			}
		}
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	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.4.4 " + text3 + " remote: " + text + " " + text2));
			if (text2 != text3 || text != "1.4.4")
			{
				Recycle_N_ReclaimPlugin.ConnectionError = "Recycle_N_Reclaim Installed: 1.4.4 " + 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
{
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	public class ContainerRecyclingButtonHolder : MonoBehaviour
	{
		[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>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.IsOn());
			}
		}

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

		private void FixedUpdate()
		{
			if (!Recycle_N_ReclaimPlugin.ContainerRecyclingEnabled.Value.IsOff() && !((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();
			}
		}
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>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;
		}
	}
	[HarmonyPatch]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	public static class InventoryGuiPatches
	{
		[HarmonyPatch(typeof(InventoryGui), "OnTabCraftPressed")]
		[HarmonyPatch(typeof(InventoryGui), "OnTabUpgradePressed")]
		[HarmonyPriority(600)]
		[HarmonyPrefix]
		private static void OnTabCraftPressedAlsoEnableRecycling1(InventoryGui __instance)
		{
			Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.SetInteractable(interactable: true);
			__instance.UpdateCraftingPanel(false);
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
		[HarmonyPrefix]
		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);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe", new Type[]
		{
			typeof(Player),
			typeof(float)
		})]
		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;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Inventory), "Changed")]
		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.HasInventoryChanged(__instance))
			{
				Recycle_N_ReclaimPlugin.RecyclingTabButtonHolder.UpdateRecyclingList();
				InventoryGui.instance.SetRecipe(-1, false);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Update")]
		[HarmonyPostfix]
		private static void OnInventoryGuiUpdate()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (InventoryGui.IsVisible() && !((Object)(object)Player.m_localPlayer == (Object)null) && Recycle_N_ReclaimPlugin.UndoRecycleKeybind.Value.IsKeyDown() && RecycleUndoManager.CanUndo)
			{
				RecycleUndoManager.TryUndo();
			}
		}

		[HarmonyPatch(typeof(Humanoid), "EquipItem", new Type[]
		{
			typeof(ItemData),
			typeof(bool)
		})]
		[HarmonyPatch(typeof(Humanoid), "UnequipItem", new Type[]
		{
			typeof(ItemData),
			typeof(bool)
		})]
		[HarmonyPostfix]
		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);
			}
		}
	}
	[HarmonyPatch]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	public static class RecipeListScroll
	{
		private static ScrollRect _scrollRect;

		private static float _vanillaSensitivity = 40f;

		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		[HarmonyPostfix]
		private static void GrabScrollRect(InventoryGui __instance)
		{
			_scrollRect = FindRecipeScrollRect(__instance);
			if ((Object)(object)_scrollRect == (Object)null)
			{
				Recycle_N_ReclaimPlugin.Recycle_N_ReclaimLogger.LogWarning((object)"Couldn't find the recipe list ScrollRect, scroll speed setting won't do anything");
				return;
			}
			_vanillaSensitivity = _scrollRect.scrollSensitivity;
			Apply();
		}

		private static ScrollRect FindRecipeScrollRect(InventoryGui igui)
		{
			RectTransform root = igui.m_recipeListRoot;
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			ScrollRect componentInParent = ((Component)root).GetComponentInParent<ScrollRect>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent;
			}
			return ((IEnumerable<ScrollRect>)((Component)igui).GetComponentsInChildren<ScrollRect>(true)).FirstOrDefault((Func<ScrollRect, bool>)([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (ScrollRect sr) => (Object)(object)sr.content == (Object)(object)root));
		}

		public static void Apply()
		{
			if (!((Object)(object)_scrollRect == (Object)null))
			{
				_scrollRect.scrollSensitivity = _vanillaSensitivity * Mathf.Max(0.1f, Recycle_N_ReclaimPlugin.RecipeListScrollSpeedMultiplier.Value);
			}
		}
	}
	[<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(1)]
	[<7d1fb7d6-4194-4456-8d2c-bc2f90b17619>Nullable(0)]
	public class StationRecyclingTabHolder : MonoBehaviour
	{
		private GameObject _recyclingTabButtonGameObject;

		private Button _recyclingTabButtonComponent;

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

		private int _lastInventoryHash;

		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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: 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.HasEpicLoot)
					{
						_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> source = from context in Reclaimer.GetRecyclingAnalysisForInventory(((Humanoid)localPlayer).GetInventory(), localPlayer)
				where (Object)(object)context.Recipe != (Object)null && context.DisplayImpediments.Count == 0
				select context;
			_recyclingAnalysisContexts.AddRange(source.Where([<e5d5b7a5-49b3-4f19-b4c0-089ff50c8a6e>NullableContext(0)] (RecyclingAnalysisContext x) => !GroupUtils.IsPrefabExcludedInReclaiming(((Object)x.Item.m_dropPrefab).name)));
			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));
			_lastInventoryHash = ComputeInventoryHash(((Humanoid)localPlayer).GetInventory());
		}

		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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Expected O, but got Unknown
			//IL_032d: 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));
			if (Recycle_N_ReclaimPlugin.HasEpicLoot && context.RecyclingImpediments.Count == 0)
			{
				EpicLoot.ApplyMagicItemBackgroundToIcon(((Component)component).gameObject, context.Item);
			}
			TMP_Text component2 = ((Component)element.transform.Find("name")).GetComponent<TMP_Text>();
			bool flag = context.RecyclingImpediments.Count > 0;
			string text = Recycle_N_ReclaimPlugin.Localize(ItemDisplayName(context.Item, flag));
			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)(flag ? new Color(0.66f, 0.66f, 0.66f, 1f) : Color.white);
			GuiBar component3 = ((Component)element.transform.Find("Durability")).GetComponent<GuiBar>();
			if (context.Item.m_shared.m_useDurability && (double)context.Item.m_durability < (double)context.Item.G