Decompiled source of ReservedItemSlotCore PlusNonScrapSlots v1.0.6

BepInEx/plugins/ReservedItemSlotCore.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using ReservedItemSlotCore.Compatibility;
using ReservedItemSlotCore.Config;
using ReservedItemSlotCore.Data;
using ReservedItemSlotCore.Input;
using ReservedItemSlotCore.Networking;
using ReservedItemSlotCore.Patches;
using TMPro;
using TooManyEmotes;
using TooManyEmotes.Patches;
using TooManyEmotes.UI;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ReservedItemSlotCore")]
[assembly: AssemblyDescription("Mod made by flipf17")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReservedItemSlotCore")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("238ce080-e339-46b6-9b08-992a950453a1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("ReservedFlashlightSlot")]
[assembly: InternalsVisibleTo("ReservedWalkieSlot")]
[assembly: InternalsVisibleTo("ReservedWeaponSlot")]
[assembly: InternalsVisibleTo("ReservedSprayPaintSlot")]
[assembly: InternalsVisibleTo("ReservedUtilitySlot")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
internal static class LethalConfigHelper
{
	private static bool _registered = false;

	private static readonly Dictionary<ConfigEntryBase, object> _lcTxtOptsByEntry = new Dictionary<ConfigEntryBase, object>();

	private static readonly Dictionary<ConfigEntryBase, object> _lcTxtItemByEntry = new Dictionary<ConfigEntryBase, object>();

	internal static void TryRegisterColorDisplay(ConfigEntry<string> colorEntry, string effectiveHex)
	{
		Type type = Type.GetType("LethalConfig.LethalConfigManager, LethalConfig");
		if (type == null)
		{
			return;
		}
		try
		{
			string text = "Current saved color:\n<b>" + effectiveHex + "</b>";
			MethodInfo methodInfo = null;
			Type type2 = Type.GetType("LethalConfig.ConfigItems.BaseConfigItem, LethalConfig");
			if (type2 != null)
			{
				methodInfo = type.GetMethod("AddConfigItem", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type2 }, null);
			}
			if (methodInfo == null)
			{
				methodInfo = Array.Find(type.GetMethods(BindingFlags.Static | BindingFlags.Public), (MethodInfo m) => m.Name == "AddConfigItem" && m.GetParameters().Length == 1);
			}
			bool flag = false;
			if (!_registered)
			{
				Type type3 = Type.GetType("LethalConfig.ConfigItems.Options.TextInputFieldOptions, LethalConfig");
				Type type4 = Type.GetType("LethalConfig.ConfigItems.TextInputFieldConfigItem, LethalConfig");
				if (type3 != null && type4 != null && methodInfo != null)
				{
					object obj = Activator.CreateInstance(type3);
					type3.GetProperty("Section")?.SetValue(obj, ((ConfigEntryBase)colorEntry).Definition.Section);
					type3.GetProperty("Name")?.SetValue(obj, ((ConfigEntryBase)colorEntry).Definition.Key);
					ConfigDescription description = ((ConfigEntryBase)colorEntry).Description;
					string text2 = ((description != null) ? description.Description : null) ?? "";
					type3.GetProperty("Description")?.SetValue(obj, string.IsNullOrWhiteSpace(text2) ? text : (text2 + "\n\n" + text));
					type3.GetProperty("RequiresRestart")?.SetValue(obj, false);
					object obj2 = Activator.CreateInstance(type4, colorEntry, obj);
					methodInfo.Invoke(null, new object[1] { obj2 });
					flag = true;
					_lcTxtOptsByEntry[(ConfigEntryBase)(object)colorEntry] = obj;
					_lcTxtItemByEntry[(ConfigEntryBase)(object)colorEntry] = obj2;
				}
			}
			else
			{
				if (_lcTxtOptsByEntry.TryGetValue((ConfigEntryBase)(object)colorEntry, out var value))
				{
					ConfigDescription description2 = ((ConfigEntryBase)colorEntry).Description;
					string text3 = ((description2 != null) ? description2.Description : null) ?? "";
					string value2 = (string.IsNullOrWhiteSpace(text3) ? text : (text3 + "\n\n" + text));
					value.GetType().GetProperty("Description")?.SetValue(value, value2);
					if (_lcTxtItemByEntry.TryGetValue((ConfigEntryBase)(object)colorEntry, out var value3))
					{
						value3.GetType().GetMethod("ApplyChanges", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(value3, null);
					}
				}
				else
				{
					Type type5 = Type.GetType("LethalConfig.ConfigItems.Options.TextInputFieldOptions, LethalConfig");
					Type type6 = Type.GetType("LethalConfig.ConfigItems.TextInputFieldConfigItem, LethalConfig");
					if (type5 != null && type6 != null && methodInfo != null)
					{
						object obj3 = Activator.CreateInstance(type5);
						type5.GetProperty("Section")?.SetValue(obj3, ((ConfigEntryBase)colorEntry).Definition.Section);
						type5.GetProperty("Name")?.SetValue(obj3, ((ConfigEntryBase)colorEntry).Definition.Key);
						ConfigDescription description3 = ((ConfigEntryBase)colorEntry).Description;
						string text4 = ((description3 != null) ? description3.Description : null) ?? "";
						string value4 = (string.IsNullOrWhiteSpace(text4) ? text : (text4 + "\n\n" + text));
						type5.GetProperty("Description")?.SetValue(obj3, value4);
						type5.GetProperty("RequiresRestart")?.SetValue(obj3, false);
						object obj4 = Activator.CreateInstance(type6, colorEntry, obj3);
						methodInfo.Invoke(null, new object[1] { obj4 });
						_lcTxtOptsByEntry[(ConfigEntryBase)(object)colorEntry] = obj3;
						_lcTxtItemByEntry[(ConfigEntryBase)(object)colorEntry] = obj4;
					}
					else
					{
						Debug.LogWarning((object)"LethalConfig: cannot update description (no cache and no re-add path).");
					}
				}
				flag = true;
			}
			if (flag)
			{
				_registered = true;
				type.GetMethod("SkipAutoGenFor", new Type[1] { typeof(ConfigEntryBase) })?.Invoke(null, new object[1] { colorEntry });
			}
			else
			{
				Debug.Log((object)"LethalConfigHelper: Could not display currently active color.");
			}
		}
		catch (Exception arg)
		{
			Debug.Log((object)$"LethalConfig UI extras failed: {arg}");
		}
	}
}
namespace ReservedItemSlotCore
{
	[HarmonyPatch]
	internal static class ItemNameMap
	{
		private static Dictionary<string, Item> originalNameToItemMap = new Dictionary<string, Item>();

		private static Dictionary<Item, string> itemToNameMap = new Dictionary<Item, string>();

		[HarmonyPatch(typeof(StartOfRound), "Start")]
		[HarmonyPrefix]
		private static void RecordOriginalItemNames(StartOfRound __instance)
		{
			List<Item> list = __instance?.allItemsList?.itemsList;
			if (list == null)
			{
				Plugin.LogError("Failed to record original item names. This might be fine if you're not using translation/localization mods. (no guarantees)");
				return;
			}
			foreach (Item item in list)
			{
				string text = item?.itemName;
				if (!string.IsNullOrEmpty(text))
				{
					if (!itemToNameMap.ContainsKey(item))
					{
						itemToNameMap.Add(item, text);
					}
					if (!originalNameToItemMap.ContainsKey(text))
					{
						originalNameToItemMap.Add(text, item);
					}
				}
			}
		}

		internal static string GetItemName(GrabbableObject grabbableObject)
		{
			if ((Object)(object)grabbableObject?.itemProperties == (Object)null)
			{
				return "";
			}
			string itemName = GetItemName(grabbableObject.itemProperties);
			if (itemName == null)
			{
				return "";
			}
			return itemName;
		}

		internal static string GetItemName(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return "";
			}
			if (itemToNameMap.TryGetValue(item, out var value) && value != null)
			{
				return value;
			}
			return "";
		}

		internal static bool IsZeroValueScrap(GrabbableObject grabbable)
		{
			if ((Object)(object)grabbable == (Object)null || (Object)(object)grabbable.itemProperties == (Object)null)
			{
				return false;
			}
			try
			{
				return !grabbable.itemProperties.isScrap || (grabbable.itemProperties.isScrap && grabbable.scrapValue == 0);
			}
			catch
			{
				return false;
			}
		}
	}
	[BepInPlugin("FlipMods.ReservedItemSlotCore", "ReservedItemSlotCore", "2.0.52")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		public static Plugin instance;

		private static ManualLogSource logger;

		public static List<ReservedItemSlotData> customItemSlots = new List<ReservedItemSlotData>();

		private void Awake()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			instance = this;
			CreateCustomLogger();
			ConfigSettings.BindConfigSettings();
			AddCustomItemSlots();
			_harmony = new Harmony("ReservedItemSlotCore");
			PatchAll();
			Log("ReservedItemSlotCore loaded");
		}

		private void AddCustomItemSlots()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			foreach (CustomItemSlotConfigEntry customItemSlotConfig in ConfigSettings.customItemSlotConfigs)
			{
				if (!(customItemSlotConfig.customItemSlotName == "") && customItemSlotConfig.customItemSlotItems.Length != 0)
				{
					ReservedItemSlotData reservedItemSlotData = ReservedItemSlotData.CreateReservedItemSlotData(customItemSlotConfig.customItemSlotName, customItemSlotConfig.customItemSlotPriority, customItemSlotConfig.customItemSlotPrice);
					string[] customItemSlotItems = customItemSlotConfig.customItemSlotItems;
					for (int i = 0; i < customItemSlotItems.Length; i++)
					{
						ReservedItemData itemData = new ReservedItemData(customItemSlotItems[i]);
						reservedItemSlotData.AddItemToReservedItemSlot(itemData);
					}
					customItemSlots.Add(reservedItemSlotData);
				}
			}
		}

		private void PatchAll()
		{
			IEnumerable<Type> enumerable;
			try
			{
				enumerable = Assembly.GetExecutingAssembly().GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				enumerable = ex.Types.Where((Type t) => t != null);
			}
			foreach (Type item in enumerable)
			{
				try
				{
					_harmony.PatchAll(item);
				}
				catch
				{
				}
			}
		}

		private void CreateCustomLogger()
		{
			try
			{
				logger = Logger.CreateLogSource(string.Format("{0}-{1}", "ReservedItemSlotCore", "2.0.52"));
			}
			catch
			{
				logger = ((BaseUnityPlugin)this).Logger;
			}
		}

		public static void Log(string message)
		{
			logger.LogInfo((object)message);
		}

		public static void LogError(string message)
		{
			logger.LogError((object)message);
		}

		public static void LogWarning(string message)
		{
			logger.LogWarning((object)message);
		}

		public static void LogVerbose(string message)
		{
			if (ConfigSettings.verboseLogs.Value)
			{
				logger.LogInfo((object)("[VERBOSE] " + message));
			}
		}

		public static void LogErrorVerbose(string message)
		{
			if (ConfigSettings.verboseLogs.Value)
			{
				logger.LogError((object)("[VERBOSE] " + message));
			}
		}

		public static void LogWarningVerbose(string message)
		{
			if (ConfigSettings.verboseLogs.Value)
			{
				logger.LogWarning((object)("[VERBOSE] " + message));
			}
		}

		public static bool IsModLoaded(string guid)
		{
			return Chainloader.PluginInfos.ContainsKey(guid);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "FlipMods.ReservedItemSlotCore";

		public const string PLUGIN_NAME = "ReservedItemSlotCore";

		public const string PLUGIN_VERSION = "2.0.52";
	}
	[HarmonyPatch]
	public static class ReservedHotbarManager
	{
		public static int indexInHotbar = 0;

		public static int indexInReservedHotbar = 0;

		internal static List<ReservedItemSlotData> currentlyToggledItemSlots = new List<ReservedItemSlotData>();

		public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;

		public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData;

		public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked;

		public static bool isToggledInReservedSlots
		{
			get
			{
				ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot();
				if (!ReservedPlayerData.localPlayerData.inReservedHotbarSlots || !Keybinds.pressedToggleKey)
				{
					if (currentlyToggledItemSlots != null && currentlySelectedReservedItemSlot != null)
					{
						return currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot);
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPrefix]
		public static void InitSession(StartOfRound __instance)
		{
			currentlyToggledItemSlots = new List<ReservedItemSlotData>();
			ReservedPlayerData.allPlayerData.Clear();
			indexInHotbar = 0;
			indexInReservedHotbar = -1;
		}

		public static void ForceToggleReservedHotbar(params ReservedItemSlotData[] reservedItemSlots)
		{
			if (((NetworkBehaviour)localPlayerController).IsOwner && localPlayerController.isPlayerControlled && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject) && HUDPatcher.hasReservedItemSlotsAndEnabled && reservedHotbarSize > 0 && CanSwapHotbars() && reservedItemSlots != null && reservedItemSlots.Length != 0 && !((Object)(object)localPlayerController == (Object)null))
			{
				currentlyToggledItemSlots = new List<ReservedItemSlotData>(reservedItemSlots);
				int num = currentlyToggledItemSlots.First().GetReservedItemSlotIndex() + localPlayerData.reservedHotbarStartIndex;
				bool active = ReservedPlayerData.localPlayerData.IsReservedItemSlot(num);
				if (currentlyToggledItemSlots.Contains(localPlayerData.GetCurrentlySelectedReservedItemSlot()))
				{
					FocusReservedHotbarSlots(active: false);
					return;
				}
				HUDPatcher.UpdateToggledReservedItemSlotsUI();
				FocusReservedHotbarSlots(active, num);
			}
		}

		public static void FocusReservedHotbarSlots(bool active, int forceSlot = -1)
		{
			if (!HUDPatcher.hasReservedItemSlotsAndEnabled || (reservedHotbarSize <= 0 && active) || (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved == active && (forceSlot == -1 || localPlayerData.currentItemSlot == forceSlot)))
			{
				return;
			}
			if (forceSlot != -1)
			{
				active = localPlayerData.IsReservedItemSlot(forceSlot);
			}
			ReservedPlayerData reservedPlayerData = ReservedPlayerData.localPlayerData;
			indexInHotbar = Mathf.Clamp(indexInHotbar, 0, localPlayerController.ItemSlots.Length - 1);
			indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0);
			indexInReservedHotbar = Mathf.Clamp(indexInReservedHotbar, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1);
			int num = Mathf.Clamp(localPlayerController.currentItemSlot, 0, localPlayerController.ItemSlots.Length);
			int i = num;
			bool flag = active;
			if (flag && (!reservedPlayerData.IsReservedItemSlot(num) || forceSlot != -1))
			{
				indexInHotbar = num;
				indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0);
				if (forceSlot != -1 && reservedPlayerData.IsReservedItemSlot(forceSlot))
				{
					indexInReservedHotbar = forceSlot;
				}
				i = indexInReservedHotbar;
				if (!AllowScrollCompat.Loaded && (Object)(object)localPlayerController.ItemSlots[i] == (Object)null && reservedPlayerData.GetNumHeldReservedItems() > 0)
				{
					for (i = reservedPlayerData.reservedHotbarStartIndex; i < reservedPlayerData.reservedHotbarEndIndexExcluded && !((Object)(object)localPlayerController.ItemSlots[i] != (Object)null); i++)
					{
					}
				}
				Plugin.LogVerbose("Focusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + ReservedPlayerData.localPlayerData.reservedHotbarStartIndex);
			}
			else if (!flag && (ReservedPlayerData.localPlayerData.IsReservedItemSlot(num) || forceSlot != -1))
			{
				indexInReservedHotbar = Mathf.Clamp(num, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1);
				if (forceSlot != -1 && !reservedPlayerData.IsReservedItemSlot(forceSlot))
				{
					indexInHotbar = forceSlot;
				}
				i = indexInHotbar;
				Plugin.LogVerbose("Unfocusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + ReservedPlayerData.localPlayerData.reservedHotbarStartIndex);
			}
			if (i < 0)
			{
				Plugin.LogError("Swapping to hotbar slot: " + i + ". Maybe send these logs to Flip? :)");
			}
			else if (i >= localPlayerController.ItemSlots.Length)
			{
				Plugin.LogError("Swapping to hotbar slot: " + i + " InventorySize: " + localPlayerController.ItemSlots.Length + ". Maybe send these logs to Flip? :)");
			}
			SyncManager.SwapHotbarSlot(i);
			if (localPlayerController.currentItemSlot != i)
			{
				Plugin.LogWarning("OnFocusReservedHotbarSlots - New hotbar index does not match target hotbar index. Tried to swap to index: " + i + " Current index: " + localPlayerController.currentItemSlot + " Tried swapping to reserved hotbar: " + active);
			}
		}

		public static bool CanSwapHotbars()
		{
			if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return false;
			}
			if (TooManyEmotes_Compat.Enabled && TooManyEmotes_Compat.IsLocalPlayerPerformingCustomEmote() && !TooManyEmotes_Compat.CanMoveWhileEmoting())
			{
				return false;
			}
			if (ReservedPlayerData.localPlayerData.grabbingReservedItemData == null && !localPlayerController.isGrabbingObjectAnimation && !localPlayerController.quickMenuManager.isMenuOpen && !localPlayerController.inSpecialInteractAnimation && !localPlayerData.throwingObject && !localPlayerController.isTypingChat && !localPlayerController.twoHanded && !localPlayerController.activatingItem && !localPlayerController.jetpackControls && !localPlayerController.disablingJetpackControls && !localPlayerController.inTerminalMenu && !localPlayerController.isPlayerDead)
			{
				return !(localPlayerData.timeSinceSwitchingSlots < 0.3f);
			}
			return false;
		}

		internal static void OnSwapToReservedHotbar()
		{
			if (!localPlayerData.currentItemSlotIsReserved)
			{
				return;
			}
			if (localPlayerData.currentItemSlotIsReserved)
			{
				indexInReservedHotbar = localPlayerController.currentItemSlot;
			}
			ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot();
			if (isToggledInReservedSlots && currentlyToggledItemSlots != null && !currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot))
			{
				currentlyToggledItemSlots = null;
			}
			if (HUDPatcher.reservedItemSlots == null)
			{
				return;
			}
			foreach (Image reservedItemSlot in HUDPatcher.reservedItemSlots)
			{
				CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>();
				if ((Object)(object)component != (Object)null)
				{
					component.ignoreParentGroups = !HUDPatcher.IsHudHidden;
				}
			}
		}

		internal static void OnSwapToVanillaHotbar()
		{
			if (localPlayerData.currentItemSlotIsReserved)
			{
				return;
			}
			if (!localPlayerData.currentItemSlotIsReserved)
			{
				indexInHotbar = localPlayerController.currentItemSlot;
			}
			currentlyToggledItemSlots = null;
			if (HUDPatcher.reservedItemSlots == null)
			{
				return;
			}
			foreach (Image reservedItemSlot in HUDPatcher.reservedItemSlots)
			{
				CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>();
				if ((Object)(object)component != (Object)null)
				{
					component.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPrefix]
		private static void RefocusReservedHotbarAfterAnimation(PlayerControllerB __instance)
		{
			if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !Keybinds.pressedToggleKey && Keybinds.holdingModifierKey != ReservedPlayerData.localPlayerData.currentItemSlotIsReserved && !isToggledInReservedSlots && CanSwapHotbars())
			{
				FocusReservedHotbarSlots(Keybinds.holdingModifierKey);
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "UpdateSpecialAnimationValue")]
		[HarmonyPostfix]
		private static void UpdateReservedHotbarAfterAnimation(bool specialAnimation, PlayerControllerB __instance)
		{
			if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !specialAnimation && !Keybinds.pressedToggleKey && ReservedPlayerData.localPlayerData.currentItemSlotIsReserved != Keybinds.holdingModifierKey)
			{
				FocusReservedHotbarSlots(Keybinds.holdingModifierKey);
			}
		}
	}
	[HarmonyPatch]
	public static class SessionManager
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass25_0
		{
			public bool force;
		}

		internal static List<ReservedItemSlotData> unlockedReservedItemSlots = new List<ReservedItemSlotData>();

		internal static Dictionary<string, ReservedItemSlotData> unlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>();

		internal static List<ReservedItemSlotData> pendingUnlockedReservedItemSlots = new List<ReservedItemSlotData>();

		internal static Dictionary<string, ReservedItemSlotData> pendingUnlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>();

		private static Dictionary<string, ReservedItemData> allReservedItemData = new Dictionary<string, ReservedItemData>();

		internal static bool gameStarted = false;

		internal static List<ReservedItemSlotData> allUnlockableReservedItemSlots => SyncManager.unlockableReservedItemSlots;

		internal static Dictionary<string, ReservedItemSlotData> allUnlockableReservedItemSlotsDict => SyncManager.unlockableReservedItemSlotsDict;

		public static int numReservedItemSlotsUnlocked
		{
			get
			{
				if (unlockedReservedItemSlots == null)
				{
					return 0;
				}
				return unlockedReservedItemSlots.Count;
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPrefix]
		private static void InitSession()
		{
			unlockedReservedItemSlots.Clear();
			unlockedReservedItemSlotsDict.Clear();
			pendingUnlockedReservedItemSlots.Clear();
			pendingUnlockedReservedItemSlotsDict.Clear();
			allReservedItemData.Clear();
			gameStarted = false;
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetPlayersLoadedValueClientRpc")]
		[HarmonyPostfix]
		private static void OnStartGame(StartOfRound __instance, bool landingShip = false)
		{
			if (gameStarted || !NetworkManager.Singleton.IsClient)
			{
				return;
			}
			if (!SyncManager.hostHasMod && SyncManager.canUseModDisabledOnHost)
			{
				Plugin.LogWarning("Starting game while host does not have this mod, and ForceEnableReservedItemSlots is enabled in the config. Unlocking: " + ReservedItemSlotData.allReservedItemSlotData.Count + " slots. THIS MAY NOT BE STABLE");
				SyncManager.isSynced = true;
				SyncManager.enablePurchasingItemSlots = false;
				ReservedPlayerData.localPlayerData.reservedHotbarStartIndex = ReservedPlayerData.localPlayerData.itemSlots.Length;
				foreach (ReservedItemSlotData value in ReservedItemSlotData.allReservedItemSlotData.Values)
				{
					SyncManager.AddReservedItemSlotData(value);
					UnlockReservedItemSlot(value);
				}
				pendingUnlockedReservedItemSlots?.Clear();
				pendingUnlockedReservedItemSlotsDict?.Clear();
				SyncManager.UpdateReservedItemsList();
			}
			gameStarted = true;
		}

		public static void UnlockReservedItemSlot(ReservedItemSlotData itemSlotData)
		{
			if (itemSlotData == null)
			{
				return;
			}
			Plugin.Log("Unlocking reserved item slot: " + itemSlotData.slotName);
			if (!SyncManager.isSynced)
			{
				if (!pendingUnlockedReservedItemSlotsDict.ContainsKey(itemSlotData.slotName))
				{
					pendingUnlockedReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData);
					pendingUnlockedReservedItemSlots.Add(itemSlotData);
				}
				return;
			}
			if (!unlockedReservedItemSlotsDict.ContainsKey(itemSlotData.slotName))
			{
				unlockedReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData);
				if (!unlockedReservedItemSlots.Contains(itemSlotData))
				{
					int num = -1;
					for (int i = 0; i < unlockedReservedItemSlots.Count; i++)
					{
						if (itemSlotData.slotPriority > unlockedReservedItemSlots[i].slotPriority)
						{
							num = i;
							break;
						}
					}
					if (num == -1)
					{
						num = unlockedReservedItemSlots.Count;
					}
					for (int j = 0; j < unlockedReservedItemSlots.Count; j++)
					{
						_ = unlockedReservedItemSlots[j];
					}
					unlockedReservedItemSlots.Insert(num, itemSlotData);
					foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values)
					{
						if (unlockedReservedItemSlots.Count == 1)
						{
							value.reservedHotbarStartIndex = value.itemSlots.Length;
						}
						int index = value.reservedHotbarStartIndex + num;
						List<GrabbableObject> list = new List<GrabbableObject>(value.itemSlots);
						list.Insert(index, null);
						value.playerController.ItemSlots = list.ToArray();
						value.hotbarSize = list.Count;
					}
				}
			}
			if (ReservedHotbarManager.indexInReservedHotbar < ReservedPlayerData.localPlayerData.reservedHotbarStartIndex || ReservedHotbarManager.indexInReservedHotbar >= ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded)
			{
				ReservedHotbarManager.indexInReservedHotbar = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex;
			}
			UpdateReservedItemsList();
			HUDPatcher.OnUpdateReservedItemSlots();
		}

		internal static void UnlockAllPendingItemSlots()
		{
			foreach (ReservedItemSlotData pendingUnlockedReservedItemSlot in pendingUnlockedReservedItemSlots)
			{
				UnlockReservedItemSlot(pendingUnlockedReservedItemSlot);
			}
			pendingUnlockedReservedItemSlots.Clear();
			pendingUnlockedReservedItemSlotsDict.Clear();
		}

		public static ReservedItemSlotData GetUnlockedReservedItemSlot(int indexInUnlockedItemSlots)
		{
			if (unlockedReservedItemSlots == null || indexInUnlockedItemSlots < 0 || indexInUnlockedItemSlots >= unlockedReservedItemSlots.Count)
			{
				return null;
			}
			return unlockedReservedItemSlots[indexInUnlockedItemSlots];
		}

		public static ReservedItemSlotData GetUnlockedReservedItemSlot(string itemSlotName)
		{
			if (TryGetUnlockedItemSlotData(itemSlotName, out var itemSlotData))
			{
				return itemSlotData;
			}
			return null;
		}

		public static bool IsItemSlotUnlocked(ReservedItemSlotData itemSlotData)
		{
			if (itemSlotData == null)
			{
				return false;
			}
			return IsItemSlotUnlocked(itemSlotData.slotName);
		}

		public static bool IsItemSlotUnlocked(string itemSlotName)
		{
			return unlockedReservedItemSlotsDict.ContainsKey(itemSlotName);
		}

		internal static void UpdateReservedItemsList()
		{
			if (unlockedReservedItemSlots == null)
			{
				return;
			}
			allReservedItemData.Clear();
			foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots)
			{
				if (unlockedReservedItemSlot.reservedItemData == null)
				{
					continue;
				}
				foreach (ReservedItemData value in unlockedReservedItemSlot.reservedItemData.Values)
				{
					if (!allReservedItemData.ContainsKey(value.itemName))
					{
						allReservedItemData.Add(value.itemName, value);
					}
				}
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
		[HarmonyPostfix]
		private static void OnResetShip()
		{
			if (SyncManager.enablePurchasingItemSlots)
			{
				ResetProgressDelayed();
			}
			else if (!SyncManager.hostHasMod && SyncManager.canUseModDisabledOnHost)
			{
				SyncManager.isSynced = false;
				ResetProgressDelayed(force: true);
			}
			gameStarted = false;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "SaveGameValues")]
		[HarmonyPostfix]
		private static void OnSaveGameValues()
		{
			if (NetworkManager.Singleton.IsHost && StartOfRound.Instance.inShipPhase && SyncManager.enablePurchasingItemSlots)
			{
				SaveGameValues();
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")]
		[HarmonyPostfix]
		private static void OnLoadGameValues()
		{
			if (NetworkManager.Singleton.IsServer && SyncManager.isSynced && SyncManager.enablePurchasingItemSlots)
			{
				LoadGameValues();
			}
		}

		internal static void ResetProgress(bool force = false)
		{
			if (!SyncManager.enablePurchasingItemSlots && !force)
			{
				return;
			}
			Plugin.Log("Resetting progress.");
			foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values)
			{
				GrabbableObject[] itemSlots = value.playerController.ItemSlots;
				List<GrabbableObject> list = new List<GrabbableObject>();
				for (int i = 0; i < itemSlots.Length; i++)
				{
					if (i < value.reservedHotbarStartIndex || i >= value.reservedHotbarEndIndexExcluded)
					{
						list.Add(itemSlots[i]);
					}
				}
				value.playerController.ItemSlots = list.ToArray();
			}
			unlockedReservedItemSlots?.Clear();
			unlockedReservedItemSlotsDict?.Clear();
			pendingUnlockedReservedItemSlots?.Clear();
			pendingUnlockedReservedItemSlotsDict?.Clear();
			List<Image> list2 = new List<Image>();
			List<Image> list3 = new List<Image>();
			for (int j = 0; j < HUDManager.Instance.itemSlotIconFrames.Length; j++)
			{
				Image val = HUDManager.Instance.itemSlotIconFrames[j];
				Image item = HUDManager.Instance.itemSlotIcons[j];
				if (!HUDPatcher.reservedItemSlots.Contains(val))
				{
					list2.Add(val);
					list3.Add(item);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			HUDPatcher.reservedItemSlots.Clear();
			HUDManager.Instance.itemSlotIconFrames = list2.ToArray();
			HUDManager.Instance.itemSlotIcons = list3.ToArray();
			foreach (ReservedPlayerData value2 in ReservedPlayerData.allPlayerData.Values)
			{
				if (value2.playerController.currentItemSlot < 0 || value2.playerController.currentItemSlot >= value2.playerController.ItemSlots.Length)
				{
					PlayerPatcher.SwitchToItemSlot(value2.playerController, 0);
				}
				value2.hotbarSize = value2.itemSlots.Length;
				value2.reservedHotbarStartIndex = value2.hotbarSize;
			}
			foreach (ReservedItemSlotData allUnlockableReservedItemSlot in allUnlockableReservedItemSlots)
			{
				if (allUnlockableReservedItemSlot.purchasePrice <= 0)
				{
					UnlockReservedItemSlot(allUnlockableReservedItemSlot);
				}
			}
			_ = SyncManager.hostHasMod;
			HUDPatcher.OnUpdateReservedItemSlots();
			if (NetworkManager.Singleton.IsServer)
			{
				ES3.DeleteKey("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName);
			}
		}

		internal static void ResetProgressDelayed(bool force = false)
		{
			<>c__DisplayClass25_0 CS$<>8__locals0 = new <>c__DisplayClass25_0();
			CS$<>8__locals0.force = force;
			((MonoBehaviour)StartOfRound.Instance).StartCoroutine(Reset());
			[IteratorStateMachine(typeof(<>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d))]
			IEnumerator Reset()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d(0)
				{
					<>4__this = CS$<>8__locals0
				};
			}
		}

		internal static void SaveGameValues()
		{
			if (!NetworkManager.Singleton.IsServer || unlockedReservedItemSlots == null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots)
			{
				if (!list.Contains(unlockedReservedItemSlot.slotName))
				{
					list.Add(unlockedReservedItemSlot.slotName);
				}
			}
			Plugin.LogWarning("Saving " + list.Count + " unlocked reserved item slots.");
			string[] array = list.ToArray();
			ES3.Save<string[]>("ReservedItemSlots.UnlockedItemSlots", array, GameNetworkManager.Instance.currentSaveFileName);
		}

		internal static void LoadGameValues()
		{
			if (!NetworkManager.Singleton.IsServer || SyncManager.unlockableReservedItemSlotsDict == null)
			{
				return;
			}
			string[] array = ES3.Load<string[]>("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName, new string[0]);
			Plugin.LogWarning("Loading " + array.Length + " unlocked reserved item slots.");
			int num = 0;
			string[] array2 = array;
			foreach (string key in array2)
			{
				if (SyncManager.unlockableReservedItemSlotsDict.TryGetValue(key, out var value))
				{
					num++;
					UnlockReservedItemSlot(value);
					SyncManager.SendUnlockItemSlotToClients(value.slotId);
				}
			}
			Plugin.Log("Loaded " + num + " unlocked reserved items.");
		}

		public static bool IsReservedItem(GrabbableObject grabbableObject)
		{
			if (!IsReservedItem(ItemNameMap.GetItemName(grabbableObject)))
			{
				if ((Object)(object)grabbableObject?.itemProperties != (Object)null)
				{
					return IsReservedItem(grabbableObject.itemProperties.itemName);
				}
				return false;
			}
			return true;
		}

		public static bool IsReservedItem(string itemName)
		{
			return allReservedItemData.ContainsKey(itemName);
		}

		public static bool TryGetUnlockedItemSlotData(string itemSlotName, out ReservedItemSlotData itemSlotData)
		{
			itemSlotData = null;
			unlockedReservedItemSlotsDict.TryGetValue(itemSlotName, out itemSlotData);
			return itemSlotData != null;
		}

		public static bool TryGetUnlockedItemData(GrabbableObject item, out ReservedItemData itemData)
		{
			itemData = null;
			if (!TryGetUnlockedItemData(ItemNameMap.GetItemName(item), out itemData))
			{
				if ((Object)(object)item?.itemProperties != (Object)null)
				{
					return TryGetUnlockedItemData(item.itemProperties.itemName, out itemData);
				}
				return false;
			}
			return true;
		}

		public static bool TryGetUnlockedItemData(string itemName, out ReservedItemData itemData)
		{
			itemData = null;
			return allReservedItemData.TryGetValue(itemName, out itemData);
		}
	}
}
namespace ReservedItemSlotCore.Patches
{
	[HarmonyPatch]
	internal static class DropReservedItemPatcher
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass10_0
		{
			public PlayerControllerB playerController;

			public float time;

			internal bool <SwitchToItemSlotAfterDelay>b__0()
			{
				if (!((Object)(object)playerController.currentlyHeldObjectServer == (Object)null))
				{
					return Time.time - time >= 5f;
				}
				return true;
			}
		}

		[CompilerGenerated]
		private sealed class <SwitchToItemSlotAfterDelay>d__10 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public PlayerControllerB playerController;

			private <>c__DisplayClass10_0 <>8__1;

			public int slot;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SwitchToItemSlotAfterDelay>d__10(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Expected O, but got Unknown
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass10_0();
					<>8__1.playerController = playerController;
					<>8__1.time = Time.time;
					if ((Object)(object)<>8__1.playerController == (Object)(object)localPlayerController)
					{
						<>2__current = (object)new WaitUntil((Func<bool>)(() => (Object)(object)<>8__1.playerController.currentlyHeldObjectServer == (Object)null || Time.time - <>8__1.time >= 5f));
						<>1__state = 1;
						return true;
					}
					goto IL_0091;
				case 1:
					<>1__state = -1;
					goto IL_0091;
				case 2:
					{
						<>1__state = -1;
						playersDiscardingItems.Remove(<>8__1.playerController);
						if (<>8__1.playerController.currentItemSlot != slot && Time.time - <>8__1.time < 3f && ReservedPlayerData.allPlayerData.TryGetValue(<>8__1.playerController, out var value))
						{
							value.CallSwitchToItemSlot(slot);
						}
						return false;
					}
					IL_0091:
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static HashSet<PlayerControllerB> playersDiscardingItems = new HashSet<PlayerControllerB>();

		private static float timeLoggedPreventedScroll = 0f;

		private static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;

		private static bool IsNoScrapSlotName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			string text = name.Trim().ToLowerInvariant();
			if (!(text == "no_scrap_1"))
			{
				return text == "no_scrap_2";
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SetObjectAsNoLongerHeld")]
		[HarmonyPatch(typeof(PlayerControllerB), "PlaceGrabbableObject")]
		[HarmonyPostfix]
		public static void OnObjectNoLongerHeld(PlayerControllerB __instance)
		{
			OnDiscardItem(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DestroyItemInSlot")]
		[HarmonyPostfix]
		public static void OnDestroyItem(int itemSlot, PlayerControllerB __instance)
		{
			if (ReservedPlayerData.localPlayerData != null && SessionManager.unlockedReservedItemSlots != null && itemSlot >= ReservedPlayerData.localPlayerData.reservedHotbarStartIndex && itemSlot < ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded)
			{
				if (itemSlot == __instance.currentItemSlot)
				{
					OnDiscardItem(__instance);
				}
				if ((Object)(object)__instance == (Object)(object)localPlayerController)
				{
					HUDPatcher.UpdateUI();
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DespawnHeldObjectOnClient")]
		[HarmonyPostfix]
		public static void OnDespawnItem(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)(object)localPlayerController)
			{
				HUDPatcher.UpdateUI();
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DropAllHeldItems")]
		[HarmonyPostfix]
		public static void OnDropAllHeldItems(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)(object)localPlayerController)
			{
				HUDPatcher.UpdateUI();
			}
		}

		private static void OnDiscardItem(PlayerControllerB playerController)
		{
			if ((Object)(object)playerController == (Object)null || playersDiscardingItems.Contains(playerController) || !ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value) || !value.currentItemSlotIsReserved || (Object)(object)value.currentlySelectedItem != (Object)null)
			{
				return;
			}
			ReservedItemSlotData currentlySelectedReservedItemSlot = value.GetCurrentlySelectedReservedItemSlot();
			if (currentlySelectedReservedItemSlot != null && IsNoScrapSlotName(currentlySelectedReservedItemSlot.slotName))
			{
				if ((Object)(object)playerController == (Object)(object)localPlayerController)
				{
					HUDPatcher.UpdateUI();
				}
				return;
			}
			if (value.GetNumHeldReservedItems() > 0)
			{
				int num = value.CallGetNextItemSlot(forward: true);
				if (!value.IsReservedItemSlot(num) && !value.IsReservedItemSlot(ReservedHotbarManager.indexInHotbar))
				{
					num = ReservedHotbarManager.indexInHotbar;
				}
				playersDiscardingItems.Add(playerController);
				((MonoBehaviour)playerController).StartCoroutine(SwitchToItemSlotAfterDelay(playerController, num));
			}
			if ((Object)(object)playerController == (Object)(object)localPlayerController)
			{
				HUDPatcher.UpdateUI();
			}
		}

		[IteratorStateMachine(typeof(<SwitchToItemSlotAfterDelay>d__10))]
		private static IEnumerator SwitchToItemSlotAfterDelay(PlayerControllerB playerController, int slot)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SwitchToItemSlotAfterDelay>d__10(0)
			{
				playerController = playerController,
				slot = slot
			};
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")]
		[HarmonyPrefix]
		public static bool PreventItemSwappingDroppingItem(CallbackContext context, PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)(object)localPlayerController && playersDiscardingItems.Contains(__instance))
			{
				float time = Time.time;
				if (ConfigSettings.verboseLogs.Value && time - timeLoggedPreventedScroll > 1f)
				{
					timeLoggedPreventedScroll = time;
					Plugin.LogWarning("[VERBOSE] Prevented item swap. Player is currently discarding an item? This should be fine, unless these logs are spamming.");
				}
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class HUDPatcher
	{
		private static bool usingController = false;

		private static float itemSlotWidth;

		internal static float itemSlotSpacing;

		private static float defaultItemSlotPosX;

		private static float defaultItemSlotPosY;

		private static float defaultItemSlotSpacing;

		private static Vector2 defaultItemSlotSize;

		private static Vector2 defaultItemIconSize;

		private static TextMeshProUGUI hotkeyTooltip;

		public static List<Image> reservedItemSlots = new List<Image>();

		public static HashSet<ReservedItemSlotData> toggledReservedItemSlots = new HashSet<ReservedItemSlotData>();

		private static bool lerpToggledItemSlotFrames = false;

		private static float largestPositionDifference = 0f;

		private static bool currentApplyHotbarPlusSize;

		private static bool currentHideEmptySlots;

		private static readonly bool allowScroll = true;

		private static Image noScrap1Frame;

		private static Image noScrap2Frame;

		private static readonly HashSet<string> NoScrapSlotNames = new HashSet<string> { "no_scrap_1", "no_scrap_2" };

		private static Color DefaultOutlineColor = new Color(0f, 0f, 0f, 0f);

		private static Color DefaultFrameColor = Color.white;

		private static bool DefaultColorsCaptured = false;

		private static bool baselineInit = false;

		private static float baselineCenterX = 0f;

		private static float baselineSpacingS = 0f;

		private static float baselineY = 0f;

		private static Vector2 baselineSize;

		private static readonly Color DefaultTint = new Color(0.9098039f, 0.7019608f, 1f, 1f);

		private static bool hasAlphaInConfig = false;

		private const string LocalColorPrefKey = "ReservedItemSlotCore.NonScrapSlotColor";

		public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;

		public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData;

		public static bool localPlayerUsingController
		{
			get
			{
				if (!((Object)(object)StartOfRound.Instance != (Object)null))
				{
					return false;
				}
				return StartOfRound.Instance.localPlayerUsingController;
			}
		}

		private static float currentItemSlotScale => itemSlotWidth / defaultItemSlotSize.x;

		public static bool hasReservedItemSlotsAndEnabled
		{
			get
			{
				if (reservedItemSlots != null && reservedItemSlots.Count > 0 && ((Component)reservedItemSlots[0]).gameObject.activeSelf)
				{
					return ((Behaviour)reservedItemSlots[0]).enabled;
				}
				return false;
			}
		}

		internal static Color Tint { get; private set; } = DefaultTint;


		internal static bool IsHudHidden { get; private set; } = false;


		internal static string EffectiveNonScrapHexUI { get; private set; } = "#E8B3FF";


		internal static string EffectiveNonScrapHexSourceUI { get; private set; } = "default";


		[HarmonyPatch(typeof(HUDManager), "HideHUD")]
		[HarmonyPostfix]
		private static void ReservedSlotsRespectHideHUD(bool hide)
		{
			IsHudHidden = hide;
			if (!hasReservedItemSlotsAndEnabled || reservedItemSlots == null)
			{
				return;
			}
			bool flag = ReservedPlayerData.localPlayerData?.currentItemSlotIsReserved ?? false;
			foreach (Image reservedItemSlot in reservedItemSlots)
			{
				if ((Object)(object)reservedItemSlot == (Object)null)
				{
					continue;
				}
				CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>();
				if (!((Object)(object)component == (Object)null))
				{
					if (hide)
					{
						component.ignoreParentGroups = false;
					}
					else
					{
						component.ignoreParentGroups = flag || ConfigSettings.preventReservedItemSlotFade.Value;
					}
				}
			}
		}

		private static string NormalizeHex(string s)
		{
			if (string.IsNullOrWhiteSpace(s))
			{
				return null;
			}
			s = s.Trim();
			if (!s.StartsWith("#"))
			{
				s = "#" + s;
			}
			return s.ToUpperInvariant();
		}

		internal static void RefreshTintColor()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			string text = NormalizeHex(ConfigSettings.nonScrapSlotColorHex?.Value);
			ConfigEntry<string> nonScrapSlotColorHex = ConfigSettings.nonScrapSlotColorHex;
			string text2 = NormalizeHex(((nonScrapSlotColorHex == null) ? null : ((ConfigEntryBase)nonScrapSlotColorHex).DefaultValue?.ToString()) ?? "#E8B3FF");
			bool flag = PlayerPrefs.HasKey("ReservedItemSlotCore.NonScrapSlotColor");
			string text3 = NormalizeHex(flag ? PlayerPrefs.GetString("ReservedItemSlotCore.NonScrapSlotColor") : null);
			if (!string.IsNullOrEmpty(text) && !string.Equals(text, text2, StringComparison.OrdinalIgnoreCase))
			{
				PlayerPrefs.SetString("ReservedItemSlotCore.NonScrapSlotColor", text);
				PlayerPrefs.Save();
				text3 = text;
				flag = true;
			}
			string text4 = text;
			if (string.Equals(text, text2, StringComparison.OrdinalIgnoreCase))
			{
				text4 = ((flag && !string.IsNullOrEmpty(text3)) ? text3 : text2);
			}
			EffectiveNonScrapHexUI = NormalizeHex((!string.IsNullOrEmpty(text4)) ? text4 : text2);
			Color tint = DefaultTint;
			hasAlphaInConfig = false;
			if (!string.IsNullOrEmpty(text4))
			{
				string text5 = ((text4[0] == '#') ? text4.Substring(1) : text4);
				hasAlphaInConfig = text5.Length == 4 || text5.Length == 8;
				Color val = default(Color);
				if (ColorUtility.TryParseHtmlString(text4, ref val))
				{
					tint = val;
				}
				else
				{
					hasAlphaInConfig = false;
				}
			}
			Tint = tint;
			UpdateUI();
		}

		private static bool ShouldTint(ReservedItemSlotData slotData)
		{
			if (slotData == null)
			{
				return false;
			}
			return NoScrapSlotNames.Contains(slotData.slotName);
		}

		private static void ApplyTintToFrame(Image itemSlotFrame)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)itemSlotFrame == (Object)null))
			{
				Outline obj = ((Component)itemSlotFrame).GetComponent<Outline>() ?? ((Component)itemSlotFrame).gameObject.AddComponent<Outline>();
				float num = OnePixel(itemSlotFrame);
				((Shadow)obj).effectDistance = new Vector2(num, 0f - num);
				((Shadow)obj).effectColor = new Color(Tint.r, Tint.g, Tint.b, hasAlphaInConfig ? Tint.a : 0.1f);
				((Shadow)obj).useGraphicAlpha = !hasAlphaInConfig;
				((Graphic)itemSlotFrame).color = new Color(Tint.r, Tint.g, Tint.b, hasAlphaInConfig ? Tint.a : ((Graphic)itemSlotFrame).color.a);
			}
		}

		private static void CaptureDefaultColors(HUDManager hud)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (DefaultColorsCaptured || (Object)(object)hud == (Object)null || hud.itemSlotIconFrames == null || hud.itemSlotIconFrames.Length == 0)
			{
				return;
			}
			Image val = hud.itemSlotIconFrames[0];
			if ((Object)(object)val != (Object)null)
			{
				Outline component = ((Component)val).GetComponent<Outline>();
				if ((Object)(object)component != (Object)null)
				{
					DefaultOutlineColor = ((Shadow)component).effectColor;
				}
				DefaultFrameColor = ((Graphic)val).color;
				DefaultColorsCaptured = true;
			}
		}

		private static void ResetTint(Image frame)
		{
			//IL_0045: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)frame == (Object)null))
			{
				Outline component = ((Component)frame).GetComponent<Outline>();
				if ((Object)(object)component != (Object)null)
				{
					((Shadow)component).effectColor = DefaultOutlineColor;
				}
				((Graphic)frame).color = new Color(DefaultFrameColor.r, DefaultFrameColor.g, DefaultFrameColor.b, ((Graphic)frame).color.a);
			}
		}

		private static float OnePixel(Image img)
		{
			Canvas val = (((Object)(object)img != (Object)null) ? ((Graphic)img).canvas : null);
			float num = (((Object)(object)val != (Object)null) ? val.scaleFactor : 1f);
			return 1f / Mathf.Max(num, 0.01f);
		}

		private static void RecenterMainHotbarWithTwoLeftReserved()
		{
			//IL_00f5: 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_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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_017f: Unknown result type (might be due to invalid IL or missing references)
			HUDManager instance = HUDManager.Instance;
			if (!baselineInit || (Object)(object)instance == (Object)null || (Object)(object)noScrap1Frame == (Object)null || (Object)(object)noScrap2Frame == (Object)null)
			{
				return;
			}
			List<Image> list = new List<Image>();
			Image[] itemSlotIconFrames = instance.itemSlotIconFrames;
			foreach (Image val in itemSlotIconFrames)
			{
				if (!((Object)(object)val == (Object)null) && !reservedItemSlots.Contains(val))
				{
					list.Add(val);
				}
			}
			if (list.Count >= 4)
			{
				list.Sort((Image a, Image b) => ((Graphic)a).rectTransform.anchoredPosition.x.CompareTo(((Graphic)b).rectTransform.anchoredPosition.x));
				float num = baselineCenterX;
				float num2 = baselineSpacingS;
				float num3 = baselineY;
				float[] array = new float[6];
				for (int j = 0; j < 6; j++)
				{
					array[j] = num + ((float)j - 2.5f) * num2;
				}
				((Graphic)noScrap1Frame).rectTransform.anchoredPosition = new Vector2(array[0], num3);
				((Graphic)noScrap2Frame).rectTransform.anchoredPosition = new Vector2(array[1], num3);
				((Graphic)list[0]).rectTransform.anchoredPosition = new Vector2(array[2], num3);
				((Graphic)list[1]).rectTransform.anchoredPosition = new Vector2(array[3], num3);
				((Graphic)list[2]).rectTransform.anchoredPosition = new Vector2(array[4], num3);
				((Graphic)list[3]).rectTransform.anchoredPosition = new Vector2(array[5], num3);
			}
		}

		private static void EnsureVanillaBaseline()
		{
			//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_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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Vector2 sizeDelta = ((Graphic)instance.itemSlotIconFrames[0]).rectTransform.sizeDelta;
			if (baselineInit && sizeDelta == baselineSize)
			{
				return;
			}
			List<Image> list = new List<Image>();
			Image[] itemSlotIconFrames = instance.itemSlotIconFrames;
			foreach (Image val in itemSlotIconFrames)
			{
				if (!((Object)(object)val == (Object)null) && !reservedItemSlots.Contains(val))
				{
					list.Add(val);
				}
			}
			if (list.Count >= 4)
			{
				list.Sort((Image a, Image b) => ((Graphic)a).rectTransform.anchoredPosition.x.CompareTo(((Graphic)b).rectTransform.anchoredPosition.x));
				baselineY = ((Graphic)list[0]).rectTransform.anchoredPosition.y;
				float num = Mathf.Abs(((Graphic)list[1]).rectTransform.anchoredPosition.x - ((Graphic)list[0]).rectTransform.anchoredPosition.x);
				float num2 = Mathf.Abs(((Graphic)list[2]).rectTransform.anchoredPosition.x - ((Graphic)list[1]).rectTransform.anchoredPosition.x);
				float num3 = Mathf.Abs(((Graphic)list[3]).rectTransform.anchoredPosition.x - ((Graphic)list[2]).rectTransform.anchoredPosition.x);
				baselineSpacingS = (num + num2 + num3) / 3f;
				baselineCenterX = 0f;
				for (int j = 0; j < 4; j++)
				{
					baselineCenterX += ((Graphic)list[j]).rectTransform.anchoredPosition.x;
				}
				baselineCenterX /= 4f;
				baselineSize = sizeDelta;
				baselineInit = true;
			}
		}

		[HarmonyPatch(typeof(HUDManager), "Awake")]
		[HarmonyPostfix]
		public static void Initialize(HUDManager __instance)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			CanvasScaler componentInParent = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<CanvasScaler>();
			AspectRatioFitter componentInParent2 = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<AspectRatioFitter>();
			itemSlotWidth = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta.x;
			itemSlotSpacing = 1.125f * itemSlotWidth;
			defaultItemSlotPosX = componentInParent.referenceResolution.x / 2f / componentInParent2.aspectRatio - itemSlotWidth / 4f;
			defaultItemSlotSpacing = itemSlotSpacing;
			defaultItemSlotSize = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta;
			defaultItemIconSize = ((Graphic)__instance.itemSlotIcons[0]).rectTransform.sizeDelta;
			defaultItemSlotPosY = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.anchoredPosition.y;
			reservedItemSlots.Clear();
			CaptureDefaultColors(__instance);
			RefreshTintColor();
		}

		[HarmonyPatch(typeof(StartOfRound), "Update")]
		[HarmonyPrefix]
		public static void UpdateUsingController(StartOfRound __instance)
		{
			if (!((Object)(object)__instance.localPlayerController == (Object)null) && !((Object)(object)hotkeyTooltip == (Object)null) && ((Component)hotkeyTooltip).gameObject.activeSelf && ((Behaviour)hotkeyTooltip).enabled)
			{
				if (__instance.localPlayerUsingController != usingController)
				{
					usingController = __instance.localPlayerUsingController;
					UpdateHotkeyTooltipText();
				}
				LerpItemSlotFrames();
			}
		}

		private static void LerpItemSlotFrames()
		{
			//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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if (!lerpToggledItemSlotFrames)
			{
				return;
			}
			if (largestPositionDifference < 2f && largestPositionDifference != -1f)
			{
				lerpToggledItemSlotFrames = false;
			}
			for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++)
			{
				ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i);
				if (!ShouldTint(unlockedReservedItemSlot))
				{
					Image val = HUDManager.Instance.itemSlotIconFrames[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i];
					bool flag = unlockedReservedItemSlot.slotPriority >= 0 || !ConfigSettings.displayNegativePrioritySlotsLeftSideOfScreen.Value;
					Vector2 anchoredPosition = ((Graphic)val).rectTransform.anchoredPosition;
					anchoredPosition.x = (defaultItemSlotPosX + (defaultItemSlotSize.x - itemSlotWidth) / 2f) * (float)(flag ? 1 : (-1));
					if (ReservedHotbarManager.isToggledInReservedSlots && ReservedHotbarManager.currentlyToggledItemSlots != null && ReservedHotbarManager.currentlyToggledItemSlots.Contains(unlockedReservedItemSlot))
					{
						anchoredPosition.x += itemSlotWidth / 2f * (float)((!flag) ? 1 : (-1));
					}
					float num = Mathf.Abs(anchoredPosition.x - ((Graphic)val).rectTransform.anchoredPosition.x);
					largestPositionDifference = Mathf.Max(largestPositionDifference, num);
					if (lerpToggledItemSlotFrames)
					{
						((Graphic)val).rectTransform.anchoredPosition = Vector2.Lerp(((Graphic)val).rectTransform.anchoredPosition, anchoredPosition, Time.deltaTime * 10f);
					}
					else
					{
						((Graphic)val).rectTransform.anchoredPosition = anchoredPosition;
					}
				}
			}
		}

		public static void OnUpdateReservedItemSlots()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			if (reservedItemSlots == null || SessionManager.numReservedItemSlotsUnlocked <= 0 || reservedItemSlots.Count == SessionManager.numReservedItemSlotsUnlocked)
			{
				return;
			}
			List<Image> list = new List<Image>(HUDManager.Instance.itemSlotIconFrames);
			List<Image> list2 = new List<Image>(HUDManager.Instance.itemSlotIcons);
			for (int i = reservedItemSlots.Count; i < SessionManager.numReservedItemSlotsUnlocked; i++)
			{
				Image component = Object.Instantiate<GameObject>(((Component)list[0]).gameObject, ((Component)list[0]).transform.parent).GetComponent<Image>();
				Image component2 = ((Component)((Component)component).transform.GetChild(0)).GetComponent<Image>();
				((Component)component).transform.localScale = ((Component)list[0]).transform.localScale;
				((Transform)((Graphic)component).rectTransform).eulerAngles = ((Transform)((Graphic)list[0]).rectTransform).eulerAngles;
				((Transform)((Graphic)component2).rectTransform).eulerAngles = ((Transform)((Graphic)list2[0]).rectTransform).eulerAngles;
				CanvasGroup obj = ((Component)component).gameObject.AddComponent<CanvasGroup>();
				obj.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value;
				obj.alpha = 1f;
				component.fillMethod = list[0].fillMethod;
				component.sprite = list[0].sprite;
				((Graphic)component).material = ((Graphic)list[0]).material;
				if (Plugin.IsModLoaded("xuxiaolan.hotbarrd"))
				{
					component.overrideSprite = list[0].overrideSprite;
				}
				ResetTint(component);
				int index = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + reservedItemSlots.Count;
				list.Insert(index, component);
				list2.Insert(index, component2);
				reservedItemSlots.Add(component);
				if (ShouldTint(SessionManager.GetUnlockedReservedItemSlot(i)))
				{
					ApplyTintToFrame(component);
				}
			}
			HUDManager.Instance.itemSlotIconFrames = list.ToArray();
			HUDManager.Instance.itemSlotIcons = list2.ToArray();
			UpdateUI();
		}

		public static void UpdateUI()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0515: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_046d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_048a: 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_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			if (reservedItemSlots.Count != SessionManager.numReservedItemSlotsUnlocked)
			{
				Plugin.LogError("Called UpdateUI with mismatched unlocked reserved item slots and reserved item slot hud elements.");
				return;
			}
			noScrap1Frame = null;
			noScrap2Frame = null;
			int num = 0;
			int num2 = 0;
			RectTransform val = null;
			EnsureVanillaBaseline();
			Vector2 anchoredPosition = default(Vector2);
			for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++)
			{
				ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i);
				Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, reservedItemSlots[i]);
				Image val2 = reservedItemSlots[i];
				Image component = ((Component)((Component)reservedItemSlots[i]).transform.GetChild(0)).GetComponent<Image>();
				((Graphic)val2).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIconFrames[0]).rectTransform.sizeDelta;
				((Graphic)component).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIcons[0]).rectTransform.sizeDelta;
				if (HotbarPlus_Compat.Enabled && !ConfigSettings.applyHotbarPlusItemSlotSize.Value)
				{
					((Graphic)val2).rectTransform.sizeDelta = defaultItemSlotSize;
					((Graphic)component).rectTransform.sizeDelta = defaultItemIconSize;
				}
				itemSlotWidth = ((Graphic)val2).rectTransform.sizeDelta.x;
				itemSlotSpacing = defaultItemSlotSpacing * currentItemSlotScale;
				if (ShouldTint(unlockedReservedItemSlot))
				{
					float num3 = OnePixel(val2);
					RectTransform rectTransform = ((Graphic)val2).rectTransform;
					rectTransform.sizeDelta -= new Vector2(2f * num3, 2f * num3);
					itemSlotWidth = rectTransform.sizeDelta.x;
				}
				GrabbableObject reservedItem = ReservedPlayerData.localPlayerData.GetReservedItem(unlockedReservedItemSlot);
				((Object)val2).name = "Slot" + i + " [ReservedItemSlot] (" + unlockedReservedItemSlot.slotName + ")";
				((Vector2)(ref anchoredPosition))..ctor(defaultItemSlotPosX, defaultItemSlotPosY);
				if (unlockedReservedItemSlot.slotPriority >= 0 || !ConfigSettings.displayNegativePrioritySlotsLeftSideOfScreen.Value)
				{
					anchoredPosition.x = defaultItemSlotPosX + (defaultItemSlotSize.x - itemSlotWidth) / 2f;
					anchoredPosition.y = defaultItemSlotPosY + 36f * ((itemSlotWidth / defaultItemSlotSize.x - 1f) / 2f) + itemSlotSpacing * (float)num;
					if (!ConfigSettings.hideEmptyReservedItemSlots.Value || (Object)(object)reservedItem != (Object)null || allowScroll)
					{
						if (!Object.op_Implicit((Object)(object)val))
						{
							val = ((Graphic)val2).rectTransform;
						}
						num++;
					}
					else
					{
						anchoredPosition.y = -1000f;
					}
				}
				else
				{
					anchoredPosition.x = 0f - defaultItemSlotPosX - (defaultItemSlotSize.x - itemSlotWidth) / 2f;
					anchoredPosition.y = defaultItemSlotPosY + 36f * ((itemSlotWidth / defaultItemSlotSize.x - 1f) / 2f) + itemSlotSpacing * (float)num2;
					if (!ConfigSettings.hideEmptyReservedItemSlots.Value || (Object)(object)reservedItem != (Object)null || allowScroll)
					{
						num2++;
					}
					else
					{
						anchoredPosition.y = -1000f;
					}
				}
				if (!ShouldTint(unlockedReservedItemSlot))
				{
					((Graphic)val2).rectTransform.anchoredPosition = anchoredPosition;
				}
				else if (unlockedReservedItemSlot.slotName == "no_scrap_1")
				{
					noScrap1Frame = val2;
				}
				else if (unlockedReservedItemSlot.slotName == "no_scrap_2")
				{
					noScrap2Frame = val2;
				}
				ResetTint(val2);
				if (ShouldTint(unlockedReservedItemSlot))
				{
					ApplyTintToFrame(val2);
				}
				if ((Object)(object)reservedItem != (Object)null)
				{
					((Behaviour)component).enabled = true;
					component.sprite = reservedItem.itemProperties.itemIcon;
				}
				else
				{
					((Behaviour)component).enabled = false;
					component.sprite = null;
				}
			}
			if (SessionManager.numReservedItemSlotsUnlocked > 0 && !ConfigSettings.hideFocusHotbarTooltip.Value)
			{
				if ((Object)(object)hotkeyTooltip == (Object)null)
				{
					hotkeyTooltip = new GameObject("ReservedItemSlotTooltip", new Type[2]
					{
						typeof(RectTransform),
						typeof(TextMeshProUGUI)
					}).GetComponent<TextMeshProUGUI>();
				}
				RectTransform rectTransform2 = ((TMP_Text)hotkeyTooltip).rectTransform;
				((Transform)rectTransform2).SetParent((Transform)(object)val);
				if (Object.op_Implicit((Object)(object)val))
				{
					((Transform)rectTransform2).localScale = Vector3.one;
					rectTransform2.sizeDelta = new Vector2(val.sizeDelta.x * 2f, 10f);
					rectTransform2.pivot = Vector2.one / 2f;
					rectTransform2.anchoredPosition3D = new Vector3(0f, 0f - rectTransform2.sizeDelta.x / 2f - itemSlotWidth / 2f - 5f, 0f);
					((TMP_Text)hotkeyTooltip).font = ((TMP_Text)HUDManager.Instance.controlTipLines[0]).font;
					((TMP_Text)hotkeyTooltip).fontSize = 7f * (val.sizeDelta.x / defaultItemSlotSize.x);
					((TMP_Text)hotkeyTooltip).alignment = (TextAlignmentOptions)4100;
					UpdateHotkeyTooltipText();
				}
				else
				{
					((Transform)rectTransform2).localScale = Vector3.zero;
				}
			}
			RecenterMainHotbarWithTwoLeftReserved();
			if ((Object)(object)noScrap1Frame != (Object)null)
			{
				ResetTint(noScrap1Frame);
				ApplyTintToFrame(noScrap1Frame);
			}
			if ((Object)(object)noScrap2Frame != (Object)null)
			{
				ResetTint(noScrap2Frame);
				ApplyTintToFrame(noScrap2Frame);
			}
			currentApplyHotbarPlusSize = ConfigSettings.applyHotbarPlusItemSlotSize.Value;
			currentHideEmptySlots = ConfigSettings.hideEmptyReservedItemSlots.Value;
		}

		public static void UpdateHotkeyTooltipText()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)localPlayerController == (Object)null || (Object)(object)hotkeyTooltip == (Object)null || Keybinds.FocusReservedHotbarAction == null)
			{
				return;
			}
			int num = (localPlayerUsingController ? 1 : 0);
			string text = "";
			string text2 = "";
			InputBinding val;
			if (num >= 0 && num < Keybinds.FocusReservedHotbarAction.bindings.Count)
			{
				val = Keybinds.FocusReservedHotbarAction.bindings[num];
				text = KeybindDisplayNames.GetKeybindDisplayName(((InputBinding)(ref val)).effectivePath);
			}
			else
			{
				Plugin.LogError("Failed to update FocusReservedHotbar keybind tooltip. Using controller: " + localPlayerUsingController + " NumFocusReservedHotbarActionBindings: " + Keybinds.FocusReservedHotbarAction.bindings.Count);
			}
			if (num >= 0 && num < Keybinds.ToggleFocusReservedHotbarAction.bindings.Count)
			{
				val = Keybinds.ToggleFocusReservedHotbarAction.bindings[num];
				text2 = KeybindDisplayNames.GetKeybindDisplayName(((InputBinding)(ref val)).effectivePath);
			}
			else
			{
				Plugin.LogError("Failed to update ToggleFocusReservedHotbar keybind tooltip. Using controller: " + localPlayerUsingController + " NumToggleFocusReservedHotbarActionBindings: " + Keybinds.ToggleFocusReservedHotbarAction.bindings.Count);
			}
			((TMP_Text)hotkeyTooltip).text = "";
			if (allowScroll)
			{
				return;
			}
			if (text != "")
			{
				((TMP_Text)hotkeyTooltip).text = $"Hold: [{text}]";
			}
			if (text2 != "" && text2 != text)
			{
				if (((TMP_Text)hotkeyTooltip).text != "")
				{
					TextMeshProUGUI obj = hotkeyTooltip;
					((TMP_Text)obj).text = ((TMP_Text)obj).text + "\n";
				}
				TextMeshProUGUI obj2 = hotkeyTooltip;
				((TMP_Text)obj2).text = ((TMP_Text)obj2).text + $"Toggle: [{text2}]";
			}
		}

		public static void UpdateToggledReservedItemSlotsUI()
		{
			if (ReservedHotbarManager.currentlyToggledItemSlots != null)
			{
				toggledReservedItemSlots = new HashSet<ReservedItemSlotData>(ReservedHotbarManager.currentlyToggledItemSlots);
			}
			else
			{
				toggledReservedItemSlots.Clear();
			}
			lerpToggledItemSlotFrames = true;
			largestPositionDifference = -1f;
		}

		private static float GetCurrentItemSlotSpacing()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Image val = HUDManager.Instance.itemSlotIconFrames[0];
				Image val2 = HUDManager.Instance.itemSlotIconFrames[1];
				if (((Object)val).name.ToLower().Contains("reserved") || ((Object)val2).name.ToLower().Contains("reserved"))
				{
					return defaultItemSlotSpacing;
				}
				return Mathf.Abs(((Graphic)val2).rectTransform.anchoredPosition.x - ((Graphic)val).rectTransform.anchoredPosition.x);
			}
			catch
			{
			}
			return defaultItemSlotSpacing;
		}

		[HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")]
		[HarmonyPostfix]
		public static void OnCloseQuickMenu()
		{
			if (HotbarPlus_Compat.Enabled || currentHideEmptySlots != ConfigSettings.hideEmptyReservedItemSlots.Value)
			{
				UpdateUI();
			}
		}
	}
	[HarmonyPatch]
	internal class MaskedEnemyPatcher
	{
		[HarmonyPatch(typeof(MaskedPlayerEnemy), "Awake")]
		[HarmonyPrefix]
		public static void InitMaskedEnemy(MaskedPlayerEnemy __instance)
		{
			if (ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value && !MaskedEnemyData.allMaskedEnemyData.ContainsKey(__instance))
			{
				MaskedEnemyData.allMaskedEnemyData.Add(__instance, new MaskedEnemyData(__instance));
			}
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "OnDestroy")]
		[HarmonyPrefix]
		public static void OnDestroy(MaskedPlayerEnemy __instance)
		{
			if (MaskedEnemyData.allMaskedEnemyData.TryGetValue(__instance, out var value))
			{
				value.DestroyEquippedItems();
				MaskedEnemyData.allMaskedEnemyData.Remove(__instance);
			}
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "Update")]
		[HarmonyPostfix]
		public static void Update(MaskedPlayerEnemy __instance)
		{
			if (ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value && MaskedEnemyData.allMaskedEnemyData.TryGetValue(__instance, out var value) && (Object)(object)value.originallyMimickingPlayer == (Object)null && (Object)(object)value.maskedEnemy.mimickingPlayer != (Object)null)
			{
				AddReservedItemsToMaskedEnemy(__instance);
			}
		}

		public static void AddReservedItemsToMaskedEnemy(MaskedPlayerEnemy maskedEnemy)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			if (!ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value || !MaskedEnemyData.allMaskedEnemyData.TryGetValue(maskedEnemy, out var value))
			{
				return;
			}
			value.originallyMimickingPlayer = value.maskedEnemy.mimickingPlayer;
			if (!ReservedPlayerData.allPlayerData.TryGetValue(value.originallyMimickingPlayer, out var value2))
			{
				Plugin.LogWarning("Failed to mimic player's equipped reserved items. Could not retrieve player data from: " + value.originallyMimickingPlayer.playerUsername);
				return;
			}
			for (int i = value2.reservedHotbarStartIndex; i < Mathf.Min(value2.reservedHotbarEndIndexExcluded, value2.playerController.ItemSlots.Length); i++)
			{
				GrabbableObject val = value2.playerController.ItemSlots[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int num = i - value2.reservedHotbarStartIndex;
				if (num < 0 || num >= SessionManager.unlockedReservedItemSlots.Count)
				{
					Plugin.LogWarning("Failed to add reserved item to MaskedEnemy. Could not get ReservedItemSlot at index: " + num + " Item: " + val.itemProperties.itemName + " SlotIndexInInventory: " + i + " ReservedHotbarStartIndex: " + value2.reservedHotbarStartIndex);
					continue;
				}
				ReservedItemData reservedItemData = SessionManager.unlockedReservedItemSlots[num].GetReservedItemData(val);
				if (reservedItemData.holsteredParentBone == PlayerBone.None)
				{
					continue;
				}
				Transform bone = value.boneMap.GetBone(reservedItemData.holsteredParentBone);
				if ((Object)(object)bone == (Object)null)
				{
					Plugin.LogWarning("Failed to get bone from masked enemy: " + reservedItemData.holsteredParentBone);
					continue;
				}
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, bone);
				val2.transform.localEulerAngles = reservedItemData.holsteredRotationOffset;
				val2.transform.localPosition = reservedItemData.holsteredPositionOffset;
				val2.transform.localScale = ((Component)val).transform.localScale;
				val2.layer = 6;
				MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>();
				foreach (MeshRenderer val3 in componentsInChildren)
				{
					if (!((Object)val3).name.Contains("ScanNode") && !((Component)val3).gameObject.CompareTag("DoNotSet") && !((Component)val3).gameObject.CompareTag("InteractTrigger"))
					{
						((Component)val3).gameObject.layer = 6;
					}
				}
				if (val is FlashlightItem)
				{
					Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>();
					for (int j = 0; j < componentsInChildren2.Length; j++)
					{
						((Behaviour)componentsInChildren2[j]).enabled = false;
					}
				}
				else
				{
					Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>();
					for (int j = 0; j < componentsInChildren2.Length; j++)
					{
						((Behaviour)componentsInChildren2[j]).enabled = true;
					}
				}
				GrabbableObject componentInChildren = val2.GetComponentInChildren<GrabbableObject>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.playerHeldBy = null;
					FlashlightItem val4 = (FlashlightItem)(object)((componentInChildren is FlashlightItem) ? componentInChildren : null);
					if ((Object)(object)val4 != (Object)null)
					{
						((Behaviour)val4.flashlightBulb).enabled = true;
						((Behaviour)val4.flashlightBulbGlow).enabled = true;
						if (((Renderer)val4.flashlightMesh).sharedMaterials.Length > 1 && (Object)(object)val4.bulbLight != (Object)null)
						{
							((Renderer)val4.flashlightMesh).sharedMaterials[1] = val4.bulbLight;
						}
					}
					ReservedItemsPatcher.ForceEnableItemMesh(componentInChildren, enabled: true);
					componentInChildren.EnablePhysics(false);
				}
				Object.DestroyImmediate((Object)(object)val2.GetComponentInChildren<NetworkObject>());
				Collider[] componentsInChildren3 = val2.GetComponentsInChildren<Collider>();
				for (int j = 0; j < componentsInChildren3.Length; j++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren3[j]);
				}
				MonoBehaviour[] componentsInChildren4 = val2.GetComponentsInChildren<MonoBehaviour>();
				for (int j = 0; j < componentsInChildren4.Length; j++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren4[j]);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class MouseScrollPatcher
	{
		private static float timeLoggedPreventedScroll;

		public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;

		[HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")]
		[HarmonyPrefix]
		public static void CorrectReservedScrollDirectionNextItemSlot(ref bool forward)
		{
			if (Keybinds.scrollingReservedHotbar)
			{
				forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SwitchItemSlotsServerRpc")]
		[HarmonyPrefix]
		public static void CorrectReservedScrollDirectionServerRpc(ref bool forward)
		{
			if (Keybinds.scrollingReservedHotbar)
			{
				forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")]
		[HarmonyPrefix]
		public static bool PreventInvertedScrollingReservedHotbar(CallbackContext context)
		{
			if (AllowScrollCompat.LoadedAndEnabled)
			{
				return true;
			}
			if (StartOfRound.Instance.localPlayerUsingController || SessionManager.numReservedItemSlotsUnlocked <= 0 || HUDPatcher.reservedItemSlots == null || localPlayerController.inTerminalMenu)
			{
				return true;
			}
			if (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved)
			{
				if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
				{
					return true;
				}
				float time = Time.time;
				if (!Keybinds.scrollingReservedHotbar)
				{
					return false;
				}
				if (ReservedPlayerData.localPlayerData.GetNumHeldReservedItems() == 1 && (Object)(object)ReservedPlayerData.localPlayerData.currentlySelectedItem != (Object)null && !ReservedHotbarManager.isToggledInReservedSlots)
				{
					if (ConfigSettings.verboseLogs.Value && time - timeLoggedPreventedScroll > 1f)
					{
						timeLoggedPreventedScroll = time;
					}
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class PlayerPatcher
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass25_0
		{
			public GrabbableObject __instance;
		}

		private static int INTERACTABLE_OBJECT_MASK = 0;

		public static int vanillaHotbarSize = 4;

		private static bool initialized = false;

		private static bool suppressNextAutoSwitchFromNoScrapDrop = false;

		private static int suppressedNoScrapSlotIndex = -1;

		private static int suppressExpireFrame = -1;

		public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;

		public static Dictionary<PlayerControllerB, ReservedPlayerData> allPlayerData => ReservedPlayerData.allPlayerData;

		public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData;

		public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked;

		private static bool IsNoScrapSlotName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			string text = name.Trim().ToLowerInvariant();
			if (!(text == "no_scrap_1"))
			{
				return text == "no_scrap_2";
			}
			return true;
		}

		private static void ArmNoScrapDropSuppression(PlayerControllerB controller, ReservedPlayerData playerData)
		{
			if (!((Object)(object)controller == (Object)null) && playerData != null && playerData.IsReservedItemSlot(controller.currentItemSlot))
			{
				ReservedItemSlotData currentlySelectedReservedItemSlot = playerData.GetCurrentlySelectedReservedItemSlot();
				if (currentlySelectedReservedItemSlot != null && IsNoScrapSlotName(currentlySelectedReservedItemSlot.slotName))
				{
					suppressedNoScrapSlotIndex = controller.currentItemSlot;
					suppressNextAutoSwitchFromNoScrapDrop = true;
					suppressExpireFrame = Time.frameCount + 6;
					Plugin.Log($"[NO_SCRAP] Armed keep-focus suppression at slot {suppressedNoScrapSlotIndex} (expires frame {suppressExpireFrame}).");
				}
			}
		}

		private static void ClearNoScrapDropSuppression()
		{
			suppressNextAutoSwitchFromNoScrapDrop = false;
			suppressedNoScrapSlotIndex = -1;
			suppressExpireFrame = -1;
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPrefix]
		private static void InitSession(StartOfRound __instance)
		{
			initialized = false;
			vanillaHotbarSize = 4;
			ReservedPlayerData.allPlayerData?.Clear();
			ClearNoScrapDropSuppression();
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Awake")]
		[HarmonyPostfix]
		private static void InitializePlayerController(PlayerControllerB __instance)
		{
			if (!initialized)
			{
				vanillaHotbarSize = __instance.ItemSlots.Length;
				INTERACTABLE_OBJECT_MASK = (int)Traverse.Create((object)__instance).Field("interactableObjectsMask").GetValue();
				initialized = true;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Start")]
		[HarmonyPrefix]
		private static void InitializePlayerControllerLate(PlayerControllerB __instance)
		{
			ReservedPlayerData value = new ReservedPlayerData(__instance);
			if (!allPlayerData.ContainsKey(__instance))
			{
				Plugin.Log("Initializing ReservedPlayerData for player: " + ((Object)__instance).name);
				allPlayerData.Add(__instance, value);
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPostfix]
		private static void CheckForChangedInventorySize(PlayerControllerB __instance)
		{
			if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || reservedHotbarSize <= 0 || value.hotbarSize == __instance.ItemSlots.Length)
			{
				return;
			}
			value.hotbarSize = __instance.ItemSlots.Length;
			int num = -1;
			if ((Object)(object)__instance == (Object)(object)localPlayerController)
			{
				if (HUDPatcher.reservedItemSlots != null && HUDPatcher.reservedItemSlots.Count > 0)
				{
					num = Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, HUDPatcher.reservedItemSlots[0]);
					Plugin.Log("OnUpdateInventorySize A for local player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
				}
				if (num == -1)
				{
					for (int i = 0; i < HUDManager.Instance.itemSlotIconFrames.Length; i++)
					{
						if (((Object)HUDManager.Instance.itemSlotIconFrames[i]).name.ToLower().Contains("reserved"))
						{
							num = i;
							Plugin.Log("OnUpdateInventorySize B for local player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
							break;
						}
					}
				}
				PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
				foreach (PlayerControllerB val in allPlayerScripts)
				{
					if (ReservedPlayerData.allPlayerData.TryGetValue(val, out var value2) && value2 != value && reservedHotbarSize > 0 && value2.hotbarSize != val.ItemSlots.Length)
					{
						value2.reservedHotbarStartIndex = num;
					}
				}
			}
			if (num == -1)
			{
				num = value.reservedHotbarStartIndex;
				Plugin.Log("OnUpdateInventorySize C for player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
			}
			if (num == -1)
			{
				num = vanillaHotbarSize;
				Plugin.Log("OnUpdateInventorySize D for player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
			}
			value.reservedHotbarStartIndex = num;
			if (value.reservedHotbarStartIndex < 0)
			{
				Plugin.LogError("Set new reserved start index to slot: " + value.reservedHotbarStartIndex + ".");
			}
			if (value.reservedHotbarEndIndexExcluded - 1 >= value.playerController.ItemSlots.Length)
			{
				Plugin.LogError("Set new reserved start index to slot: " + value.reservedHotbarStartIndex + " Last reserved slot index: " + (value.reservedHotbarEndIndexExcluded - 1) + " Inventory size: " + value.playerController.ItemSlots.Length + ".");
			}
			if (value.isLocalPlayer)
			{
				HUDPatcher.UpdateUI();
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
		[HarmonyPrefix]
		private static bool BeginGrabReservedItemPrefix(PlayerControllerB __instance)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return true;
			}
			localPlayerData.grabbingReservedItemSlotData = null;
			localPlayerData.grabbingReservedItemData = null;
			localPlayerData.grabbingReservedItem = null;
			localPlayerData.previousHotbarIndex = -1;
			if (__instance.twoHanded || __instance.sinkingValue > 0.73f)
			{
				return true;
			}
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(new Ray(((Component)__instance.gameplayCamera).transform.position, ((Component)__instance.gameplayCamera).transform.forward), ref val, __instance.grabDistance, INTERACTABLE_OBJECT_MASK) && ((Component)((RaycastHit)(ref val)).collider).gameObject.layer != 8 && ((Component)((RaycastHit)(ref val)).collider).tag == "PhysicsProp")
			{
				GrabbableObject component = ((Component)((Component)((RaycastHit)(ref val)).collider).transform).gameObject.GetComponent<GrabbableObject>();
				if ((Object)(object)component != (Object)null && !__instance.inSpecialInteractAnimation && !component.isHeld && !component.isPocketed)
				{
					NetworkObject networkObject = ((NetworkBehaviour)component).NetworkObject;
					if ((Object)(object)networkObject != (Object)null && networkObject.IsSpawned)
					{
						if (SessionManager.TryGetUnlockedItemData(component, out var itemData))
						{
							localPlayerData.grabbingReservedItemData = itemData;
							localPlayerData.grabbingReservedItem = component;
							localPlayerData.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
							ReservedItemSlotData firstEmptySlotForReservedItem = localPlayerData.GetFirstEmptySlotForReservedItem(itemData.itemName);
							if (firstEmptySlotForReservedItem != null)
							{
								localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForReservedItem;
								Plugin.Log($"Beginning grab on reserved item: {itemData.itemName} -> slot {firstEmptySlotForReservedItem.slotName} (prev slot {localPlayerData.previousHotbarIndex})");
							}
							else if (ItemNameMap.IsZeroValueScrap(component))
							{
								ReservedItemSlotData firstEmptySlotForZeroValueScrap = localPlayerData.GetFirstEmptySlotForZeroValueScrap();
								if (firstEmptySlotForZeroValueScrap != null)
								{
									localPlayerData.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__");
									localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap;
									Plugin.Log($"Reserved full; routing IsZeroValueScrap into {firstEmptySlotForZeroValueScrap.slotName} (prev slot {localPlayerData.previousHotbarIndex})");
								}
							}
						}
						else if (ItemNameMap.IsZeroValueScrap(component))
						{
							ReservedItemSlotData firstEmptySlotForZeroValueScrap2 = localPlayerData.GetFirstEmptySlotForZeroValueScrap();
							if (firstEmptySlotForZeroValueScrap2 != null)
							{
								localPlayerData.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__");
								localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap2;
								localPlayerData.grabbingReservedItem = component;
								localPlayerData.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
								Plugin.Log($"Beginning grab on zero-value scrap into slot: {firstEmptySlotForZeroValueScrap2.slotName} (prev slot {localPlayerData.previousHotbarIndex})");
							}
						}
					}
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
		[HarmonyPostfix]
		private static void BeginGrabReservedItemPostfix(PlayerControllerB __instance)
		{
			if (localPlayerData == null || !localPlayerData.isGrabbingReservedItem || localPlayerData.IsReservedItemSlot(localPlayerData.previousHotbarIndex))
			{
				return;
			}
			if (localPlayerData.grabbingReservedItemSlotData == null && localPlayerData.grabbingReservedItemData != null)
			{
				ReservedItemSlotData firstEmptySlotForReservedItem = localPlayerData.GetFirstEmptySlotForReservedItem(localPlayerData.grabbingReservedItemData.itemName);
				if (firstEmptySlotForReservedItem != null)
				{
					localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForReservedItem;
				}
			}
			if (localPlayerData.grabbingReservedItemSlotData == null || (!localPlayerData.grabbingReservedItemSlotData.AutoSwitchOnPickup && !IsNoScrapSlotName(localPlayerData.grabbingReservedItemSlotData.slotName)))
			{
				SetSpecialGrabAnimationBool(__instance, setTrue: false, __instance.currentlyHeldObjectServer);
				GrabbableObject previouslyHeldItem = localPlayerData.previouslyHeldItem;
				if ((Object)(object)previouslyHeldItem != (Object)null)
				{
					SetSpecialGrabAnimationBool(__instance, setTrue: true, previouslyHeldItem);
				}
				__instance.playerBodyAnimator.SetBool("GrabValidated", true);
				__instance.playerBodyAnimator.SetBool("GrabInvalidated", false);
				__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation");
				__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded");
				if ((Object)(object)previouslyHeldItem != (Object)null)
				{
					__instance.playerBodyAnimator.ResetTrigger(previouslyHeldItem.itemProperties.pocketAnim);
				}
				__instance.twoHanded = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHanded;
				__instance.twoHandedAnimation = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHandedAnimation;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
		[HarmonyPrefix]
		private static void GrabReservedItemClientRpcPrefix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance)
		{
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !NetworkHelper.IsClientExecStage((NetworkBehaviour)(object)__instance) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value))
			{
				return;
			}
			NetworkObject val = default(NetworkObject);
			GrabbableObject val2 = default(GrabbableObject);
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening && grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2))
			{
				if (SessionManager.TryGetUnlockedItemData(val2, out var itemData))
				{
					ReservedItemSlotData firstEmptySlotForReservedItem = value.GetFirstEmptySlotForReservedItem(itemData.itemName);
					if (firstEmptySlotForReservedItem != null)
					{
						value.grabbingReservedItemSlotData = firstEmptySlotForReservedItem;
						value.grabbingReservedItemData = itemData;
						value.grabbingReservedItem = val2;
						value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
						return;
					}
					if (ItemNameMap.IsZeroValueScrap(val2))
					{
						ReservedItemSlotData firstEmptySlotForZeroValueScrap = value.GetFirstEmptySlotForZeroValueScrap();
						if (firstEmptySlotForZeroValueScrap != null)
						{
							value.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap;
							value.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__");
							value.grabbingReservedItem = val2;
							value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
							return;
						}
					}
				}
				else if (ItemNameMap.IsZeroValueScrap(val2))
				{
					ReservedItemSlotData firstEmptySlotForZeroValueScrap2 = value.GetFirstEmptySlotForZeroValueScrap();
					if (firstEmptySlotForZeroValueScrap2 != null)
					{
						value.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap2;
						value.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__");
						value.grabbingReservedItem = val2;
						value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
						return;
					}
				}
			}
			value.grabbingReservedItemSlotData = null;
			value.grabbingReservedItemData = null;
			value.grabbingReservedItem = null;
			value.previousHotbarIndex = -1;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
		[HarmonyPostfix]
		private static void GrabReservedItemClientRpcPostfix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance)
		{
			if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !NetworkHelper.IsClientExecStage((NetworkBehaviour)(object)__instance) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || !value.isGrabbingReservedItem)
			{
				return;
			}
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening)
			{
				NetworkObject val = default(NetworkObject);
				GrabbableObject val2 = default(GrabbableObject);
				if (grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2))
				{
					if (value.grabbingReservedItemSlotData != null)
					{
						bool flag = value.grabbingReservedItemSlotData.AutoSwitchOnPickup || IsNoScrapSlotName(value.grabbingReservedItemSlotData.slotName);
						if (!value.IsReservedItemSlot(value.previousHotbarIndex))
						{
							if (!flag)
							{
								if ((Object)(object)value.previouslyHeldItem != (Object)null)
								{
									value.previouslyHeldItem.EnableItemMeshes(true);
								}
								ReservedItemsPatcher.ForceEnableItemMesh(value.grabbingReservedItem, enabled: false);
								Traverse.Create((object)val2).Field("previousPlayerHeldBy").SetValue((object)__instance);
								if (value.isLocalPlayer)
								{
									int num = value.reservedHotbarStartIndex + value.grabbingReservedItemSlotData.GetReservedItemSlotIndex();
									((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().SetBool("selectedSlot", false);
									((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().SetBool("selectedSlot", true);
									((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().Play("PanelLines", 0, 1f);
									((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().Play("PanelEnlarge", 0, 1f);
								}
								else
								{
									SwitchToItemSlot(__instance, value.previousHotbarIndex);
								}
								SetSpecialGrabAnimationBool(__instance, setTrue: false, __instance.currentlyHeldObjectServer);
								GrabbableObject previouslyHeldItem = value.previouslyHeldItem;
								if ((Object)(object)previouslyHeldItem != (Object)null)
								{
									SetSpecialGrabAnimationBool(__instance, setTrue: true, previouslyHeldItem);
								}
								__instance.playerBodyAnimator.SetBool("GrabValidated", true);
								__instance.playerBodyAnimator.SetBool("GrabInvalidated", false);
								__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation");
								__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded");
								if ((Object)(object)previouslyHeldItem != (Object)null)
								{
									__instance.playerBodyAnimator.ResetTrigger(previouslyHeldItem.itemProperties.pocketAnim);
								}
								__instance.twoHanded = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHanded;
								__instance.twoHandedAnimation = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHandedAnimation;
							}
							else
							{
								int num2 = value.reservedHotbarStartIndex + val