Decompiled source of ExtraSlots v1.2.14

ExtraSlots.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using ConditionalConfigSync;
using ExtraSlots;
using ExtraSlots.Compatibility;
using ExtraSlots.HotBars;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.UI;
using YamlDotNet.Serialization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ExtraSlots")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ExtraSlots")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7e559c9a-ba1c-45b5-a260-ec3a1455248b")]
[assembly: AssemblyFileVersion("1.2.14")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.14.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace LocalizationManager
{
	[PublicAPI]
	public class Localizer
	{
		private const string defaultLanguage = "English";

		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;

		private static BaseUnityPlugin? _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin Plugin
		{
			get
			{
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: 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((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out string value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out Dictionary<string, Func<string>> value2))
			{
				text = value2.Aggregate(text, (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, Func<T, string>? convertConfigValue = null) where T : notnull
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += delegate
			{
				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 IEnumerator Load()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => PlatformManager.DistributionPlatform != null && PlatformInitializer.PreferencesInitialized));
			if (string.IsNullOrEmpty(PlatformPrefs.GetString("language", "")))
			{
				PlatformPrefs.SetString("language", "English");
			}
			LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage());
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> localizationFiles = new Dictionary<string, string>();
			string[] prefixes = new string[2]
			{
				Plugin.Info.Metadata.Name + ".",
				Plugin.Info.Metadata.Name.Replace(" ", "") + "."
			};
			Scan(Paths.ConfigPath, warn: true);
			byte[] array = LoadTranslationFromAssembly("English");
			if (array == null)
			{
				throw new Exception("Found no English localizations in mod " + Plugin.Info.Metadata.Name + ". Expected an embedded resource Translations/English.json or Translations/English.yml.");
			}
			Dictionary<string, string> dictionary = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array));
			if (dictionary == null)
			{
				throw new Exception("Localization for mod " + Plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text = null;
			if (language != "English")
			{
				if (localizationFiles.ContainsKey(language))
				{
					text = File.ReadAllText(localizationFiles[language]);
				}
				else
				{
					byte[] array2 = LoadTranslationFromAssembly(language);
					if (array2 != null)
					{
						text = Encoding.UTF8.GetString(array2);
					}
				}
			}
			if (text == null && localizationFiles.ContainsKey("English"))
			{
				text = File.ReadAllText(localizationFiles["English"]);
			}
			if (text != null)
			{
				Dictionary<string, string> dictionary2;
				try
				{
					dictionary2 = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text) ?? new Dictionary<string, string>();
				}
				catch (Exception arg)
				{
					global::ExtraSlots.ExtraSlots.LogWarning($"Failed to deserialize localization for language '{language}'. Using base localization only.\n{arg}");
					dictionary2 = new Dictionary<string, string>();
				}
				foreach (KeyValuePair<string, string> item in dictionary2)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			loadedTexts[language] = dictionary;
			foreach (KeyValuePair<string, string> item2 in dictionary)
			{
				UpdatePlaceholderText(__instance, item2.Key);
			}
			void Scan(string root, bool warn)
			{
				foreach (string item3 in from f in Directory.GetFiles(root, "*.*", SearchOption.AllDirectories)
					where fileExtensions.Contains(Path.GetExtension(f))
					select f)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item3);
					string[] array3 = prefixes;
					foreach (string text2 in array3)
					{
						if (fileNameWithoutExtension.StartsWith(text2))
						{
							string text3 = fileNameWithoutExtension.Substring(text2.Length);
							if (!string.IsNullOrWhiteSpace(text3))
							{
								if (localizationFiles.ContainsKey(text3))
								{
									if (warn)
									{
										global::ExtraSlots.ExtraSlots.LogWarning("Duplicate localization '" + text3 + "' for " + Plugin.Info.Metadata.Name + ". Skipping " + item3);
									}
								}
								else
								{
									localizationFiles[text3] = item3;
								}
							}
							break;
						}
					}
				}
			}
		}

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

		private static byte[]? LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("Translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
}
namespace ExtraSlots
{
	internal static class DebugLogging
	{
		[HarmonyPatch(typeof(Player), "CreateTombStone")]
		internal static class Player_CreateTombstone_LoggingItems
		{
			[HarmonyPriority(800)]
			private static void Prefix(Player __instance)
			{
				if (IsDebugEnabled && Slots.IsValidPlayer((Character)(object)__instance))
				{
					ExtraSlots.LogDebug("Player.CreateTombStone:Prefix Player Item List:");
					((Humanoid)__instance).GetInventory().LogInventory();
				}
			}

			[HarmonyPriority(0)]
			private static void Finalizer(Player __instance)
			{
				if (IsDebugEnabled && Slots.IsValidPlayer((Character)(object)__instance))
				{
					ExtraSlots.LogDebug("Player.CreateTombStone:Finalizer Player Item List:");
					((Humanoid)__instance).GetInventory().LogInventory();
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "MoveInventoryToGrave")]
		internal static class Inventory_MoveInventoryToGrave_LoggingItems
		{
			[HarmonyPriority(800)]
			private static void Prefix(Inventory __instance, Inventory original)
			{
				if (IsDebugEnabled)
				{
					ExtraSlots.LogDebug("Inventory.MoveInventoryToGrave:Prefix");
					ExtraSlots.LogDebug("From inventory " + GetInventoryState(original));
					original.LogInventory();
					ExtraSlots.LogDebug("To inventory " + GetInventoryState(__instance));
					__instance.LogInventory();
				}
			}

			[HarmonyPriority(0)]
			private static void Finalizer(Inventory __instance, Inventory original)
			{
				if (IsDebugEnabled)
				{
					ExtraSlots.LogDebug("Inventory.MoveInventoryToGrave:Finalizer");
					ExtraSlots.LogDebug("From inventory " + GetInventoryState(original));
					original.LogInventory();
					ExtraSlots.LogDebug("To inventory " + GetInventoryState(__instance));
					__instance.LogInventory();
				}
			}
		}

		internal static bool IsDebugEnabled => ExtraSlots.loggingEnabled.Value && ExtraSlots.loggingDebugEnabled.Value;

		internal static void LogItem(ItemData item)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsDebugEnabled)
			{
				return;
			}
			if (item == null)
			{
				ExtraSlots.LogDebug("<null item>");
				return;
			}
			object obj = item.m_shared?.m_name;
			if (obj == null)
			{
				GameObject dropPrefab = item.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "<unmaterialized item>";
			}
			string text = (string)obj;
			object obj2;
			if (item.m_shared != null)
			{
				Slots.Slot itemSlot = Slots.GetItemSlot(item);
				if (itemSlot != null)
				{
					obj2 = $"slot: {itemSlot} {itemSlot.GridPosition}";
					goto IL_008e;
				}
			}
			obj2 = "";
			goto IL_008e;
			IL_008e:
			string text2 = (string)obj2;
			ExtraSlots.LogDebug($"{text} {item.m_gridPos} stack:{item.m_stack} {text2}");
		}

		internal static string GetInventoryState(Inventory inventory)
		{
			object result;
			if (inventory != null)
			{
				object[] obj = new object[7] { inventory.m_name, inventory.m_temoraryInventory, null, null, null, null, null };
				Player localPlayer = Player.m_localPlayer;
				obj[2] = ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null) == inventory;
				obj[3] = inventory.m_width;
				obj[4] = inventory.m_height;
				obj[5] = inventory.m_totalWeight;
				obj[6] = inventory.m_inventory?.Count ?? 0;
				result = string.Format("name:{0} temporary:{1} isPlayer:{2} size:{3}x{4} weight:{5} items:{6}", obj);
			}
			else
			{
				result = "<null inventory>";
			}
			return (string)result;
		}

		internal static void LogInventory(this Inventory inventory)
		{
			if (!IsDebugEnabled || inventory?.m_inventory == null)
			{
				return;
			}
			foreach (ItemData item in from item in inventory.m_inventory
				orderby item?.m_gridPos.y ?? int.MaxValue, item?.m_gridPos.x ?? int.MaxValue
				select item)
			{
				LogItem(item);
			}
		}
	}
	public static class DeferredInventory
	{
		internal sealed class DeferredEntry
		{
			internal string PrefabName;

			internal string PreferredSlotId;

			internal bool RestoreEquipped;

			internal int OriginalStack;

			internal string ItemPackageBase64;

			internal bool PendingFinalization;
		}

		[HarmonyPatch(typeof(Player), "Load")]
		private static class Player_Load_ReadDeferredInventory
		{
			[HarmonyPriority(0)]
			private static void Postfix(Player __instance)
			{
				EnsureLoaded(__instance);
				ItemsSlotsValidation.ValidateItems();
				ItemsSlotsValidation.ValidateSlots();
				ItemsSlotsValidation.Validate();
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		private static class Player_Save_FlushDeferredInventory
		{
			[HarmonyPriority(800)]
			private static void Prefix(Player __instance)
			{
				if (__instance == statePlayer || (Object)(object)__instance == (Object)(object)Slots.CurrentPlayer)
				{
					Flush(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "MoveInventoryToGrave")]
		private static class Inventory_MoveInventoryToGrave_AppendDeferredItems
		{
			[HarmonyPriority(0)]
			private static void Postfix(Inventory __instance, Inventory original)
			{
				if (original == Slots.PlayerInventory)
				{
					MoveAllToTombstone(__instance);
				}
			}
		}

		public const string CustomDataKey = "ExtraSlotsDeferredInventory";

		public const int EnvelopeVersion = 1;

		private static readonly List<DeferredEntry> entries = new List<DeferredEntry>();

		private static readonly HashSet<string> unavailablePrefabsLogged = new HashSet<string>(StringComparer.Ordinal);

		private static Player statePlayer;

		private static string statePayload = "";

		private static bool storageAvailable = true;

		private static int revision;

		private static int lastAttemptRevision = -1;

		private static int lastRestorationFingerprint;

		private static bool hasLastRestorationFingerprint;

		public static int Count(Player player = null)
		{
			if (player == null)
			{
				player = Slots.CurrentPlayer;
			}
			return EnsureLoaded(player) ? entries.Count : 0;
		}

		internal static void InvalidateRestorationOpportunity()
		{
			lastAttemptRevision = -1;
			hasLastRestorationFingerprint = false;
		}

		internal static bool EnsureLoaded(Player player)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			string value;
			string text = (player.m_customData.TryGetValue("ExtraSlotsDeferredInventory", out value) ? (value ?? "") : "");
			if (statePlayer == player && string.Equals(statePayload, text, StringComparison.Ordinal))
			{
				return storageAvailable;
			}
			statePlayer = player;
			statePayload = text;
			entries.Clear();
			unavailablePrefabsLogged.Clear();
			storageAvailable = true;
			revision = 0;
			lastAttemptRevision = -1;
			hasLastRestorationFingerprint = false;
			if (string.IsNullOrEmpty(text))
			{
				return true;
			}
			try
			{
				ZPackage val = new ZPackage(text);
				int num = val.ReadInt();
				if (num != 1)
				{
					storageAvailable = false;
					ExtraSlots.LogWarning($"Deferred inventory uses unsupported envelope version {num}. Existing data will be left untouched.");
					return false;
				}
				int num2 = val.ReadInt();
				if (num2 < 0)
				{
					throw new InvalidOperationException($"Invalid deferred inventory entry count {num2}.");
				}
				for (int i = 0; i < num2; i++)
				{
					string prefabName = val.ReadString();
					string preferredSlotId = val.ReadString();
					bool restoreEquipped = val.ReadBool();
					int originalStack = val.ReadInt();
					string text2 = val.ReadString();
					if (string.IsNullOrEmpty(text2))
					{
						throw new InvalidOperationException($"Deferred inventory entry {i} has an empty item package.");
					}
					entries.Add(new DeferredEntry
					{
						PrefabName = prefabName,
						PreferredSlotId = preferredSlotId,
						RestoreEquipped = restoreEquipped,
						OriginalStack = originalStack,
						ItemPackageBase64 = text2
					});
				}
				ExtraSlots.LogDebug($"Deferred inventory loaded with {entries.Count} item(s).");
				return true;
			}
			catch (Exception arg)
			{
				entries.Clear();
				storageAvailable = false;
				ExtraSlots.LogWarning($"Failed to read deferred inventory. Existing data will be left untouched:\n{arg}");
				return false;
			}
		}

		internal static bool Flush(Player player = null)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			if (player == null)
			{
				player = statePlayer ?? Slots.CurrentPlayer;
			}
			if ((Object)(object)player == (Object)null || !EnsureLoaded(player) || !storageAvailable)
			{
				return false;
			}
			try
			{
				if (entries.Count == 0)
				{
					player.m_customData.Remove("ExtraSlotsDeferredInventory");
					statePayload = "";
					return true;
				}
				ZPackage val = new ZPackage();
				val.Write(1);
				val.Write(entries.Count);
				foreach (DeferredEntry entry in entries)
				{
					val.Write(entry.PrefabName ?? "");
					val.Write(entry.PreferredSlotId ?? "");
					val.Write(entry.RestoreEquipped);
					val.Write(entry.OriginalStack);
					val.Write(entry.ItemPackageBase64 ?? "");
				}
				statePayload = val.GetBase64();
				player.m_customData["ExtraSlotsDeferredInventory"] = statePayload;
				return true;
			}
			catch (Exception arg)
			{
				ExtraSlots.LogWarning($"Failed to persist deferred inventory:\n{arg}");
				return false;
			}
		}

		private static bool TryCreateEntry(ItemData item, string preferredSlotId, bool restoreEquipped, out DeferredEntry entry)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			entry = null;
			if (item == null)
			{
				return false;
			}
			GameObject dropPrefab = item.m_dropPrefab;
			string text = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			if (string.IsNullOrEmpty(text))
			{
				ExtraSlots.LogWarning("Cannot defer " + (item.m_shared?.m_name ?? "<unknown>") + ": item has no prefab reference.");
				return false;
			}
			try
			{
				ItemData val = item.Clone();
				val.m_equipped = false;
				val.m_gridPos = new Vector2i(0, 0);
				Inventory val2 = new Inventory("ExtraSlotsDeferredInventory", (Sprite)null, 1, 1);
				val2.m_inventory.Add(val);
				ZPackage val3 = new ZPackage();
				val2.Save(val3);
				ZPackage val4 = new ZPackage();
				val4.WriteCompressed(val3);
				entry = new DeferredEntry
				{
					PrefabName = text,
					PreferredSlotId = (preferredSlotId ?? ""),
					RestoreEquipped = restoreEquipped,
					OriginalStack = item.m_stack,
					ItemPackageBase64 = val4.GetBase64()
				};
				return true;
			}
			catch (Exception arg)
			{
				ExtraSlots.LogWarning($"Failed to serialize {item.m_shared?.m_name ?? text} for deferred inventory:\n{arg}");
				return false;
			}
		}

		private static bool TryMaterialize(DeferredEntry entry, out ItemData item)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			item = null;
			if (entry == null || string.IsNullOrEmpty(entry.PrefabName) || string.IsNullOrEmpty(entry.ItemPackageBase64))
			{
				return false;
			}
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)((instance != null) ? instance.GetItemPrefab(entry.PrefabName) : null) == (Object)null)
			{
				if (unavailablePrefabsLogged.Add(entry.PrefabName))
				{
					ExtraSlots.LogWarning("Deferred item prefab " + entry.PrefabName + " is unavailable. Its opaque item package will be preserved until the prefab exists again.");
				}
				return false;
			}
			try
			{
				ZPackage val = new ZPackage(entry.ItemPackageBase64);
				ZPackage package = val.ReadCompressedPackage();
				Inventory val2 = new Inventory("ExtraSlotsDeferredInventory", (Sprite)null, 1, 1);
				InventorySerialization.Load(val2, package);
				item = val2.m_inventory.FirstOrDefault();
				if (val2.m_inventory.Count == 1 && item != null)
				{
					GameObject dropPrefab = item.m_dropPrefab;
					if (string.Equals((dropPrefab != null) ? ((Object)dropPrefab).name : null, entry.PrefabName, StringComparison.Ordinal))
					{
						val2.m_inventory.Clear();
						item.m_equipped = false;
						if (item.m_stack != entry.OriginalStack)
						{
							ExtraSlots.LogWarning($"Deferred item {entry.PrefabName} stack changed while materializing ({entry.OriginalStack} -> {item.m_stack}). Original package will be preserved.");
							item = null;
							return false;
						}
						return true;
					}
				}
				ExtraSlots.LogWarning("Deferred item " + entry.PrefabName + " did not materialize as the expected single item. Original package will be preserved.");
				item = null;
				return false;
			}
			catch (Exception arg)
			{
				ExtraSlots.LogWarning($"Failed to materialize deferred item {entry.PrefabName}. Original package will be preserved:\n{arg}");
				item = null;
				return false;
			}
		}

		private static string CapturePreferredSlot(ItemData item)
		{
			if (item == null)
			{
				return "";
			}
			if (item.m_customData.TryGetValue("ExtraSlotsEquippedBy", out var value) && item.m_customData.TryGetValue("ExtraSlotsEquippedSlot", out var value2) && !string.IsNullOrEmpty(value2))
			{
				string text = value;
				PlayerProfile currentPlayerProfile = Slots.CurrentPlayerProfile;
				if (text == ((currentPlayerProfile != null) ? currentPlayerProfile.GetPlayerID().ToString() : null))
				{
					return value2;
				}
			}
			Slots.Slot itemSlot = Slots.GetItemSlot(item);
			return (itemSlot != null && !itemSlot.IsEmptySlot) ? itemSlot.ID : "";
		}

		private static void ApplyPreferredSlotMetadata(Player player, ItemData item, string preferredSlotId)
		{
			if (!((Object)(object)player == (Object)null) && item != null && !string.IsNullOrEmpty(preferredSlotId))
			{
				item.m_customData["ExtraSlotsEquippedBy"] = player.GetPlayerID().ToString();
				item.m_customData["ExtraSlotsEquippedSlot"] = preferredSlotId;
			}
		}

		private static void CancelTransientReferences(Player player, ItemData item)
		{
			if (!((Object)(object)player == (Object)null) && item != null)
			{
				while (player.IsEquipActionQueued(item))
				{
					((Humanoid)player).RemoveEquipAction(item);
				}
				player.m_actionQueue.RemoveAll((MinorActionData action) => action != null && action.m_item == item && ((int)action.m_type == 0 || (int)action.m_type == 1));
				InventoryGui instance = InventoryGui.instance;
				if ((Object)(object)instance != (Object)null && instance.m_dragItem == item)
				{
					instance.SetupDragItem((ItemData)null, (Inventory)null, 1);
				}
				if ((Object)(object)instance != (Object)null && instance.m_splitItem == item)
				{
					instance.OnSplitCancel();
				}
			}
		}

		internal static bool DeferExisting(ItemData item, string reason = null, string preferredSlotId = null, bool restoreEquipped = false)
		{
			Player currentPlayer = Slots.CurrentPlayer;
			Inventory playerInventory = Slots.PlayerInventory;
			if ((Object)(object)currentPlayer == (Object)null || playerInventory == null || item == null || !playerInventory.ContainsItem(item) || !EnsureLoaded(currentPlayer))
			{
				return false;
			}
			if (preferredSlotId == null)
			{
				preferredSlotId = CapturePreferredSlot(item);
			}
			bool restoreEquipped2 = restoreEquipped || item.m_equipped || ((Humanoid)currentPlayer).IsItemEquiped(item);
			ItemData val = item.Clone();
			val.m_equipped = false;
			ApplyPreferredSlotMetadata(currentPlayer, val, preferredSlotId);
			if (!TryCreateEntry(val, preferredSlotId, restoreEquipped2, out var entry))
			{
				return false;
			}
			entries.Add(entry);
			revision++;
			if (!Flush(currentPlayer))
			{
				entries.Remove(entry);
				revision++;
				return false;
			}
			CancelTransientReferences(currentPlayer, item);
			if (item.m_equipped || ((Humanoid)currentPlayer).IsItemEquiped(item))
			{
				((Humanoid)currentPlayer).UnequipItem(item, false);
			}
			item.m_equipped = false;
			if (!playerInventory.m_inventory.Remove(item))
			{
				entries.Remove(entry);
				revision++;
				Flush(currentPlayer);
				return false;
			}
			Slots.ClearCachedItems();
			PlayerInventoryOperations.MarkChanged(playerInventory);
			ExtraSlots.LogWarning("Item " + (item.m_shared?.m_name ?? entry.PrefabName) + " was moved to deferred inventory" + (string.IsNullOrEmpty(reason) ? "." : (" (" + reason + ").")));
			return true;
		}

		internal static bool EnqueueDetached(Player player, ItemData item, string preferredSlotId = null, bool restoreEquipped = false, string reason = null)
		{
			DeferredEntry handle;
			return EnqueueDetached(player, item, out handle, preferredSlotId, restoreEquipped, reason);
		}

		internal static bool EnqueueDetached(Player player, ItemData item, out DeferredEntry handle, string preferredSlotId = null, bool restoreEquipped = false, string reason = null, bool pendingFinalization = false)
		{
			handle = null;
			if ((Object)(object)player == (Object)null || item == null || !EnsureLoaded(player))
			{
				return false;
			}
			ItemData val = item.Clone();
			val.m_equipped = false;
			ApplyPreferredSlotMetadata(player, val, preferredSlotId);
			if (!TryCreateEntry(val, preferredSlotId, restoreEquipped || item.m_equipped, out var entry))
			{
				return false;
			}
			entry.PendingFinalization = pendingFinalization;
			entries.Add(entry);
			revision++;
			if (!Flush(player))
			{
				entries.Remove(entry);
				revision++;
				return false;
			}
			handle = entry;
			ExtraSlots.LogWarning("Item " + (item.m_shared?.m_name ?? entry.PrefabName) + " was added to deferred inventory" + (string.IsNullOrEmpty(reason) ? "." : (" (" + reason + ").")));
			return true;
		}

		internal static bool FinalizeDetachedReplacement(Player player, DeferredEntry handle, ItemData item)
		{
			if (handle != null)
			{
				handle.PendingFinalization = false;
				InvalidateRestorationOpportunity();
			}
			if (handle == null || item == null || !EnsureLoaded(player))
			{
				return false;
			}
			int num = entries.IndexOf(handle);
			if (num < 0)
			{
				return false;
			}
			bool flag = ((Humanoid)player).GetInventory().ContainsItem(item);
			DeferredEntry entry = null;
			if (!flag)
			{
				ItemData val = item.Clone();
				val.m_equipped = false;
				ApplyPreferredSlotMetadata(player, val, handle.PreferredSlotId);
				if (!TryCreateEntry(val, handle.PreferredSlotId, handle.RestoreEquipped, out entry))
				{
					return false;
				}
			}
			if (flag)
			{
				entries.RemoveAt(num);
			}
			else
			{
				entries[num] = entry;
			}
			revision++;
			if (Flush(player))
			{
				return true;
			}
			if (flag)
			{
				entries.Insert(num, handle);
			}
			else
			{
				entries[num] = handle;
			}
			revision++;
			return false;
		}

		internal static string GetMigrationKey(ItemData item)
		{
			if (item == null)
			{
				return "";
			}
			StringBuilder key = new StringBuilder();
			GameObject dropPrefab = item.m_dropPrefab;
			Append(((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "");
			Append(item.m_stack.ToString(CultureInfo.InvariantCulture));
			Append(item.m_quality.ToString(CultureInfo.InvariantCulture));
			Append(item.m_variant.ToString(CultureInfo.InvariantCulture));
			Append(item.m_durability.ToString("R", CultureInfo.InvariantCulture));
			Append(item.m_crafterID.ToString(CultureInfo.InvariantCulture));
			Append(item.m_crafterName ?? "");
			Append(item.m_worldLevel.ToString(CultureInfo.InvariantCulture));
			Append(item.m_pickedUp ? "1" : "0");
			Append(item.m_cheated ? "1" : "0");
			if (item.m_customData != null)
			{
				foreach (KeyValuePair<string, string> item2 in item.m_customData.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> pair) => pair.Key, StringComparer.Ordinal))
				{
					if (!(item2.Key == "ExtraSlotsEquippedBy") && !(item2.Key == "ExtraSlotsEquippedSlot") && !(item2.Key == "ExtraSlotsEquippedWeaponShield"))
					{
						Append(item2.Key ?? "");
						Append(item2.Value ?? "");
					}
				}
			}
			return key.ToString();
			void Append(string value)
			{
				key.Append(value.Length.ToString(CultureInfo.InvariantCulture));
				key.Append(':');
				key.Append(value);
				key.Append(';');
			}
		}

		internal static List<string> GetMaterializedMigrationKeys(Player player)
		{
			List<string> list = new List<string>();
			if ((Object)(object)player == (Object)null || !EnsureLoaded(player))
			{
				return list;
			}
			foreach (DeferredEntry entry in entries)
			{
				if (TryMaterialize(entry, out var item))
				{
					list.Add(GetMigrationKey(item));
				}
			}
			return list;
		}

		private static int ComputeRestorationFingerprint()
		{
			Inventory playerInventory = Slots.PlayerInventory;
			if (playerInventory?.m_inventory == null)
			{
				return 0;
			}
			int num = 17;
			num = num * 31 + playerInventory.m_width;
			num = num * 31 + Slots.InventoryHeightPlayer;
			num = num * 31 + Slots.InventoryHeightFull;
			foreach (ItemData item in playerInventory.m_inventory)
			{
				if (item == null)
				{
					continue;
				}
				int num2 = num * 31;
				GameObject dropPrefab = item.m_dropPrefab;
				int? obj;
				if (dropPrefab == null)
				{
					obj = null;
				}
				else
				{
					string name = ((Object)dropPrefab).name;
					obj = ((name != null) ? new int?(StringExtensionMethods.GetStableHashCode(name)) : ((int?)null));
				}
				int? num3 = obj;
				int valueOrDefault;
				if (!num3.HasValue)
				{
					SharedData shared = item.m_shared;
					int? obj2;
					if (shared == null)
					{
						obj2 = null;
					}
					else
					{
						string name2 = shared.m_name;
						obj2 = ((name2 != null) ? new int?(StringExtensionMethods.GetStableHashCode(name2)) : ((int?)null));
					}
					int? num4 = obj2;
					valueOrDefault = num4.GetValueOrDefault();
				}
				else
				{
					valueOrDefault = num3.GetValueOrDefault();
				}
				num = num2 + valueOrDefault;
				num = num * 31 + item.m_stack;
				num = num * 31 + item.m_quality;
				num = num * 31 + item.m_variant;
				num = num * 31 + item.m_worldLevel;
				num = num * 31 + ((item.m_gridPos.y < Slots.InventoryHeightPlayer) ? 1 : 2);
			}
			Slots.Slot[] slots = Slots.slots;
			foreach (Slots.Slot slot in slots)
			{
				num = num * 31 + StringExtensionMethods.GetStableHashCode(slot.ID);
				num = num * 31 + (slot.IsActive ? 1 : 0);
				num = num * 31 + (slot.IsFree ? 1 : 0);
			}
			return num;
		}

		internal static bool TryRestoreAvailable()
		{
			Player currentPlayer = Slots.CurrentPlayer;
			if ((Object)(object)currentPlayer == (Object)null || currentPlayer.m_isLoading || InventoryBackup.IsRecovering(currentPlayer) || Slots.PlayerInventory == null || !EnsureLoaded(currentPlayer) || entries.Count == 0)
			{
				return false;
			}
			int num = ComputeRestorationFingerprint();
			if (lastAttemptRevision == revision && hasLastRestorationFingerprint && lastRestorationFingerprint == num)
			{
				return false;
			}
			bool flag = false;
			using (PlayerInventoryOperations.Batch(Slots.PlayerInventory))
			{
				try
				{
					int num2 = 0;
					while (num2 < entries.Count)
					{
						DeferredEntry deferredEntry = entries[num2];
						if (deferredEntry.PendingFinalization || !TryMaterialize(deferredEntry, out var item))
						{
							num2++;
							continue;
						}
						ApplyPreferredSlotMetadata(currentPlayer, item, deferredEntry.PreferredSlotId);
						EquipmentAndQuickSlotsCompat.ApplyCurrentSlotMetadata(currentPlayer, item);
						InventorySlotsCompat.ApplyCurrentSlotMetadata(currentPlayer, item);
						if (!PlayerInventoryOperations.TryInsertDetachedToBestAvailable(item, deferredEntry.PreferredSlotId, deferredEntry.RestoreEquipped, out var placedItem, out var fullyInserted, out var madeProgress))
						{
							num2++;
						}
						else if (fullyInserted)
						{
							entries.RemoveAt(num2);
							revision++;
							flag = true;
							if (deferredEntry.RestoreEquipped && placedItem != null && placedItem.IsEquipable() && Slots.PlayerInventory.ContainsItem(placedItem) && !((Humanoid)currentPlayer).IsItemEquiped(placedItem))
							{
								try
								{
									((Humanoid)currentPlayer).EquipItem(placedItem, false);
								}
								catch (Exception arg)
								{
									ExtraSlots.LogWarning($"Deferred item {deferredEntry.PrefabName} was restored, but could not be equipped:\n{arg}");
								}
							}
							ExtraSlots.LogMessage("Deferred item " + deferredEntry.PrefabName + " was restored to player inventory.");
						}
						else
						{
							if (madeProgress && item.m_stack > 0 && TryCreateEntry(item, deferredEntry.PreferredSlotId, deferredEntry.RestoreEquipped, out var entry))
							{
								entries[num2] = entry;
								revision++;
								flag = true;
							}
							num2++;
						}
					}
				}
				finally
				{
					if (flag)
					{
						Flush(currentPlayer);
					}
				}
			}
			lastAttemptRevision = revision;
			lastRestorationFingerprint = ComputeRestorationFingerprint();
			hasLastRestorationFingerprint = true;
			return flag;
		}

		internal static bool MoveAllToTombstone(Inventory graveInventory)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			Player currentPlayer = Slots.CurrentPlayer;
			if ((Object)(object)currentPlayer == (Object)null || graveInventory == null || graveInventory.m_temoraryInventory || !EnsureLoaded(currentPlayer) || entries.Count == 0)
			{
				return false;
			}
			int height = graveInventory.m_height;
			bool flag = false;
			int num = 0;
			while (num < entries.Count)
			{
				DeferredEntry deferredEntry = entries[num];
				if (!TryMaterialize(deferredEntry, out var item))
				{
					num++;
					continue;
				}
				ApplyPreferredSlotMetadata(currentPlayer, item, deferredEntry.PreferredSlotId);
				item.m_equipped = false;
				Vector2i val = FindTombstoneAppendPosition(graveInventory, height);
				if (val.x < 0 && graveInventory.m_height <= 255)
				{
					graveInventory.m_height++;
					val = FindTombstoneAppendPosition(graveInventory, height);
				}
				int stack = item.m_stack;
				if (val.x < 0 || val.x > 255 || val.y > 255 || !graveInventory.AddItem(item, stack, val.x, val.y, false))
				{
					ExtraSlots.LogWarning("Unable to place deferred item " + deferredEntry.PrefabName + " into expanded tombstone inventory. Item remains deferred.");
					num++;
					continue;
				}
				entries.RemoveAt(num);
				revision++;
				flag = true;
				ExtraSlots.LogMessage("Deferred item " + deferredEntry.PrefabName + " was moved into tombstone inventory.");
			}
			if (flag)
			{
				Flush(currentPlayer);
			}
			return flag;
		}

		private static Vector2i FindTombstoneAppendPosition(Inventory inventory, int startHeight)
		{
			//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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			for (int i = Math.Max(0, startHeight); i < inventory.m_height; i++)
			{
				for (int j = 0; j < inventory.m_width; j++)
				{
					if (inventory.GetItemAt(j, i) == null)
					{
						return new Vector2i(j, i);
					}
				}
			}
			return Slots.emptyPosition;
		}
	}
	internal static class DeferredTombstone
	{
		private sealed class Entry
		{
			internal string PrefabName;

			internal string PreferredSlotId;

			internal bool RestoreEquipped;

			internal int OriginalStack;

			internal string ItemPackageBase64;
		}

		[HarmonyPatch(typeof(TombStone), "Setup")]
		private static class TombStone_Setup_TransferOpaqueDeferred
		{
			[HarmonyPriority(0)]
			private static void Postfix(TombStone __instance)
			{
				TransferRemainingPlayerPayload(__instance);
			}
		}

		[HarmonyPatch(typeof(TombStone), "Interact")]
		private static class TombStone_Interact_MaterializeOpaqueDeferred
		{
			[HarmonyPriority(0)]
			private static bool Prefix(TombStone __instance, Humanoid character, bool hold, bool alt, ref bool __result)
			{
				if (!HasPayload(__instance))
				{
					return true;
				}
				MaterializeAvailable(__instance);
				if (HasPayload(__instance))
				{
					Container container = __instance.m_container;
					if (container != null)
					{
						Inventory inventory = container.GetInventory();
						if (((inventory != null) ? new int?(inventory.NrOfItems()) : ((int?)null)) > 0)
						{
							goto IL_006e;
						}
					}
					if (hold)
					{
						return true;
					}
					__instance.m_localOpened = true;
					__result = (Object)(object)__instance.m_container != (Object)null && __instance.m_container.Interact(character, false, alt);
					return false;
				}
				goto IL_006e;
				IL_006e:
				return true;
			}
		}

		[HarmonyPatch(typeof(TombStone), "EasyFitInInventory")]
		private static class TombStone_EasyFitInInventory_OpaqueDeferredGuard
		{
			[HarmonyPriority(0)]
			private static void Postfix(TombStone __instance, ref bool __result)
			{
				if (HasPayload(__instance))
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(TombStone), "GetHoverText")]
		private static class TombStone_GetHoverText_ShowOpaqueDeferred
		{
			[HarmonyPriority(0)]
			private static void Postfix(TombStone __instance, ref string __result)
			{
				if (string.IsNullOrEmpty(__result) && HasPayload(__instance))
				{
					ZNetView nview = __instance.m_nview;
					if (nview != null && nview.IsValid())
					{
						string text = __instance.m_text + " " + __instance.GetOwnerName();
						__result = Localization.instance.Localize(text + "\n[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open");
					}
				}
			}
		}

		[HarmonyPatch]
		private static class Container_RPC_Response_MaterializeOpaqueDeferred
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return AccessTools.Method(typeof(Container), "RPC_OpenResponse", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(Container), "RPC_TakeAllResponse", (Type[])null, (Type[])null);
			}

			[HarmonyPriority(800)]
			private static void Prefix(Container __instance, bool granted)
			{
				if (!granted || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)__instance == (Object)null)
				{
					return;
				}
				TombStone componentInParent = ((Component)__instance).GetComponentInParent<TombStone>();
				if (componentInParent != null && HasPayload(componentInParent))
				{
					ZNetView nview = __instance.m_nview;
					if (nview != null)
					{
						nview.ClaimOwnership();
					}
					MaterializeAvailable(componentInParent);
				}
			}
		}

		[HarmonyPatch(typeof(TombStone), "UpdateDespawn")]
		private static class TombStone_UpdateDespawn_PreserveOpaqueDeferred
		{
			private static void Prefix(TombStone __instance, out bool __state)
			{
				__state = false;
				if (!HasPayload(__instance))
				{
					return;
				}
				MaterializeAvailable(__instance);
				if (HasPayload(__instance) && !((Object)(object)__instance.m_container == (Object)null) && !__instance.m_container.IsInUse())
				{
					Inventory inventory = __instance.m_container.GetInventory();
					if (inventory == null || inventory.NrOfItems() <= 0)
					{
						__instance.m_container.m_inUse = true;
						__state = true;
					}
				}
			}

			[HarmonyFinalizer]
			private static Exception Finalizer(TombStone __instance, bool __state, Exception __exception)
			{
				if (__state && (Object)(object)__instance?.m_container != (Object)null)
				{
					__instance.m_container.m_inUse = false;
				}
				return __exception;
			}
		}

		private const string PayloadKey = "ExtraSlotsDeferredTombstone";

		private static readonly int payloadHash = StringExtensionMethods.GetStableHashCode("ExtraSlotsDeferredTombstone");

		private static readonly HashSet<string> unavailablePrefabsLogged = new HashSet<string>(StringComparer.Ordinal);

		internal static bool HasPayload(TombStone tombstone)
		{
			return !string.IsNullOrEmpty(GetPayload(tombstone));
		}

		private static string GetPayload(TombStone tombstone)
		{
			if (tombstone != null)
			{
				ZNetView nview = tombstone.m_nview;
				if (((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true)
				{
					ZDO zDO = tombstone.m_nview.GetZDO();
					return ((zDO != null) ? zDO.GetString(payloadHash, "") : null) ?? "";
				}
			}
			return "";
		}

		private static bool TransferRemainingPlayerPayload(TombStone tombstone)
		{
			Player currentPlayer = Slots.CurrentPlayer;
			if (!((Object)(object)currentPlayer == (Object)null) && tombstone != null)
			{
				ZNetView nview = tombstone.m_nview;
				if (((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true && tombstone.m_nview.IsOwner())
				{
					if (!currentPlayer.m_customData.TryGetValue("ExtraSlotsDeferredInventory", out var value) || string.IsNullOrEmpty(value))
					{
						return false;
					}
					ZDO zDO = tombstone.m_nview.GetZDO();
					if (zDO == null)
					{
						return false;
					}
					string text = zDO.GetString(payloadHash, "");
					if (!string.IsNullOrEmpty(text) && !string.Equals(text, value, StringComparison.Ordinal))
					{
						ExtraSlots.LogWarning("Tombstone already contains a different opaque deferred payload. Player deferred data was preserved instead of overwriting grave ownership.");
						return false;
					}
					zDO.Set(payloadHash, value);
					if (!string.Equals(zDO.GetString(payloadHash, ""), value, StringComparison.Ordinal))
					{
						ExtraSlots.LogWarning("Failed to persist opaque deferred ownership on tombstone. Player deferred data was left intact.");
						return false;
					}
					currentPlayer.m_customData.Remove("ExtraSlotsDeferredInventory");
					DeferredInventory.EnsureLoaded(currentPlayer);
					ExtraSlots.LogMessage("Remaining opaque deferred item data was transferred to tombstone ownership.");
					return true;
				}
			}
			return false;
		}

		private static int MaterializeAvailable(TombStone tombstone)
		{
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Expected O, but got Unknown
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			if (tombstone != null)
			{
				ZNetView nview = tombstone.m_nview;
				if (((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true && tombstone.m_nview.IsOwner())
				{
					Container val = (((Object)(object)tombstone.m_container != (Object)null) ? tombstone.m_container : ((Component)tombstone).GetComponent<Container>());
					Inventory val2 = ((val != null) ? val.GetInventory() : null);
					if (val2 == null || val2.m_temoraryInventory || val.m_loading)
					{
						return 0;
					}
					val.Load();
					string payload = GetPayload(tombstone);
					if (string.IsNullOrEmpty(payload) || !TryReadPayload(payload, out var result))
					{
						return 0;
					}
					int height = val2.m_height;
					int num = 0;
					long owner = tombstone.GetOwner();
					int num2 = 0;
					while (num2 < result.Count)
					{
						Entry entry = result[num2];
						if (!TryMaterialize(entry, out var item))
						{
							num2++;
							continue;
						}
						if (!string.IsNullOrEmpty(entry.PreferredSlotId) && owner != 0)
						{
							item.m_customData["ExtraSlotsEquippedBy"] = owner.ToString();
							item.m_customData["ExtraSlotsEquippedSlot"] = entry.PreferredSlotId;
						}
						item.m_equipped = false;
						int height2 = val2.m_height;
						Vector2i val3 = FindAppendPosition(val2, height);
						if (val3.x < 0 && val2.m_height <= 255)
						{
							val2.m_height++;
							val3 = FindAppendPosition(val2, height);
						}
						if (val3.x < 0 || val3.x > 255 || val3.y > 255)
						{
							val2.m_height = height2;
							num2++;
							continue;
						}
						List<ItemData> collection = new List<ItemData>(val2.m_inventory);
						ZDO zDO = val.m_nview.GetZDO();
						byte[] array = zDO.GetByteArray(ZDOVars.s_items, (byte[])null);
						if (array == null)
						{
							ZPackage val4 = new ZPackage();
							val2.Save(val4);
							array = val4.GetArray();
						}
						string payload2 = GetPayload(tombstone);
						int height3 = val.m_height;
						bool loading = val.m_loading;
						try
						{
							val.m_loading = true;
							int stack = item.m_stack;
							if (!val2.AddItem(item, stack, val3.x, val3.y, false))
							{
								throw new InvalidOperationException("Unable to insert tombstone-owned item " + entry.PrefabName + ".");
							}
							val.m_height = Math.Max(val.m_height, val2.m_height);
							val.Save();
							result.RemoveAt(num2);
							PersistPayload(tombstone, result);
							val.m_lastRevision = zDO.DataRevision;
							num++;
						}
						catch (Exception arg)
						{
							val2.m_inventory.Clear();
							val2.m_inventory.AddRange(collection);
							val2.m_height = height2;
							val2.UpdateTotalWeight();
							val.m_height = height3;
							if (!result.Contains(entry))
							{
								result.Insert(num2, entry);
							}
							zDO.Set(ZDOVars.s_items, array);
							zDO.Set(payloadHash, payload2);
							PersistDimensions(val);
							val.m_lastRevision = zDO.DataRevision;
							ExtraSlots.LogWarning($"Tombstone materialization rolled back; opaque item {entry.PrefabName} was retained:\n{arg}");
							num2++;
						}
						finally
						{
							val.m_loading = loading;
						}
					}
					if (num > 0)
					{
						val.m_width = Math.Max(val.m_width, val2.m_width);
						val.m_height = Math.Max(val.m_height, val2.m_height);
						PersistDimensions(val);
					}
					return num;
				}
			}
			return 0;
		}

		private static bool TryReadPayload(string payload, out List<Entry> result)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			result = new List<Entry>();
			try
			{
				ZPackage val = new ZPackage(payload);
				int num = val.ReadInt();
				if (num != 1)
				{
					ExtraSlots.LogWarning($"Tombstone deferred payload uses unsupported envelope version {num}. Opaque data will remain attached to the grave.");
					return false;
				}
				int num2 = val.ReadInt();
				if (num2 < 0)
				{
					throw new InvalidOperationException($"Invalid tombstone deferred entry count {num2}.");
				}
				for (int i = 0; i < num2; i++)
				{
					string prefabName = val.ReadString();
					string preferredSlotId = val.ReadString();
					bool restoreEquipped = val.ReadBool();
					int originalStack = val.ReadInt();
					string text = val.ReadString();
					if (string.IsNullOrEmpty(text))
					{
						throw new InvalidOperationException($"Tombstone deferred entry {i} has an empty item package.");
					}
					result.Add(new Entry
					{
						PrefabName = prefabName,
						PreferredSlotId = preferredSlotId,
						RestoreEquipped = restoreEquipped,
						OriginalStack = originalStack,
						ItemPackageBase64 = text
					});
				}
				return true;
			}
			catch (Exception arg)
			{
				result.Clear();
				ExtraSlots.LogWarning($"Failed to read tombstone deferred payload. Opaque data will remain attached to the grave:\n{arg}");
				return false;
			}
		}

		private static bool TryMaterialize(Entry entry, out ItemData item)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			item = null;
			if (entry == null || string.IsNullOrEmpty(entry.PrefabName) || string.IsNullOrEmpty(entry.ItemPackageBase64))
			{
				return false;
			}
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)((instance != null) ? instance.GetItemPrefab(entry.PrefabName) : null) == (Object)null)
			{
				if (unavailablePrefabsLogged.Add(entry.PrefabName))
				{
					ExtraSlots.LogWarning("Tombstone deferred item prefab " + entry.PrefabName + " is unavailable. Opaque grave ownership will be preserved.");
				}
				return false;
			}
			try
			{
				ZPackage val = new ZPackage(entry.ItemPackageBase64);
				Inventory val2 = new Inventory("ExtraSlotsDeferredTombstone", (Sprite)null, 1, 1);
				InventorySerialization.Load(val2, val.ReadCompressedPackage());
				item = ((val2.m_inventory.Count == 1) ? val2.m_inventory[0] : null);
				if (item != null && item.m_stack == entry.OriginalStack)
				{
					GameObject dropPrefab = item.m_dropPrefab;
					if (string.Equals((dropPrefab != null) ? ((Object)dropPrefab).name : null, entry.PrefabName, StringComparison.Ordinal))
					{
						val2.m_inventory.Clear();
						item.m_equipped = false;
						return true;
					}
				}
				item = null;
				ExtraSlots.LogWarning("Tombstone deferred item " + entry.PrefabName + " did not materialize as the expected single stack. Opaque grave ownership will be preserved.");
				return false;
			}
			catch (Exception arg)
			{
				item = null;
				ExtraSlots.LogWarning($"Failed to materialize tombstone deferred item {entry.PrefabName}. Opaque grave ownership will be preserved:\n{arg}");
				return false;
			}
		}

		private static void PersistPayload(TombStone tombstone, IReadOnlyList<Entry> graveEntries)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			object obj;
			if (tombstone == null)
			{
				obj = null;
			}
			else
			{
				ZNetView nview = tombstone.m_nview;
				obj = ((nview != null) ? nview.GetZDO() : null);
			}
			ZDO val = (ZDO)obj;
			if (val == null)
			{
				return;
			}
			if (graveEntries == null || graveEntries.Count == 0)
			{
				val.Set(payloadHash, "");
				return;
			}
			ZPackage val2 = new ZPackage();
			val2.Write(1);
			val2.Write(graveEntries.Count);
			foreach (Entry graveEntry in graveEntries)
			{
				val2.Write(graveEntry.PrefabName ?? "");
				val2.Write(graveEntry.PreferredSlotId ?? "");
				val2.Write(graveEntry.RestoreEquipped);
				val2.Write(graveEntry.OriginalStack);
				val2.Write(graveEntry.ItemPackageBase64 ?? "");
			}
			val.Set(payloadHash, val2.GetBase64());
		}

		private static Vector2i FindAppendPosition(Inventory inventory, int startHeight)
		{
			//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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			for (int i = Math.Max(0, startHeight); i < inventory.m_height; i++)
			{
				for (int j = 0; j < inventory.m_width; j++)
				{
					if (inventory.GetItemAt(j, i) == null)
					{
						return new Vector2i(j, i);
					}
				}
			}
			return Slots.emptyPosition;
		}

		private static bool PersistDimensions(Container container)
		{
			if (container != null)
			{
				ZNetView nview = container.m_nview;
				if (((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true && container.m_nview.IsOwner() && !((Object)(object)((Component)container).GetComponentInParent<TombStone>() == (Object)null))
				{
					string name = ((object)container).GetType().Name;
					ZDO zDO = container.m_nview.GetZDO();
					zDO.Set("HasFields", true);
					zDO.Set(StringExtensionMethods.GetStableHashCode("HasFields" + name), true);
					zDO.Set(name + ".m_width", container.m_width);
					zDO.Set(name + ".m_height", container.m_height);
					return true;
				}
			}
			return false;
		}
	}
	public static class ItemNameTokens
	{
		[HarmonyPatch(typeof(Player), "Load")]
		private static class Player_Load_UpdateRegisters
		{
			private static void Prefix()
			{
				UpdateRegisters();
			}
		}

		public static readonly Dictionary<string, string> itemNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		public static void UpdateRegisters()
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return;
			}
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (component == null)
				{
					continue;
				}
				ItemData itemData = component.m_itemData;
				if (itemData != null)
				{
					SharedData shared = itemData.m_shared;
					if (shared != null && shared.m_name.StartsWith("$"))
					{
						itemNames[((Object)item).name] = shared.m_name;
						itemNames[shared.m_name] = shared.m_name;
					}
				}
			}
			Slots.UpdateCustomItemLists();
			ExtraUtilitySlots.UpdateUniqueEquipped();
			TombStoneInteraction.UpdateItemLists();
		}

		public static string GetItemName(this string input)
		{
			return itemNames.GetValueOrDefault(input.Trim(), input);
		}
	}
	public static class LightenedSlots
	{
		private static readonly List<int> m_affectedRows = new List<int>();

		public static bool IsEnabled => ExtraSlots.lightenedSlotsStartIndex.Value != 0;

		public static float WeightFactor => ExtraSlots.lightenedSlotsWeightFactor.Value;

		public static bool IsRowAffected(int row)
		{
			return IsEnabled && m_affectedRows.Contains(row);
		}

		public static void UpdateState()
		{
			UpdateAffectedRows();
			InventoryInteraction.UpdateTotalWeight();
		}

		public static void UpdateAffectedRows()
		{
			m_affectedRows.Clear();
			if (!IsEnabled || !SlotsProgression.IsPlayerKeyItemConditionMet(ExtraSlots.lightenedSlotsPlayerKey.Value, ExtraSlots.lightenedSlotsItemDiscovered.Value))
			{
				return;
			}
			for (int i = 0; i < Slots.InventoryHeightPlayer; i++)
			{
				if (!ExtraSlots.lightenedSlotsOnlyExtraRows.Value || i >= Slots.NativeInventoryHeight)
				{
					if (ExtraSlots.lightenedSlotsStartIndex.Value < 0 && i >= ExtraSlots.lightenedSlotsStartIndex.Value + Slots.InventoryHeightPlayer)
					{
						m_affectedRows.Add(i);
					}
					else if (ExtraSlots.lightenedSlotsStartIndex.Value > 0 && i >= ExtraSlots.lightenedSlotsStartIndex.Value - 1)
					{
						m_affectedRows.Add(i);
					}
				}
			}
		}
	}
	internal class CustomConfigs
	{
		internal class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public Action<ConfigEntryBase>? CustomDrawer;
		}

		internal static object? configManager;

		internal static Type? configManagerStyles;

		internal static GUIStyle GetStyle(GUIStyle other)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			if (configManagerStyles == null)
			{
				return other;
			}
			FieldInfo fieldInfo = AccessTools.Field(configManagerStyles, "fontSize");
			if (fieldInfo == null)
			{
				return other;
			}
			return new GUIStyle(other)
			{
				fontSize = (int)fieldInfo.GetValue(configManagerStyles)
			};
		}

		internal static void Awake()
		{
			Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ConfigurationManager");
			Type type = assembly?.GetType("ConfigurationManager.ConfigurationManager");
			configManager = ((type == null) ? null : Chainloader.ManagerObject.GetComponent(type));
			configManagerStyles = assembly?.GetType("ConfigurationManager.ConfigurationManagerStyles");
		}

		internal static Action<ConfigEntryBase> DrawSeparatedStrings(string splitString)
		{
			return delegate(ConfigEntryBase cfg)
			{
				//IL_010a: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0125: Expected O, but got Unknown
				//IL_0155: Unknown result type (might be due to invalid IL or missing references)
				//IL_015a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0170: Expected O, but got Unknown
				bool valueOrDefault = cfg.Description.Tags.Select((object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : ((bool?)null)).FirstOrDefault((bool? v) => v.HasValue) == true;
				bool flag = false;
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				List<string> list = new List<string>();
				List<string> list2 = ((string)cfg.BoxedValue).Split(new string[1] { splitString }, StringSplitOptions.None).ToList();
				for (int num = 0; num < list2.Count; num++)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string text = list2[num];
					string text2 = GUILayout.TextField(text, GetStyle(GUI.skin.textArea), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
					if (text2 != text && !valueOrDefault)
					{
						flag = true;
					}
					if (GUILayout.Button("x", new GUIStyle(GetStyle(GUI.skin.button))
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault)
					{
						flag = true;
					}
					else
					{
						list.Add(text2);
					}
					if (GUILayout.Button("+", new GUIStyle(GetStyle(GUI.skin.button))
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault)
					{
						flag = true;
						list.Add("");
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = string.Join(splitString, list);
				}
			};
		}

		internal static Action<ConfigEntryBase> DrawOrderedFixedStrings(string splitString)
		{
			return delegate(ConfigEntryBase cfg)
			{
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ff: Expected O, but got Unknown
				//IL_015b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0160: Unknown result type (might be due to invalid IL or missing references)
				//IL_0176: Expected O, but got Unknown
				bool valueOrDefault = cfg.Description.Tags.Select((object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : ((bool?)null)).FirstOrDefault((bool? v) => v.HasValue) == true;
				bool flag = false;
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				string[] array = ((string)cfg.BoxedValue).Split(new string[1] { splitString }, StringSplitOptions.None).ToArray();
				for (int num = 0; num < array.Length; num++)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string text = array[num];
					GUILayout.Label(text, GetStyle(GUI.skin.textArea), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
					if (GUILayout.Button("ʌ", new GUIStyle(GetStyle(GUI.skin.button))
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault && (flag = num > 0))
					{
						ref string reference = ref array[num];
						ref string reference2 = ref array[num - 1];
						string text2 = array[num - 1];
						string text3 = array[num];
						reference = text2;
						reference2 = text3;
					}
					if (GUILayout.Button("v", new GUIStyle(GetStyle(GUI.skin.button))
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault && (flag = num < array.Length - 1))
					{
						ref string reference = ref array[num];
						ref string reference3 = ref array[num + 1];
						string text3 = array[num + 1];
						string text2 = array[num];
						reference = text3;
						reference3 = text2;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = string.Join(splitString, array);
				}
			};
		}
	}
	public static class EquipmentPanel
	{
		public class SidePanelDefaults
		{
			public bool active;

			public Vector2 anchoredPosition = Vector2.zero;

			public Vector2 anchorMin = Vector2.zero;

			public Vector2 anchorMax = Vector2.zero;
		}

		private static class SlotPositions
		{
			private static int Column(int i)
			{
				return i / 3;
			}

			private static int Row(int i)
			{
				return i % 3;
			}

			private static int LastEquipmentRow()
			{
				return Row(equipmentSlotsCount - 1);
			}

			internal static int LastEquipmentColumn()
			{
				return Column(equipmentSlotsCount - 1);
			}

			internal static Vector2 GetEquipmentTileOffset(int i)
			{
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: 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)
				int x = Column(i) * 4 + ((ExtraSlots.equipmentSlotsAlignment.Value == ExtraSlots.SlotsAlignment.VerticalTopHorizontalMiddle && Row(i) > LastEquipmentRow()) ? 1 : 0) * 2 + Math.Max(quickSlotsCount - 1 - LastEquipmentColumn(), 0) * 2;
				int y = Row(i) * 4 + Math.Max((ExtraSlots.equipmentSlotsAlignment.Value == ExtraSlots.SlotsAlignment.VerticalMiddleHorizontalLeft && Column(i) == LastEquipmentColumn()) ? (2 - LastEquipmentRow()) : 0, 0) * 2;
				return GetSlotPosition(x, y);
			}

			internal static Vector2 GetQuickSlotTileOffset(int i)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				int x = i * 4 + Math.Max(ExtraSlots.quickSlotsAlignmentCenter.Value ? (LastEquipmentColumn() + 1 - quickSlotsCount) : 0, 0);
				int y = EquipmentHeight * 4 + 1;
				return GetSlotPosition(x, y);
			}

			internal static Vector2 GetFoodSlotTileOffset(int i)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				int x = Math.Max(LastEquipmentColumn() + 1, quickSlotsCount) * 4 + 1;
				int y = i * 4;
				return GetSlotPosition(x, y);
			}

			internal static Vector2 GetAmmoSlotTileOffset(int i)
			{
				//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)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				int x = Math.Max(LastEquipmentColumn() + 1, quickSlotsCount) * 4 + 1 + (Slots.IsFoodSlotAvailable() ? 4 : 0);
				int y = i * 4;
				return GetSlotPosition(x, y);
			}

			internal static Vector2 GetMiscSlotTileOffset(int i)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				int x = Math.Max(LastEquipmentColumn() + 1, quickSlotsCount) * 4 + i * 4 + 1;
				int y = EquipmentHeight * 4 + 1;
				return GetSlotPosition(x, y);
			}

			private static Vector2 GetSlotPosition(int x, int y)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				return PanelPosition + new Vector2((float)x * 70f / 4f, (float)(-y) * 70f / 4f);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static class InventoryGui_Show_UpdatePanel
		{
			private static void Postfix()
			{
				if (!((Object)(object)Player.m_localPlayer == (Object)null))
				{
					UpdatePanel();
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnDestroy")]
		private static class InventoryGui_OnDestroy_ClearObjects
		{
			private static void Postfix()
			{
				ClearPanel();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Update")]
		private static class InventoryGui_Update_UpdateEquipmentPanel
		{
			private static void Postfix()
			{
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && InventoryGui.IsVisible())
				{
					UpdateEquipmentBackground();
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		internal static class InventoryGrid_UpdateGui_UpdateSlotsOnDirty
		{
			private static void Prefix(InventoryGrid __instance, ref int __state)
			{
				if (!((Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid))
				{
					__state = __instance.m_elements.Count;
				}
			}

			private static void Postfix(InventoryGrid __instance, int __state)
			{
				if (!((Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid))
				{
					if (__state != __instance.m_elements.Count)
					{
						MarkDirty();
					}
					UpdateInventorySlots();
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupDragItem")]
		private static class InventoryGui_SetupDragItem_UpdateSlotsOnItemDrag
		{
			private static void Prefix(InventoryGui __instance, ref bool __state)
			{
				__state = Object.op_Implicit((Object)(object)__instance.m_dragGo);
			}

			private static void Postfix(InventoryGui __instance, bool __state)
			{
				MarkDirty();
				if (!Object.op_Implicit((Object)(object)__instance.m_dragGo) && __state)
				{
					UpdateSidePanels();
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGamepad")]
		public static class InventoryGrid_UpdateGamepad_GamepadSupport
		{
			public static Vector2i FindEquipmentSlot(int row = -1, Slots.Slot slotRow = null, int col = -1, Slots.Slot slotCol = null, bool right = false, Slots.Slot before = null, Slots.Slot after = null)
			{
				//IL_010b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0110: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
				Slots.Slot[] equipmentSlots = Slots.GetEquipmentSlots();
				if (row == -1 && slotRow != null)
				{
					row = Array.IndexOf(equipmentSlots, slotRow) % 3;
				}
				if (col == -1 && slotCol != null)
				{
					col = Array.IndexOf(equipmentSlots, slotCol) / 3;
				}
				int num = ((before == null) ? (-1) : Array.IndexOf(equipmentSlots, before));
				int num2 = ((after == null) ? (-1) : Array.IndexOf(equipmentSlots, after));
				int num3 = (right ? equipmentSlots.Length : (-1));
				while (true)
				{
					num3 = ((!right) ? (num3 + 1) : (num3 - 1));
					if (num3 < 0 || num3 == equipmentSlots.Length)
					{
						break;
					}
					if ((num <= -1 || num3 < num) && (num2 <= -1 || num3 > num2))
					{
						if (row == -1 && col == -1)
						{
							return equipmentSlots[num3].GridPosition;
						}
						if ((row != -1 && row == num3 % 3) || (col != -1 && col == num3 / 3))
						{
							return equipmentSlots[num3].GridPosition;
						}
					}
				}
				return Slots.emptyPosition;
			}

			private static bool Prefix(InventoryGrid __instance)
			{
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0378: Unknown result type (might be due to invalid IL or missing references)
				//IL_0158: Unknown result type (might be due to invalid IL or missing references)
				//IL_015d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_0182: Unknown result type (might be due to invalid IL or missing references)
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_0502: Unknown result type (might be due to invalid IL or missing references)
				//IL_0308: Unknown result type (might be due to invalid IL or missing references)
				//IL_030d: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_07a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_033c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0341: Unknown result type (might be due to invalid IL or missing references)
				//IL_0220: Unknown result type (might be due to invalid IL or missing references)
				//IL_0225: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_056e: Unknown result type (might be due to invalid IL or missing references)
				//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_066f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0674: Unknown result type (might be due to invalid IL or missing references)
				//IL_0525: Unknown result type (might be due to invalid IL or missing references)
				//IL_052a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0416: Unknown result type (might be due to invalid IL or missing references)
				//IL_041b: Unknown result type (might be due to invalid IL or missing references)
				//IL_09ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_07ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0804: Unknown result type (might be due to invalid IL or missing references)
				//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0842: Unknown result type (might be due to invalid IL or missing references)
				//IL_0847: Unknown result type (might be due to invalid IL or missing references)
				//IL_076c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0771: Unknown result type (might be due to invalid IL or missing references)
				//IL_0591: Unknown result type (might be due to invalid IL or missing references)
				//IL_0596: Unknown result type (might be due to invalid IL or missing references)
				//IL_0482: Unknown result type (might be due to invalid IL or missing references)
				//IL_0487: Unknown result type (might be due to invalid IL or missing references)
				//IL_0469: Unknown result type (might be due to invalid IL or missing references)
				//IL_046e: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_0292: Unknown result type (might be due to invalid IL or missing references)
				//IL_0297: Unknown result type (might be due to invalid IL or missing references)
				//IL_0993: Unknown result type (might be due to invalid IL or missing references)
				//IL_0998: Unknown result type (might be due to invalid IL or missing references)
				//IL_092a: Unknown result type (might be due to invalid IL or missing references)
				//IL_092f: Unknown result type (might be due to invalid IL or missing references)
				//IL_06e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0655: Unknown result type (might be due to invalid IL or missing references)
				//IL_065a: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_0be2: Unknown result type (might be due to invalid IL or missing references)
				//IL_09b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_09b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_0950: Unknown result type (might be due to invalid IL or missing references)
				//IL_0955: Unknown result type (might be due to invalid IL or missing references)
				//IL_08ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_08bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_08c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0607: Unknown result type (might be due to invalid IL or missing references)
				//IL_060c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0970: Unknown result type (might be due to invalid IL or missing references)
				//IL_0975: Unknown result type (might be due to invalid IL or missing references)
				//IL_0899: Unknown result type (might be due to invalid IL or missing references)
				//IL_089e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0743: Unknown result type (might be due to invalid IL or missing references)
				//IL_0748: Unknown result type (might be due to invalid IL or missing references)
				//IL_0a4e: Unknown result type (might be due to invalid IL or missing references)
				//IL_08ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_08f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0b62: Unknown result type (might be due to invalid IL or missing references)
				//IL_0b2f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0b34: Unknown result type (might be due to invalid IL or missing references)
				//IL_0afc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0b01: Unknown result type (might be due to invalid IL or missing references)
				//IL_0b56: Unknown result type (might be due to invalid IL or missing references)
				//IL_0b5b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0ab3: Unknown result type (might be due to invalid IL or missing references)
				//IL_0ab8: Unknown result type (might be due to invalid IL or missing references)
				//IL_0ba6: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid || !__instance.m_uiGroup.IsActive || Console.IsVisible() || ZInput.IsTouchActive() || !ZInput.IsExclusiveGamepadActive())
				{
					return true;
				}
				Slots.Slot slotInGrid = Slots.GetSlotInGrid(__instance.m_selected);
				if (ZInput.GetButtonDown("JoyDPadLeft") || ZInput.GetButtonDown("JoyLStickLeft"))
				{
					ExtraSlots.LogDebug($"From {__instance.m_selected} {slotInGrid} left");
					if (slotInGrid != null)
					{
						if (slotInGrid.IsAmmoSlot)
						{
							__instance.m_selected.x += 3;
							Slots.Slot slotInGrid2 = Slots.GetSlotInGrid(__instance.m_selected);
							if (slotInGrid2 == null || !slotInGrid2.IsActive)
							{
								int num = __instance.m_selected.x % 3;
								__instance.m_selected = FindEquipmentSlot(num, null, -1, null, right: true);
								if (__instance.m_selected == Slots.emptyPosition)
								{
									__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, num);
								}
							}
						}
						else if (slotInGrid.IsFoodSlot)
						{
							int num2 = __instance.m_selected.x % 3;
							__instance.m_selected = FindEquipmentSlot(num2, null, -1, null, right: true);
							if (__instance.m_selected == Slots.emptyPosition)
							{
								__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, num2);
							}
						}
						else if (slotInGrid.IsQuickSlot)
						{
							__instance.m_selected.x--;
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, 3);
							}
						}
						else if (slotInGrid.IsMiscSlot)
						{
							__instance.m_selected.x--;
							Slots.Slot slotInGrid3 = Slots.GetSlotInGrid(__instance.m_selected);
							if (slotInGrid3 == null)
							{
								__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, 3);
							}
							else if (!slotInGrid3.IsActive)
							{
								if (slotInGrid3.IsQuickSlot)
								{
									IEnumerable<Slots.Slot> source = from slot3 in Slots.GetQuickSlots()
										where slot3.IsActive
										select slot3;
									if (source.Any())
									{
										__instance.m_selected = source.Last().GridPosition;
									}
									else
									{
										__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, 3);
									}
								}
								else if (slotInGrid3.IsMiscSlot && quickSlotsCount == 0)
								{
									__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, 3);
								}
								else
								{
									__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, 3);
								}
							}
						}
						else
						{
							__instance.m_selected = FindEquipmentSlot(-1, slotInGrid, -1, null, right: true, slotInGrid);
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = new Vector2i(Slots.InventoryWidth - 1, Array.IndexOf(Slots.GetEquipmentSlots(), slotInGrid) % 3);
							}
						}
						return false;
					}
				}
				if (ZInput.GetButtonDown("JoyDPadRight") || ZInput.GetButtonDown("JoyLStickRight"))
				{
					ExtraSlots.LogDebug($"From {__instance.m_selected} {slotInGrid} right");
					if (slotInGrid != null)
					{
						if (slotInGrid.IsFoodSlot)
						{
							Slots.Slot slotInGrid4 = Slots.GetSlotInGrid(new Vector2i(__instance.m_selected.x - 3, __instance.m_selected.y));
							if (slotInGrid4 != null && slotInGrid4.IsActive)
							{
								__instance.m_selected = slotInGrid4.GridPosition;
							}
						}
						else
						{
							if (slotInGrid.IsAmmoSlot)
							{
								return false;
							}
							if (slotInGrid.IsMiscSlot)
							{
								Slots.Slot slotInGrid5 = Slots.GetSlotInGrid(new Vector2i(__instance.m_selected.x + 1, __instance.m_selected.y));
								if (slotInGrid5 != null && slotInGrid5.IsActive)
								{
									__instance.m_selected = slotInGrid5.GridPosition;
								}
							}
							else if (slotInGrid.IsQuickSlot)
							{
								if (__instance.m_selected.x < quickSlotsCount - 1)
								{
									Slots.Slot slotInGrid6 = Slots.GetSlotInGrid(new Vector2i(__instance.m_selected.x + 1, __instance.m_selected.y));
									if (slotInGrid6 != null && slotInGrid6.IsActive)
									{
										__instance.m_selected = slotInGrid6.GridPosition;
									}
								}
								else
								{
									IEnumerable<Slots.Slot> source2 = from slot3 in Slots.GetMiscSlots()
										where slot3.IsActive
										select slot3;
									if (source2.Any())
									{
										__instance.m_selected = source2.First().GridPosition;
									}
								}
							}
							else
							{
								__instance.m_selected = FindEquipmentSlot(-1, slotInGrid, -1, null, right: false, null, slotInGrid);
								if (__instance.m_selected.x < 0)
								{
									Slots.Slot[] array = (from slot3 in Slots.GetFoodSlots()
										where slot3.IsActive
										select slot3).ToArray();
									if (array.Length == 3)
									{
										__instance.m_selected = array[Array.IndexOf(Slots.GetEquipmentSlots(), slotInGrid) % 3].GridPosition;
										return false;
									}
									Slots.Slot[] array2 = (from slot3 in Slots.GetAmmoSlots()
										where slot3.IsActive
										select slot3).ToArray();
									if (array2.Length == 3)
									{
										__instance.m_selected = array2[Array.IndexOf(Slots.GetEquipmentSlots(), slotInGrid) % 3].GridPosition;
										return false;
									}
								}
								if (__instance.m_selected.x < 0)
								{
									__instance.m_selected = slotInGrid.GridPosition;
								}
							}
						}
						return false;
					}
					if (__instance.m_selected.x >= Slots.InventoryWidth - 1)
					{
						if (__instance.m_selected.y > 2)
						{
							IEnumerable<Slots.Slot> source3 = from slot3 in Slots.GetQuickSlots()
								where slot3.IsActive
								select slot3;
							if (source3.Any())
							{
								__instance.m_selected = source3.First().GridPosition;
								return false;
							}
							IEnumerable<Slots.Slot> source4 = from slot3 in Slots.GetMiscSlots()
								where slot3.IsActive
								select slot3;
							if (source4.Any())
							{
								__instance.m_selected = source4.First().GridPosition;
								return false;
							}
							__instance.m_selected = new Vector2i(0, Slots.InventoryHeightPlayer);
						}
						else
						{
							Vector2i val = FindEquipmentSlot(Math.Min(__instance.m_selected.y, equipmentSlotsCount - 1));
							if (val != Slots.emptyPosition)
							{
								__instance.m_selected = val;
							}
						}
						return false;
					}
				}
				if (ZInput.GetButtonDown("JoyDPadUp") || ZInput.GetButtonDown("JoyLStickUp"))
				{
					ExtraSlots.LogDebug($"From {__instance.m_selected} {slotInGrid} up");
					if (slotInGrid != null)
					{
						if (slotInGrid.IsFoodSlot)
						{
							__instance.m_selected.x--;
							if (__instance.m_selected.x < 3)
							{
								__instance.m_selected = slotInGrid.GridPosition;
							}
						}
						else if (slotInGrid.IsAmmoSlot)
						{
							__instance.m_selected.x--;
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = slotInGrid.GridPosition;
							}
						}
						else if (slotInGrid.IsMiscSlot)
						{
							if (slotInGrid.Index == 6)
							{
								Slots.Slot slot = Slots.GetFoodSlots().Last();
								__instance.m_selected = ((slot != null && slot.IsActive) ? slot : Slots.GetAmmoSlots().Last()).GridPosition;
							}
							else if (slotInGrid.Index == 7)
							{
								__instance.m_selected = Slots.GetAmmoSlots().Last().GridPosition;
							}
							Slots.Slot slotInGrid7 = Slots.GetSlotInGrid(__instance.m_selected);
							if (slotInGrid7 == null || !slotInGrid7.IsActive)
							{
								__instance.m_selected = slotInGrid.GridPosition;
							}
						}
						else if (slotInGrid.IsQuickSlot)
						{
							__instance.m_selected = FindEquipmentSlot(-1, null, Math.Min(__instance.m_selected.x, equipmentSlotsCount / 3), null, right: true);
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = FindEquipmentSlot(-1, null, -1, null, right: true);
							}
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = slotInGrid.GridPosition;
							}
						}
						else
						{
							__instance.m_selected = FindEquipmentSlot(-1, null, Array.IndexOf(Slots.GetEquipmentSlots(), slotInGrid) / 3, null, right: true, slotInGrid);
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = slotInGrid.GridPosition;
							}
						}
						return false;
					}
				}
				if (ZInput.GetButtonDown("JoyDPadDown") || ZInput.GetButtonDown("JoyLStickDown"))
				{
					ExtraSlots.LogDebug($"From {__instance.m_selected} {slotInGrid} down");
					if (slotInGrid != null)
					{
						if (slotInGrid.IsQuickSlot || slotInGrid.IsMiscSlot)
						{
							if (!__instance.jumpToNextContainer)
							{
								return false;
							}
							__instance.OnMoveToLowerInventoryGrid?.Invoke(__instance.m_selected);
							return false;
						}
						if (slotInGrid.IsAmmoSlot)
						{
							__instance.m_selected.x++;
							if (__instance.m_selected.x > 2)
							{
								Slots.Slot slot2 = Slots.GetMiscSlots()[1];
								__instance.m_selected = ((slot2 != null && slot2.IsActive) ? slot2 : Slots.GetMiscSlots()[0]).GridPosition;
							}
						}
						else if (slotInGrid.IsFoodSlot)
						{
							__instance.m_selected.x++;
							if (__instance.m_selected.x > 5)
							{
								__instance.m_selected = Slots.GetMiscSlots()[0].GridPosition;
							}
						}
						else if (slotInGrid.IsEquipmentSlot)
						{
							int num3 = Array.IndexOf(Slots.GetEquipmentSlots(), slotInGrid) / 3;
							__instance.m_selected = FindEquipmentSlot(-1, null, num3, null, right: false, null, slotInGrid);
							if (__instance.m_selected.x < 0)
							{
								__instance.m_selected = Slots.GetQuickSlots()[num3].GridPosition;
							}
						}
						Slots.Slot slotInGrid8 = Slots.GetSlotInGrid(__instance.m_selected);
						if (slotInGrid8 == null || !slotInGrid8.IsActive)
						{
							if (!__instance.jumpToNextContainer)
							{
								return false;
							}
							__instance.OnMoveToLowerInventoryGrid?.Invoke(__instance.m_selected);
						}
						return false;
					}
					if (__instance.m_selected.y >= Slots.InventoryHeightPlayer - 1)
					{
						__instance.OnMoveToLowerInventoryGrid?.Invoke(__instance.m_selected);
						return false;
					}
				}
				return true;
			}

			private static void Postfix(InventoryGrid __instance, bool __runOriginal)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				if (!__runOriginal)
				{
					ExtraSlots.LogDebug($"Selected {__instance.m_selected}");
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "SetGamepadSelection")]
		public static class InventoryGrid_SetSelection_GamepadSupport
		{
			private static void Prefix(InventoryGrid __instance, ref Vector2i pos)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)InventoryGui.instance) && !((Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid))
				{
					Slots.Slot slotInGrid = Slots.GetSlotInGrid(pos);
					if (slotInGrid == null || slotInGrid.IsEmptySlot || !slotInGrid.IsActive)
					{
						pos.x = Mathf.Clamp(pos.x, 0, Slots.InventoryWidth - 1);
						pos.y = Mathf.Clamp(pos.y, 0, Slots.InventoryHeightPlayer - 1);
					}
				}
			}
		}

		[HarmonyPatch(typeof(RectTransformUtility), "RectangleContainsScreenPoint", new Type[]
		{
			typeof(RectTransform),
			typeof(Vector2)
		})]
		public static class RectTransformUtility_RectangleContainsScreenPoint_BackpacksCompat
		{
			private static void Postfix(RectTransform rect, Vector2 screenPoint, ref bool __result)
			{
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)InventoryGui.instance) || (Object)(object)rect != (Object)(object)InventoryGui.instance.m_playerGrid.m_gridRoot)
				{
					return;
				}
				for (int i = 0; i < Math.Min(Slots.slots.Length, InventoryGui.instance.m_playerGrid.m_elements.Count - Slots.InventorySizePlayer); i++)
				{
					InventoryElement val = InventoryGui.instance.m_playerGrid.m_elements[Slots.InventorySizePlayer + i];
					if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeInHierarchy && RectTransformUtility.RectangleContainsScreenPoint(val.GetElementRectTransform(), screenPoint))
					{
						__result = true;
						break;
					}
				}
			}
		}

		private const string BackgroundName = "ExtraSlotsEquipmentPanel";

		private const float tileSpace = 6f;

		private const float tileSize = 70f;

		private const float interslotSpaceInTiles = 0.25f;

		private const float inventoryPanelOffset = 100f;

		private static int equipmentSlotsCount = 0;

		internal static int quickSlotsCount = 0;

		private static Vector2? draggedPanelOffset;

		private static readonly Vector3[] dragRectCorners = (Vector3[])(object)new Vector3[4];

		public static RectTransform inventoryDarken = null;

		public static RectTransform inventoryBackground = null;

		public static Image inventoryBackgroundImage = null;

		public static RectTransform equipmentBackground = null;

		public static Image equipmentBackgroundImage = null;

		public static RectTransform selectedFrame = null;

		public static RectTransform inventorySelectedFrame = null;

		private static bool isDirty = true;

		private static int updateSidePanelsInFrames;

		private static int updateSidePanelsPreviousExtraRows = -10;

		private static Color normalColor = Color.clear;

		private static Color highlightedColor = Color.clear;

		private static Color normalColorUnfit = Color.clear;

		private static Color highlightedColorUnfit = Color.clear;

		private static Material iconMaterial;

		private static Vector3 originalScale = Vector3.zero;

		private static Vector2 originalTooltipPosition = Vector2.zero;

		internal static Sprite ammoSlot;

		internal static Sprite miscSlot;

		internal static Sprite quickSlot;

		internal static Sprite lightenedSlot;

		internal static Sprite background;

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

		private static float InventoryPanelWidth
		{
			get
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				float result;
				if (!Object.op_Implicit((Object)(object)InventoryGui.instance))
				{
					result = 0f;
				}
				else
				{
					Rect rect = InventoryGui.instance.m_player.rect;
					result = ((Rect)(ref rect)).width;
				}
				return result;
			}
		}

		private static float PanelWidth => ((float)Math.Max(quickSlotsCount, SlotPositions.LastEquipmentColumn() + 1) + FoodAmmoSlotsWidthInTiles) * 70f + 3f;

		private static float PanelHeight => (((quickSlotsCount > 0 || Slots.IsFirstMiscSlotAvailable()) ? 1.25f : 0f) + (float)EquipmentHeight) * 70f + 3f;

		private static Vector2 CurrentPanelOffset => (Vector2)(((??)draggedPanelOffset) ?? ExtraSlots.equipmentPanelOffset.Value);

		private static Vector2 PanelOffset => new Vector2(CurrentPanelOffset.x, 0f - CurrentPanelOffset.y);

		private static Vector2 PanelPosition => GetPanelPosition(CurrentPanelOffset);

		private static float FoodAmmoSlotsWidthInTiles => ((Slots.IsFoodSlotAvailable() || Slots.IsAmmoSlotAvailable()) ? 0.25f : 0f) + (Slots.IsFoodSlotAvailable() ? 1f : 0f) + (Slots.IsAmmoSlotAvailable() ? 1f : 0f);

		private static int EquipmentHeight => (equipmentSlotsCount > 3 || Slots.IsFoodSlotAvailable() || Slots.IsAmmoSlotAvailable()) ? 3 : equipmentSlotsCount;

		private static bool CanDragPanel => UIDragging.CanDrag(ExtraSlots.panelsDraggable.Value, ExtraSlots.panelsDragKey.Value);

		private static RectTransform SelectedFrameArmor
		{
			get
			{
				Transform obj = ((Transform)InventoryGui.instance.m_player).Find("selected_frame/selected (2)");
				return (RectTransform)(object)((obj is RectTransform) ? obj : null);
			}
		}

		private static RectTransform SelectedFrameWeight
		{
			get
			{
				Transform obj = ((Transform)InventoryGui.instance.m_player).Find("selected_frame/selected (3)");
				return (RectTransform)(object)((obj is RectTransform) ? obj : null);
			}
		}

		private static Vector2 GetPanelPosition(Vector2 offset)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(InventoryPanelWidth + 100f + offset.x, 0f - offset.y);
		}

		private static Vector2 SnapPanelOffset(Vector2 offset)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			if (!ExtraSlots.equipmentPanelSticky.Value || ExtraSlots.equipmentPanelStickyDistance.Value <= 0f)
			{
				return offset;
			}
			float value = ExtraSlots.equipmentPanelStickyDistance.Value;
			bool flag = Mathf.Abs(offset.x) <= value;
			bool flag2 = Mathf.Abs(offset.y) <= value;
			if (flag)
			{
				offset.x = 0f;
			}
			if (flag2)
			{
				offset.y = 0f;
			}
			if (!Object.op_Implicit((Object)(object)InventoryGui.instance) || !Object.op_Implicit((Object)(object)InventoryGui.instance.m_player))
			{
				return offset;
			}
			Rect predictedPanelRect = GetPredictedPanelRect(offset);
			RectTransform[] array = (RectTransform[])(object)new RectTransform[5]
			{
				inventoryBackground,
				InventoryGui.instance.m_player,
				InventoryGui.instance.m_crafting,
				InventoryGui.instance.m_info,
				InventoryGui.instance.m_container
			};
			float bestDelta = 0f;
			float bestDistance = value + 1f;
			RectTransform[] array2 = array;
			foreach (RectTransform target in array2)
			{
				if (TryGetRectInPlayerSpace(target, out var rect) && RangesOverlap(((Rect)(ref predictedPanelRect)).yMin, ((Rect)(ref predictedPanelRect)).yMax, ((Rect)(ref rect)).yMin, ((Rect)(ref rect)).yMax))
				{
					ConsiderSnap(((Rect)(ref rect)).xMin - ((Rect)(ref predictedPanelRect)).xMax, ref bestDelta, ref bestDistance, value);
					ConsiderSnap(((Rect)(ref rect)).xMax - ((Rect)(ref predictedPanelRect)).xMin, ref bestDelta, ref bestDistance, value);
				}
			}
			if (!flag && bestDistance <= value)
			{
				offset.x += bestDelta;
				((Rect)(ref predictedPanelRect)).x = ((Rect)(ref predictedPanelRect)).x + bestDelta;
			}
			float bestDelta2 = 0f;
			float bestDistance2 = value + 1f;
			RectTransform[] array3 = array;
			foreach (RectTransform target2 in array3)
			{
				if (TryGetRectInPlayerSpace(target2, out var rect2) && Range