Decompiled source of ReservedItemSlotCore v1.8.17

ReservedItemSlotCore.dll

Decompiled 3 weeks 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 BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using ReservedItemSlotCore.Compatibility;
using ReservedItemSlotCore.Config;
using ReservedItemSlotCore.Input;
using ReservedItemSlotCore.Networking;
using ReservedItemSlotCore.Patches;
using TMPro;
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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[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("ReservedBoomboxSlot")]
[assembly: InternalsVisibleTo("ReservedUtilitySlot")]
[assembly: InternalsVisibleTo("ReservedPersonalBoomboxSlot")]
[assembly: InternalsVisibleTo("ReservedKeySlot")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ReservedItemSlotCore
{
	internal class ReservedItemInfo
	{
		public static Dictionary<string, ReservedItemInfo> reservedItemsDictDefault = new Dictionary<string, ReservedItemInfo>();

		public static List<ReservedItemInfo> reservedItemsListDefault = new List<ReservedItemInfo>();

		public static List<ReservedItemInfo> reservedItemSlotRepsDefault = new List<ReservedItemInfo>();

		public static Dictionary<string, ReservedItemInfo> reservedItemsDict = new Dictionary<string, ReservedItemInfo>();

		public static List<ReservedItemInfo> reservedItemsList = new List<ReservedItemInfo>();

		public static List<ReservedItemInfo> reservedItemSlotReps = new List<ReservedItemInfo>();

		public string itemName = "";

		public HashSet<string> acceptedItemNames;

		public int hotbarSlotPriority = 0;

		public int reservedItemIndex = 0;

		public bool forceUpdateCanBeGrabbedBeforeGameStart = false;

		public bool canBeGrabbedBeforeGameStart = false;

		public bool forceUpdateRequiresBattery = false;

		public bool requiresBattery = false;

		public static int numReservedItemSlotsDefault => reservedItemSlotRepsDefault.Count;

		public ReservedItemInfo()
		{
		}

		public ReservedItemInfo(string itemName, int hotbarSlotPriority, bool forceUpdateCanBeGrabbedBeforeGameStart = false, bool canBeGrabbedBeforeGameStart = false, bool forceUpdateRequiresBattery = false, bool requiresBattery = false)
		{
			this.itemName = itemName;
			this.hotbarSlotPriority = hotbarSlotPriority;
			AddItemInfoToList(this);
			ReservedItemInfo info = new ReservedItemInfo(this);
			AddItemInfoToList(info, reservedItemsListDefault, reservedItemsDictDefault, reservedItemSlotRepsDefault);
		}

		public static void AddItemInfoToList(ReservedItemInfo info, List<ReservedItemInfo> _reservedItemsList = null, Dictionary<string, ReservedItemInfo> _reservedItemsDict = null, List<ReservedItemInfo> _reservedItemSlotReps = null)
		{
			if (_reservedItemsList == null)
			{
				_reservedItemsList = reservedItemsList;
			}
			if (_reservedItemsDict == null)
			{
				_reservedItemsDict = reservedItemsDict;
			}
			if (_reservedItemSlotReps == null)
			{
				_reservedItemSlotReps = reservedItemSlotReps;
			}
			if (!_reservedItemsDict.ContainsKey(info.itemName))
			{
				_reservedItemsDict.Add(info.itemName, info);
				_reservedItemsList.Add(info);
				int i;
				for (i = 0; i < _reservedItemSlotReps.Count; i++)
				{
					ReservedItemInfo reservedItemInfo = _reservedItemSlotReps[i];
					if (info.hotbarSlotPriority >= reservedItemInfo.hotbarSlotPriority)
					{
						break;
					}
				}
				info.reservedItemIndex = i;
				if (i == _reservedItemSlotReps.Count || info.hotbarSlotPriority != _reservedItemSlotReps[i].hotbarSlotPriority)
				{
					info.acceptedItemNames = new HashSet<string> { info.itemName };
					_reservedItemSlotReps.Insert(i, info);
					{
						foreach (ReservedItemInfo _reservedItems in _reservedItemsList)
						{
							if (info != _reservedItems && _reservedItems.reservedItemIndex >= i)
							{
								_reservedItems.reservedItemIndex++;
							}
						}
						return;
					}
				}
				info.acceptedItemNames = _reservedItemSlotReps[i].acceptedItemNames;
				info.acceptedItemNames.Add(info.itemName);
			}
			else
			{
				Plugin.Log($"Tried to add duplicate item name to the ReservedItems list: {info.itemName}. Sorting instead");
			}
		}

		public ReservedItemInfo(ReservedItemInfo copyFrom)
		{
			itemName = copyFrom.itemName;
			hotbarSlotPriority = copyFrom.hotbarSlotPriority;
			reservedItemIndex = copyFrom.reservedItemIndex;
			forceUpdateCanBeGrabbedBeforeGameStart = copyFrom.forceUpdateCanBeGrabbedBeforeGameStart;
			canBeGrabbedBeforeGameStart = copyFrom.canBeGrabbedBeforeGameStart;
			forceUpdateRequiresBattery = copyFrom.forceUpdateRequiresBattery;
			requiresBattery = copyFrom.requiresBattery;
		}
	}
	internal class ReservedPlayerData
	{
		public PlayerControllerB playerController;

		public ReservedItemInfo grabbingReservedItemInfo = null;

		public GrabbableObject grabbingReservedItem = null;

		public int previousHotbarIndex = -1;

		public bool inReservedHotbarSlots = false;

		public int hotbarSize = 4;

		public int reservedHotbarStartIndex = 4;

		public bool isLocalPlayer => (Object)(object)playerController != (Object)null && (Object)(object)playerController == (Object)(object)StartOfRound.Instance?.localPlayerController;

		public int currentItemSlot => playerController.currentItemSlot;

		public bool currentItemSlotIsReserved => currentItemSlot >= reservedHotbarStartIndex && currentItemSlot < reservedHotbarStartIndex + SyncManager.numReservedItemSlots;

		public GrabbableObject previouslyHeldItem => (previousHotbarIndex >= 0 && previousHotbarIndex < playerController.ItemSlots.Length) ? playerController.ItemSlots[previousHotbarIndex] : null;

		public bool throwingObject => (bool)Traverse.Create((object)playerController).Field("throwingObject").GetValue();

		public int reservedHotbarEndIndexExcluded => reservedHotbarStartIndex + SyncManager.numReservedItemSlots;

		public bool IsReservedItemSlot(int index)
		{
			return index >= reservedHotbarStartIndex && index < reservedHotbarStartIndex + SyncManager.numReservedItemSlots;
		}

		public int GetNumHeldReservedItems()
		{
			int num = 0;
			for (int i = 0; i < playerController.ItemSlots.Length; i++)
			{
				GrabbableObject val = playerController.ItemSlots[i];
				num += (((Object)(object)val != (Object)null && SyncManager.IsReservedItem(val.itemProperties.itemName)) ? 1 : 0);
			}
			return num;
		}

		public GrabbableObject GetReservedItem(ReservedItemInfo itemInfo)
		{
			if (itemInfo == null)
			{
				return null;
			}
			int num = reservedHotbarStartIndex + itemInfo.reservedItemIndex;
			return (num >= 0 && num < playerController.ItemSlots.Length) ? playerController.ItemSlots[num] : null;
		}

		public string DumpData()
		{
			if ((Object)(object)playerController == (Object)null)
			{
				Plugin.LogError("PLAYER NULL");
			}
			if (SyncManager.syncReservedItemSlotReps == null)
			{
				Plugin.LogError("REPS NULL");
			}
			string text = "[ReservedPlayerData Dump]\nPlayer: " + ((Object)playerController).name + (isLocalPlayer ? " [LocalPlayer]" : "") + "\nCurrentItemSlot: " + currentItemSlot + "\nRegisteredHotbarSize: " + hotbarSize + "\nActualHotbarSize: " + playerController.ItemSlots.Length + "\nCurrentlyGrabbingReservedItem: " + ((grabbingReservedItemInfo != null) ? grabbingReservedItemInfo.itemName : "false") + "\nReservedHotbarStartIndex: " + reservedHotbarStartIndex + "\n" + (isLocalPlayer ? ("NumItemSlotsHUD: " + HUDManager.Instance.itemSlotIconFrames.Length + "\n") : "") + "ItemsInInventory: [";
			for (int i = 0; i < playerController.ItemSlots.Length; i++)
			{
				if (i > 0)
				{
					text += ", ";
				}
				text += (("[" + i + "] " + (object)playerController.ItemSlots[i] != null) ? ((Object)playerController.ItemSlots[i]).name : "Empty");
			}
			return text + "]\nNumHeldReservedItems: " + GetNumHeldReservedItems();
		}
	}
	[BepInPlugin("FlipMods.ReservedItemSlotCore", "ReservedItemSlotCore", "1.8.17")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		public static Plugin instance;

		private static ManualLogSource logger;

		public static Dictionary<string, ReservedItemInfo> reservedItemsDictDefault => ReservedItemInfo.reservedItemsDictDefault;

		public static List<ReservedItemInfo> reservedItemsListDefault => ReservedItemInfo.reservedItemsListDefault;

		public static List<ReservedItemInfo> reservedItemSlotRepsDefault => ReservedItemInfo.reservedItemSlotRepsDefault;

		public static int numReservedItemSlotsDefault => ReservedItemInfo.numReservedItemSlotsDefault;

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

		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)
			{
				_harmony.PatchAll(item);
			}
		}

		private void CreateCustomLogger()
		{
			try
			{
				logger = Logger.CreateLogSource($"{((BaseUnityPlugin)this).Info.Metadata.Name}-{((BaseUnityPlugin)this).Info.Metadata.Version}");
			}
			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 bool IsModLoaded(string guid)
		{
			return Chainloader.PluginInfos.ContainsKey(guid);
		}

		public static bool IsReservedItemDefault(string itemName)
		{
			return reservedItemsDictDefault.ContainsKey(itemName);
		}

		public static ReservedItemInfo GetReservedItemInfoDefault(string itemName)
		{
			return IsReservedItemDefault(itemName) ? reservedItemsDictDefault[itemName] : null;
		}

		public static ReservedItemInfo GetReservedItemInfoDefault(GrabbableObject item)
		{
			return ((Object)(object)item != (Object)null) ? GetReservedItemInfoDefault(item.itemProperties.itemName) : null;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "FlipMods.ReservedItemSlotCore";

		public const string PLUGIN_NAME = "ReservedItemSlotCore";

		public const string PLUGIN_VERSION = "1.8.17";
	}
	[HarmonyPatch]
	public static class UpdateKeybindDisplayNames
	{
		public static bool usingControllerPrevious;

		public static bool usingController => StartOfRound.Instance.localPlayerUsingController;

		[HarmonyPatch(typeof(HUDManager), "Update")]
		[HarmonyPostfix]
		public static void CheckForInputSourceUpdate()
		{
			if (usingController != usingControllerPrevious)
			{
				usingControllerPrevious = usingController;
				UpdateControlTipLines();
			}
		}

		[HarmonyPatch(typeof(KepRemapPanel), "OnDisable")]
		[HarmonyPostfix]
		public static void OnCloseRemapPanel()
		{
			UpdateControlTipLines();
		}

		public static void UpdateControlTipLines()
		{
			HUDPatcher.UpdateHotkeyTooltipText();
		}
	}
}
namespace ReservedItemSlotCore.Config
{
	public static class ConfigSettings
	{
		public static ConfigEntry<bool> forceEnableThisModIfNotEnabledOnHost;

		public static ConfigEntry<bool> displayNegativePrioritySlotsLeftSideOfScreen;

		public static ConfigEntry<string> focusReservedHotbarHotkey;

		public static ConfigEntry<bool> toggleFocusReservedHotbar;

		public static ConfigEntry<bool> preventReservedItemSlotFade;

		public static Dictionary<string, ConfigEntryBase> currentConfigEntries = new Dictionary<string, ConfigEntryBase>();

		public static void BindConfigSettings()
		{
			Plugin.Log("BindingConfigs");
			forceEnableThisModIfNotEnabledOnHost = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("ReservedItemSlotCore", "ForceEnableThisModIfNotEnabledOnHost", false, "This is disabled by default for a reason, and it is NOT recommended to enable this, especially in public lobbies. Enabling this when the host does not have the ReservedItemSlotCore mod CAN, and likely WILL cause de-sync issues. You have been warned. This setting only applies if you are a non-host client, and the host does not have this mod."));
			displayNegativePrioritySlotsLeftSideOfScreen = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("ReservedItemSlotCore", "DisplayNegativePrioritySlotsLeftSideOfScreen", true, "For any reserved item slot mods that have a negative priority, by default, those slots will appear on the left side of the screen, rather than the right. Setting this option to false will have them appear on top of the slots on the right side."));
			focusReservedHotbarHotkey = AddConfigEntry<string>(((BaseUnityPlugin)Plugin.instance).Config.Bind<string>("ReservedItemSlotCore", "FocusReservedItemSlotsHotkey", "<Keyboard>/leftAlt", "This setting will be ignored if InputUtils is installed and enabled. (I recommend running InputUtils to edit keybinds in the in-game settings)"));
			toggleFocusReservedHotbar = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("ReservedItemSlotCore", "ToggleFocusReservedHotbar", false, "If set to true, swapping to the reserved hotbar slots will be toggled when pressing the hotkey rather than while holding the hotkey. Setting this option to true may have bugs at this current time."));
			preventReservedItemSlotFade = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("ReservedItemSlotCore", "PreventReservedHotbarSlotFade", false, "If true, the reserved hotbar slots will not fade with the rest of the default slots."));
			TryRemoveOldConfigSettings();
		}

		public static ConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry)
		{
			currentConfigEntries.Add(((ConfigEntryBase)configEntry).Definition.Key, (ConfigEntryBase)(object)configEntry);
			return configEntry;
		}

		public static string GetDisplayName(string key)
		{
			try
			{
				if (key.Length <= 1)
				{
					return key;
				}
				int num = key.IndexOf(">/");
				key = ((num >= 0) ? key.Substring(num + 2) : key);
				string text = key.ToLower();
				if (text.Contains("not-bound"))
				{
					return "";
				}
				text = text.Replace("leftalt", "Alt");
				text = text.Replace("rightalt", "Alt");
				text = text.Replace("leftctrl", "Ctrl");
				text = text.Replace("rightctrl", "Ctrl");
				text = text.Replace("leftshift", "Shift");
				text = text.Replace("rightshift", "Shift");
				text = text.Replace("leftbutton", "LMB");
				text = text.Replace("rightbutton", "RMB");
				text = text.Replace("middlebutton", "MMB");
				text = text.Replace("lefttrigger", "LT");
				text = text.Replace("righttrigger", "RT");
				text = text.Replace("leftshoulder", "LB");
				text = text.Replace("rightshoulder", "RB");
				text = text.Replace("leftstickpress", "LS");
				text = text.Replace("rightstickpress", "RS");
				text = text.Replace("dpad/", "DPad-");
				text = text.Replace("backquote", "`");
				try
				{
					text = char.ToUpper(text[0]) + text.Substring(1);
				}
				catch
				{
				}
				return text;
			}
			catch
			{
				return "";
			}
		}

		public static void TryRemoveOldConfigSettings()
		{
			HashSet<string> hashSet = new HashSet<string>();
			HashSet<string> hashSet2 = new HashSet<string>();
			foreach (ConfigEntryBase value in currentConfigEntries.Values)
			{
				hashSet.Add(value.Definition.Section);
				hashSet2.Add(value.Definition.Key);
			}
			try
			{
				Plugin.Log("Cleaning old config entries");
				ConfigFile config = ((BaseUnityPlugin)Plugin.instance).Config;
				string configFilePath = config.ConfigFilePath;
				if (!File.Exists(configFilePath))
				{
					return;
				}
				string text = File.ReadAllText(configFilePath);
				string[] array = File.ReadAllLines(configFilePath);
				string text2 = "";
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = array[i].Replace("\n", "");
					if (array[i].Length <= 0)
					{
						continue;
					}
					if (array[i].StartsWith("["))
					{
						if (text2 != "" && !hashSet.Contains(text2))
						{
							text2 = "[" + text2 + "]";
							int num = text.IndexOf(text2);
							int num2 = text.IndexOf(array[i]);
							text = text.Remove(num, num2 - num);
						}
						text2 = array[i].Replace("[", "").Replace("]", "").Trim();
					}
					else
					{
						if (!(text2 != ""))
						{
							continue;
						}
						if (i <= array.Length - 4 && array[i].StartsWith("##"))
						{
							int j;
							for (j = 1; i + j < array.Length && array[i + j].Length > 3; j++)
							{
							}
							if (hashSet.Contains(text2))
							{
								int num3 = array[i + j - 1].IndexOf("=");
								string item = array[i + j - 1].Substring(0, num3 - 1);
								if (!hashSet2.Contains(item))
								{
									int num4 = text.IndexOf(array[i]);
									int num5 = text.IndexOf(array[i + j - 1]) + array[i + j - 1].Length;
									text = text.Remove(num4, num5 - num4);
								}
							}
							i += j - 1;
						}
						else if (array[i].Length > 3)
						{
							text = text.Replace(array[i], "");
						}
					}
				}
				if (!hashSet.Contains(text2))
				{
					text2 = "[" + text2 + "]";
					int num6 = text.IndexOf(text2);
					text = text.Remove(num6, text.Length - num6);
				}
				while (text.Contains("\n\n\n"))
				{
					text = text.Replace("\n\n\n", "\n\n");
				}
				File.WriteAllText(configFilePath, text);
				config.Reload();
			}
			catch
			{
			}
		}
	}
}
namespace ReservedItemSlotCore.Networking
{
	public static class NetworkHelper
	{
		private static int NONE_EXEC_STAGE = 0;

		private static int SERVER_EXEC_STAGE = 1;

		private static int CLIENT_EXEC_STAGE = 2;

		public static int GetExecStage(NetworkBehaviour __instance)
		{
			return (int)Traverse.Create((object)__instance).Field("__rpc_exec_stage").GetValue();
		}

		public static bool IsClientExecStage(NetworkBehaviour __instance)
		{
			return GetExecStage(__instance) == CLIENT_EXEC_STAGE;
		}

		public static bool IsServerExecStage(NetworkBehaviour __instance)
		{
			return GetExecStage(__instance) == SERVER_EXEC_STAGE;
		}

		public static bool IsValidClientRpcExecStage(NetworkBehaviour __instance)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
			{
				return false;
			}
			int num = (int)Traverse.Create((object)__instance).Field("__rpc_exec_stage").GetValue();
			if ((singleton.IsServer || singleton.IsHost) && num != 2)
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal class SyncManager
	{
		public static PlayerControllerB localPlayerController;

		public static bool isSynced = false;

		public static Dictionary<string, ReservedItemInfo> syncReservedItemsDict = new Dictionary<string, ReservedItemInfo>();

		public static List<ReservedItemInfo> syncReservedItemsList = new List<ReservedItemInfo>();

		public static List<ReservedItemInfo> syncReservedItemSlotReps = new List<ReservedItemInfo>();

		public static bool canUseModDisabledOnHost => ConfigSettings.forceEnableThisModIfNotEnabledOnHost.Value;

		public static int numReservedItemSlots => syncReservedItemSlotReps.Count;

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

		public static bool TryGetReservedItemInfo(string itemName, out ReservedItemInfo info)
		{
			info = null;
			if (IsReservedItem(itemName))
			{
				info = syncReservedItemsDict[itemName];
				return true;
			}
			return false;
		}

		public static bool TryGetReservedItemInfo(GrabbableObject item, out ReservedItemInfo info)
		{
			info = null;
			return (Object)(object)item != (Object)null && TryGetReservedItemInfo(item.itemProperties.itemName, out info);
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPrefix]
		public static void ResetValues()
		{
			isSynced = false;
			localPlayerController = null;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		public static void Init(PlayerControllerB __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			localPlayerController = __instance;
			NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlots-OnSwapHotbarClientRpc", new HandleNamedMessageDelegate(OnSwapHotbarClientRpc));
			NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlots-RequestSyncClientRpc", new HandleNamedMessageDelegate(RequestSyncClientRpc));
			if (NetworkManager.Singleton.IsServer)
			{
				isSynced = true;
				syncReservedItemsDict = ReservedItemInfo.reservedItemsDict;
				syncReservedItemsList = ReservedItemInfo.reservedItemsList;
				syncReservedItemSlotReps = ReservedItemInfo.reservedItemSlotReps;
				NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlots-OnSwapHotbarServerRpc", new HandleNamedMessageDelegate(OnSwapHotbarServerRpc));
				NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlots-RequestSyncServerRpc", new HandleNamedMessageDelegate(RequestSyncServerRpc));
				{
					foreach (ReservedItemInfo syncReservedItems in syncReservedItemsList)
					{
						ReservedItemInfo reservedItemInfo = ReservedItemInfo.reservedItemsDictDefault[syncReservedItems.itemName];
						syncReservedItems.hotbarSlotPriority = reservedItemInfo.hotbarSlotPriority;
						syncReservedItems.reservedItemIndex = reservedItemInfo.reservedItemIndex;
					}
					return;
				}
			}
			isSynced = false;
			if (canUseModDisabledOnHost)
			{
				syncReservedItemsDict = ReservedItemInfo.reservedItemsDict;
				syncReservedItemsList = ReservedItemInfo.reservedItemsList;
				syncReservedItemSlotReps = ReservedItemInfo.reservedItemSlotReps;
			}
			else
			{
				syncReservedItemsDict = new Dictionary<string, ReservedItemInfo>();
				syncReservedItemsList = new List<ReservedItemInfo>();
				syncReservedItemSlotReps = new List<ReservedItemInfo>();
			}
			RequestSyncWithServer();
		}

		private static void RequestSyncWithServer()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsClient)
			{
				Plugin.Log("Requesting sync with server.");
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlots-RequestSyncServerRpc", 0uL, new FastBufferWriter(0, (Allocator)2, -1), (NetworkDelivery)3);
			}
		}

		private static void RequestSyncServerRpc(ulong clientId, FastBufferReader reader)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkManager.Singleton.IsServer)
			{
				return;
			}
			Plugin.Log("Receiving sync request from client: " + clientId);
			int num = 4 * syncReservedItemsList.Count;
			foreach (ReservedItemInfo syncReservedItems in syncReservedItemsList)
			{
				num += 4 + 2 * syncReservedItems.itemName.Length;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, -1);
			int count = syncReservedItemsList.Count;
			((FastBufferWriter)(ref val)).WriteValue<int>(ref count, default(ForPrimitives));
			foreach (ReservedItemInfo syncReservedItems2 in syncReservedItemsList)
			{
				count = syncReservedItems2.itemName.Length;
				((FastBufferWriter)(ref val)).WriteValue<int>(ref count, default(ForPrimitives));
				string itemName = syncReservedItems2.itemName;
				for (int i = 0; i < itemName.Length; i++)
				{
					char c = itemName[i];
					((FastBufferWriter)(ref val)).WriteValue<char>(ref c, default(ForPrimitives));
				}
				((FastBufferWriter)(ref val)).WriteValue<int>(ref syncReservedItems2.hotbarSlotPriority, default(ForPrimitives));
			}
			Plugin.Log("Sent sync to client.");
			NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlots-RequestSyncClientRpc", clientId, val, (NetworkDelivery)3);
		}

		private static void RequestSyncClientRpc(ulong clientId, FastBufferReader reader)
		{
			//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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer)
			{
				return;
			}
			PlayerPatcher.isSynced = false;
			isSynced = true;
			syncReservedItemsDict = new Dictionary<string, ReservedItemInfo>();
			syncReservedItemsList = new List<ReservedItemInfo>();
			syncReservedItemSlotReps = new List<ReservedItemInfo>();
			Plugin.Log("Receiving sync from server.");
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValue<int>(ref num, default(ForPrimitives));
			int num2 = default(int);
			char c = default(char);
			for (int i = 0; i < num; i++)
			{
				((FastBufferReader)(ref reader)).ReadValue<int>(ref num2, default(ForPrimitives));
				((FastBufferReader)(ref reader)).TryBeginRead(2 * num2);
				string text = "";
				for (int j = 0; j < num2; j++)
				{
					((FastBufferReader)(ref reader)).ReadValue<char>(ref c, default(ForPrimitives));
					text += c;
				}
				bool flag = ReservedItemInfo.reservedItemsDict.ContainsKey(text);
				ReservedItemInfo reservedItemInfo = (ReservedItemInfo.reservedItemsDict.ContainsKey(text) ? ReservedItemInfo.reservedItemsDict[text] : new ReservedItemInfo
				{
					itemName = text
				});
				((FastBufferReader)(ref reader)).ReadValue<int>(ref reservedItemInfo.hotbarSlotPriority, default(ForPrimitives));
				Plugin.Log("Receiving sync for item: - Item: " + reservedItemInfo.itemName + " Prio: " + reservedItemInfo.hotbarSlotPriority);
				ReservedItemInfo.AddItemInfoToList(reservedItemInfo, syncReservedItemsList, syncReservedItemsDict, syncReservedItemSlotReps);
			}
			Plugin.Log("Received sync for " + syncReservedItemSlotReps.Count + " reserved item slots. (" + syncReservedItemsList.Count + " items total)");
		}

		private static void SendSwapHotbarUpdate(int hotbarSlot)
		{
			//IL_003b: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsClient)
			{
				Plugin.Log("Sending OnSwapReservedHotbar update to server. Hotbar slot: " + hotbarSlot);
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
				((FastBufferWriter)(ref val)).WriteValue<int>(ref hotbarSlot, default(ForPrimitives));
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlots-OnSwapHotbarServerRpc", 0uL, val, (NetworkDelivery)3);
			}
		}

		private static void OnSwapHotbarServerRpc(ulong clientId, FastBufferReader reader)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsServer)
			{
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValue<int>(ref num, default(ForPrimitives));
				Plugin.Log("Receiving OnSwapReservedHotbar update from client. ClientId: " + clientId + " Slot: " + num);
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1);
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref clientId, default(ForPrimitives));
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("ReservedItemSlots-OnSwapHotbarClientRpc", val, (NetworkDelivery)3);
			}
		}

		private static void OnSwapHotbarClientRpc(ulong clientId, FastBufferReader reader)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsClient)
			{
				int hotbarSlot = default(int);
				((FastBufferReader)(ref reader)).ReadValue<int>(ref hotbarSlot, default(ForPrimitives));
				ulong num = default(ulong);
				((FastBufferReader)(ref reader)).ReadValue<ulong>(ref num, default(ForPrimitives));
				Plugin.Log("Receiving OnSwapReservedHotbar update from client. ClientId: " + num + " Slot: " + hotbarSlot);
				if (num != localPlayerController.actualClientId && !TryUpdateClientHotbarSlot(num, hotbarSlot))
				{
					Plugin.Log("Failed to receive hotbar swap index from Client: " + num);
				}
			}
		}

		private static bool TryUpdateClientHotbarSlot(ulong clientId, int hotbarSlot)
		{
			for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[i];
				if (val.actualClientId == clientId)
				{
					CallSwitchToItemSlotMethod(val, hotbarSlot);
					return true;
				}
			}
			return false;
		}

		public static void SwapHotbarSlot(int hotbarIndex)
		{
			SendSwapHotbarUpdate(hotbarIndex);
			CallSwitchToItemSlotMethod(localPlayerController, hotbarIndex);
		}

		private static void CallSwitchToItemSlotMethod(PlayerControllerB playerController, int hotbarIndex)
		{
			if (!((Object)(object)playerController == (Object)null) && playerController.ItemSlots != null && hotbarIndex >= 0 && hotbarIndex < playerController.ItemSlots.Length)
			{
				if ((Object)(object)playerController == (Object)(object)localPlayerController)
				{
					ShipBuildModeManager.Instance.CancelBuildMode(true);
					playerController.playerBodyAnimator.SetBool("GrabValidated", false);
				}
				ReservedItemPatcher.SwitchToItemSlot(playerController, hotbarIndex);
				if ((Object)(object)playerController.currentlyHeldObjectServer != (Object)null)
				{
					((Component)playerController.currentlyHeldObjectServer).gameObject.GetComponent<AudioSource>().PlayOneShot(playerController.currentlyHeldObjectServer.itemProperties.grabSFX, 0.6f);
				}
			}
		}
	}
}
namespace ReservedItemSlotCore.Input
{
	internal class InputUtilsCompat
	{
		internal static bool Enabled => Plugin.IsModLoaded("com.rune580.LethalCompanyInputUtils");

		internal static InputActionAsset Asset => ((LcInputActions)IngameKeybinds.Instance).Asset;

		public static InputAction FocusReservedHotbarHotkey => IngameKeybinds.Instance.FocusReservedHotbarHotkey;

		internal static void Init()
		{
			if (Enabled && IngameKeybinds.Instance == null)
			{
				IngameKeybinds.Instance = new IngameKeybinds();
			}
		}
	}
	internal class IngameKeybinds : LcInputActions
	{
		internal static IngameKeybinds Instance;

		[InputAction("<Keyboard>/leftAlt", GamepadPath = "<Gamepad>/leftShoulder", Name = "Swap hotbars")]
		internal InputAction FocusReservedHotbarHotkey { get; set; }

		internal static InputActionAsset GetAsset()
		{
			return ((LcInputActions)Instance).Asset;
		}
	}
	[HarmonyPatch]
	internal class Keybinds
	{
		public static InputActionAsset Asset;

		public static InputActionMap ActionMap;

		public static InputAction FocusReservedHotbarAction;

		public static InputAction RawScrollAction;

		public static bool holdingModifierKey;

		public static bool scrollingReservedHotbar;

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

		[HarmonyPatch(typeof(PreInitSceneScript), "Awake")]
		[HarmonyPrefix]
		public static void AddToKeybindMenu()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			if (InputUtilsCompat.Enabled)
			{
				Asset = InputUtilsCompat.Asset;
				FocusReservedHotbarAction = InputUtilsCompat.FocusReservedHotbarHotkey;
			}
			else
			{
				Asset = ScriptableObject.CreateInstance<InputActionAsset>();
				ActionMap = new InputActionMap("ReservedItemSlots");
				InputActionSetupExtensions.AddActionMap(Asset, ActionMap);
				FocusReservedHotbarAction = InputActionSetupExtensions.AddAction(ActionMap, "ReservedItemSlots.FocusReservedHotbar", (InputActionType)0, ConfigSettings.focusReservedHotbarHotkey.Value, (string)null, (string)null, (string)null, (string)null);
				InputActionSetupExtensions.AddBinding(FocusReservedHotbarAction, "<Gamepad>/leftShoulder", (string)null, (string)null, (string)null);
			}
			RawScrollAction = new InputAction("ReservedItemSlots.RawScroll", (InputActionType)0, "<Mouse>/scroll/y", (string)null, (string)null, (string)null);
		}

		[HarmonyPatch(typeof(StartOfRound), "OnEnable")]
		[HarmonyPrefix]
		public static void OnEnable()
		{
			Asset.Enable();
			RawScrollAction.Enable();
			FocusReservedHotbarAction.performed += FocusReservedHotbarSlotsAction;
			if (!ConfigSettings.toggleFocusReservedHotbar.Value)
			{
				FocusReservedHotbarAction.canceled += UnfocusReservedHotbarSlotsPerformed;
			}
			RawScrollAction.performed += OnScrollReservedHotbar;
		}

		[HarmonyPatch(typeof(StartOfRound), "OnDisable")]
		[HarmonyPrefix]
		public static void OnDisable()
		{
			Asset.Disable();
			RawScrollAction.Disable();
			FocusReservedHotbarAction.performed -= FocusReservedHotbarSlotsAction;
			if (!ConfigSettings.toggleFocusReservedHotbar.Value)
			{
				FocusReservedHotbarAction.canceled -= UnfocusReservedHotbarSlotsPerformed;
			}
			RawScrollAction.performed -= OnScrollReservedHotbar;
		}

		private static void FocusReservedHotbarSlotsAction(CallbackContext context)
		{
			if ((Object)(object)localPlayerController == (Object)null || !((NetworkBehaviour)localPlayerController).IsOwner || !localPlayerController.isPlayerControlled || (((NetworkBehaviour)localPlayerController).IsServer && !localPlayerController.isHostPlayerObject) || SyncManager.numReservedItemSlots <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return;
			}
			if (!ConfigSettings.toggleFocusReservedHotbar.Value)
			{
				holdingModifierKey = true;
			}
			if (((CallbackContext)(ref context)).performed && ReservedItemPatcher.CanSwapToReservedHotbarSlot())
			{
				if (!ConfigSettings.toggleFocusReservedHotbar.Value)
				{
					ReservedItemPatcher.FocusReservedHotbarSlots(active: true);
				}
				else
				{
					ReservedItemPatcher.FocusReservedHotbarSlots(!PlayerPatcher.playerDataLocal.currentItemSlotIsReserved);
				}
			}
		}

		private static void UnfocusReservedHotbarSlotsPerformed(CallbackContext context)
		{
			if (!((Object)(object)localPlayerController == (Object)null) && ((NetworkBehaviour)localPlayerController).IsOwner && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject))
			{
				holdingModifierKey = false;
				if (((CallbackContext)(ref context)).canceled && ReservedItemPatcher.CanSwapToReservedHotbarSlot())
				{
					ReservedItemPatcher.FocusReservedHotbarSlots(active: false);
				}
			}
		}

		private static void OnScrollReservedHotbar(CallbackContext context)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)localPlayerController == (Object)null) && ((NetworkBehaviour)localPlayerController).IsOwner && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject) && ((CallbackContext)(ref context)).performed && !PlayerPatcher.playerDataLocal.throwingObject && !scrollingReservedHotbar && PlayerPatcher.playerDataLocal.currentItemSlotIsReserved && PlayerPatcher.playerDataLocal.grabbingReservedItemInfo == null)
			{
				scrollingReservedHotbar = true;
				MethodInfo method = ((object)localPlayerController).GetType().GetMethod("ScrollMouse_performed", BindingFlags.Instance | BindingFlags.NonPublic);
				method.Invoke(localPlayerController, new object[1] { context });
				((MonoBehaviour)localPlayerController).StartCoroutine(ResetScrollDelayed());
			}
			static IEnumerator ResetScrollDelayed()
			{
				yield return null;
				yield return (object)new WaitForEndOfFrame();
				scrollingReservedHotbar = false;
			}
		}
	}
}
namespace ReservedItemSlotCore.Patches
{
	[HarmonyPatch]
	public static class HUDPatcher
	{
		private static bool usingController;

		private static float iconWidth;

		private static float xPos;

		private static TextMeshProUGUI hotkeyTooltip;

		public static List<Image> reservedItemSlots;

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

		public static bool localPlayerUsingController => (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.localPlayerUsingController;

		public static bool hasReservedItemSlotsAndEnabled => reservedItemSlots != null && reservedItemSlots.Count > 0 && ((Component)reservedItemSlots[0]).gameObject.activeSelf && ((Behaviour)reservedItemSlots[0]).enabled;

		[HarmonyPatch(typeof(HUDManager), "Awake")]
		[HarmonyPostfix]
		public static void Initialize(HUDManager __instance)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			CanvasScaler componentInParent = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<CanvasScaler>();
			AspectRatioFitter componentInParent2 = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<AspectRatioFitter>();
			iconWidth = ((Component)__instance.itemSlotIconFrames[0]).GetComponent<RectTransform>().sizeDelta.x;
			xPos = componentInParent.referenceResolution.x / 2f / componentInParent2.aspectRatio - iconWidth / 4f;
			reservedItemSlots = new List<Image>();
		}

		[HarmonyPatch(typeof(StartOfRound), "Update")]
		[HarmonyPostfix]
		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 && __instance.localPlayerUsingController != usingController)
			{
				usingController = __instance.localPlayerUsingController;
				UpdateHotkeyTooltipText();
			}
		}

		public static void AddNewHotbarSlotsHud()
		{
			//IL_0048: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerPatcher.reservedHotbarSize <= 0)
			{
				return;
			}
			List<Image> list = new List<Image>(HUDManager.Instance.itemSlotIconFrames);
			List<Image> list2 = new List<Image>(HUDManager.Instance.itemSlotIcons);
			float y = ((Component)HUDManager.Instance.itemSlotIconFrames[0]).GetComponent<RectTransform>().sizeDelta.y;
			Vector3 eulerAngles = ((Transform)((Component)HUDManager.Instance.itemSlotIconFrames[0]).GetComponent<RectTransform>()).eulerAngles;
			Vector3 eulerAngles2 = ((Transform)((Component)HUDManager.Instance.itemSlotIcons[0]).GetComponent<RectTransform>()).eulerAngles;
			Plugin.Log($"Adding {SyncManager.syncReservedItemSlotReps.Count} reserved item slots to the inventory HUD. Previous inventory HUD size: {PlayerPatcher.playerDataLocal.reservedHotbarStartIndex}");
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < SyncManager.syncReservedItemSlotReps.Count; i++)
			{
				ReservedItemInfo reservedItemInfo = SyncManager.syncReservedItemSlotReps[i];
				Plugin.Log($"Adding Reserved item slot for item types [{reservedItemInfo.itemName}]. Inventory index: {list.Count}");
				float num3 = ((Graphic)HUDManager.Instance.itemSlotIconFrames[0]).rectTransform.anchoredPosition.y + 1.125f * y * (float)((reservedItemInfo.hotbarSlotPriority >= 0) ? num : num2);
				Image val = Object.Instantiate<Image>(HUDManager.Instance.itemSlotIconFrames[0], ((Component)HUDManager.Instance.itemSlotIconFrames[0]).transform.parent);
				((Object)val).name = "Slot" + list.Count + " [ReservedItemSlot]";
				((Graphic)val).rectTransform.anchoredPosition = new Vector2((reservedItemInfo.hotbarSlotPriority >= 0) ? xPos : (0f - xPos), num3);
				((Transform)((Graphic)val).rectTransform).eulerAngles = eulerAngles;
				CanvasGroup val2 = ((Component)val).gameObject.AddComponent<CanvasGroup>();
				val2.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value;
				val2.alpha = 1f;
				Image component = ((Component)((Component)val).transform.GetChild(0)).GetComponent<Image>();
				((Object)component).name = "Icon";
				((Transform)((Graphic)component).rectTransform).eulerAngles = eulerAngles2;
				reservedItemSlots.Add(val);
				list.Insert(PlayerPatcher.playerDataLocal.reservedHotbarStartIndex + i, val);
				list2.Insert(PlayerPatcher.playerDataLocal.reservedHotbarStartIndex + i, component);
				if (reservedItemInfo.hotbarSlotPriority >= 0)
				{
					num++;
				}
				else
				{
					num2++;
				}
			}
			if (SyncManager.numReservedItemSlots > 0)
			{
				if ((Object)(object)hotkeyTooltip == (Object)null)
				{
					hotkeyTooltip = new GameObject("ReservedItemSlotTooltip", new Type[2]
					{
						typeof(RectTransform),
						typeof(TextMeshProUGUI)
					}).GetComponent<TextMeshProUGUI>();
				}
				RectTransform rectTransform = ((TMP_Text)hotkeyTooltip).rectTransform;
				((Component)rectTransform).transform.parent = ((Component)reservedItemSlots[0]).transform;
				((Transform)rectTransform).localScale = Vector3.one;
				rectTransform.sizeDelta = new Vector2(((Graphic)list[0]).rectTransform.sizeDelta.x * 2f, 10f);
				rectTransform.pivot = Vector2.one / 2f;
				rectTransform.anchoredPosition3D = new Vector3(0f, (0f - rectTransform.sizeDelta.x / 2f) * 1.2f, 0f);
				((TMP_Text)hotkeyTooltip).font = ((TMP_Text)HUDManager.Instance.controlTipLines[0]).font;
				((TMP_Text)hotkeyTooltip).fontSize = 7f;
				((TMP_Text)hotkeyTooltip).alignment = (TextAlignmentOptions)514;
				UpdateHotkeyTooltipText();
			}
			HUDManager.Instance.itemSlotIconFrames = list.ToArray();
			HUDManager.Instance.itemSlotIcons = list2.ToArray();
			Plugin.Log($"Finished adding {PlayerPatcher.reservedHotbarSize} Reserved Item slots in the inventory HUD.");
		}

		public static void UpdateHotkeyTooltipText()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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 && !Plugin.IsModLoaded("com.potatoepet.AdvancedCompany"))
			{
				int num = (localPlayerUsingController ? 1 : 0);
				InputBinding val = Keybinds.FocusReservedHotbarAction.bindings[num];
				string displayName = ConfigSettings.GetDisplayName(((InputBinding)(ref val)).path);
				((TMP_Text)hotkeyTooltip).text = (ConfigSettings.toggleFocusReservedHotbar.Value ? $"Toggle: [{displayName}]" : $"Hold: [{displayName}]");
			}
		}

		public static void UpdateHUD()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if (AdvancedCompanyPatcher.Enabled)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < PlayerPatcher.reservedHotbarSize; i++)
			{
				ReservedItemInfo reservedItemInfo = SyncManager.syncReservedItemSlotReps[i];
				int num3 = PlayerPatcher.playerDataLocal.reservedHotbarStartIndex + i;
				float num4 = ((Graphic)HUDManager.Instance.itemSlotIconFrames[0]).rectTransform.anchoredPosition.y + 1.125f * iconWidth * (float)((reservedItemInfo.hotbarSlotPriority >= 0) ? num : num2);
				((Graphic)HUDManager.Instance.itemSlotIconFrames[num3]).rectTransform.anchoredPosition = new Vector2((reservedItemInfo.hotbarSlotPriority >= 0) ? xPos : (0f - xPos), num4);
				if (reservedItemInfo.hotbarSlotPriority >= 0)
				{
					num++;
				}
				else
				{
					num2++;
				}
			}
		}
	}
	[HarmonyPatch]
	public static class MouseScrollPatcher
	{
		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)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (StartOfRound.Instance.localPlayerUsingController || SyncManager.numReservedItemSlots <= 0)
			{
				return true;
			}
			if (PlayerPatcher.playerDataLocal.currentItemSlotIsReserved)
			{
				if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
				{
					return true;
				}
				if (HUDPatcher.reservedItemSlots.Count >= 2 && ((Graphic)HUDPatcher.reservedItemSlots[1]).rectTransform.anchoredPosition.y - ((Graphic)HUDPatcher.reservedItemSlots[0]).rectTransform.anchoredPosition.y <= 5f)
				{
					return true;
				}
				if (!Keybinds.scrollingReservedHotbar || SyncManager.numReservedItemSlots == 1 || (PlayerPatcher.playerDataLocal.GetNumHeldReservedItems() == 1 && (Object)(object)localPlayerController.ItemSlots[localPlayerController.currentItemSlot] != (Object)null))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class ReservedItemPatcher
	{
		public static int indexInHotbar;

		public static int indexInReservedHotbar;

		public static PlayerControllerB localPlayerController => PlayerPatcher.localPlayerController;

		public static int reservedHotbarSize => SyncManager.numReservedItemSlots;

		private static GrabbableObject GetCurrentlyGrabbingObject(PlayerControllerB playerController)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return (GrabbableObject)Traverse.Create((object)playerController).Field("currentlyGrabbingObject").GetValue();
		}

		private static void SetCurrentlyGrabbingObject(PlayerControllerB playerController, GrabbableObject grabbable)
		{
			Traverse.Create((object)playerController).Field("currentlyGrabbingObject").SetValue((object)grabbable);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
		[HarmonyPrefix]
		public static bool GrabReservedItemPrefix(PlayerControllerB __instance)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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)
			if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return true;
			}
			PlayerPatcher.playerDataLocal.grabbingReservedItemInfo = null;
			PlayerPatcher.playerDataLocal.grabbingReservedItem = null;
			PlayerPatcher.playerDataLocal.previousHotbarIndex = -1;
			if (PlayerPatcher.playerDataLocal.currentItemSlotIsReserved && !ConfigSettings.toggleFocusReservedHotbar.Value)
			{
				return false;
			}
			if (__instance.twoHanded || __instance.sinkingValue > 0.73f)
			{
				return true;
			}
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(((Component)__instance.gameplayCamera).transform.position, ((Component)__instance.gameplayCamera).transform.forward);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val, ref val2, __instance.grabDistance, PlayerPatcher.INTERACTABLE_OBJECT_MASK) && ((Component)((RaycastHit)(ref val2)).collider).gameObject.layer != 8 && ((Component)((RaycastHit)(ref val2)).collider).tag == "PhysicsProp")
			{
				GrabbableObject component = ((Component)((Component)((RaycastHit)(ref val2)).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 && SyncManager.TryGetReservedItemInfo(component, out var info))
					{
						Plugin.Log("Beginning grab on reserved item: " + info.itemName);
						PlayerPatcher.playerDataLocal.grabbingReservedItemInfo = info;
						PlayerPatcher.playerDataLocal.grabbingReservedItem = component;
						PlayerPatcher.playerDataLocal.previousHotbarIndex = __instance.currentItemSlot;
					}
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
		[HarmonyPostfix]
		public static void GrabReservedItemPostfix(PlayerControllerB __instance)
		{
			if (PlayerPatcher.playerDataLocal.grabbingReservedItemInfo != null)
			{
				SetSpecialGrabAnimationBool(__instance, setTrue: false);
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
		[HarmonyPrefix]
		public static void GrabReservedItemClientRpcPrefix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance)
		{
			if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !NetworkHelper.IsClientExecStage((NetworkBehaviour)(object)__instance))
			{
				return;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[__instance];
			NetworkObject val = default(NetworkObject);
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening && grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null))
			{
				GrabbableObject component = ((Component)val).GetComponent<GrabbableObject>();
				if (SyncManager.TryGetReservedItemInfo(component, out var info))
				{
					if (IsItemSlotEmpty(info, __instance))
					{
						Plugin.Log("OnGrabReservedItem for Player: " + ((Object)__instance).name + " Item: " + info.itemName);
						reservedPlayerData.grabbingReservedItemInfo = info;
						reservedPlayerData.grabbingReservedItem = component;
						reservedPlayerData.previousHotbarIndex = __instance.currentItemSlot;
						return;
					}
					Plugin.LogWarning("OnGrabReservedItem SlotFilled. Player: " + ((Object)__instance).name + " Item: " + info.itemName + " Slot: " + (reservedPlayerData.reservedHotbarStartIndex + info.reservedItemIndex));
				}
			}
			reservedPlayerData.grabbingReservedItemInfo = null;
			reservedPlayerData.grabbingReservedItem = null;
			reservedPlayerData.previousHotbarIndex = -1;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
		[HarmonyPostfix]
		public static void GrabReservedItemClientRpcPostfix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance)
		{
			//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_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			if ((!SyncManager.isSynced && SyncManager.canUseModDisabledOnHost) || !NetworkHelper.IsClientExecStage((NetworkBehaviour)(object)__instance))
			{
				return;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[__instance];
			if (reservedPlayerData.grabbingReservedItemInfo == null)
			{
				return;
			}
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening)
			{
				NetworkObject val = default(NetworkObject);
				if (grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null))
				{
					GrabbableObject component = ((Component)val).GetComponent<GrabbableObject>();
					if (SyncManager.TryGetReservedItemInfo(component, out var info))
					{
						SetSpecialGrabAnimationBool(__instance, (Object)(object)reservedPlayerData.previouslyHeldItem != (Object)null, reservedPlayerData.previouslyHeldItem);
						Animator playerBodyAnimator = __instance.playerBodyAnimator;
						AnimatorStateInfo currentAnimatorStateInfo = __instance.playerBodyAnimator.GetCurrentAnimatorStateInfo(2);
						playerBodyAnimator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash, 2, 1f);
						if ((Object)(object)reservedPlayerData.previouslyHeldItem != (Object)null)
						{
							reservedPlayerData.previouslyHeldItem.EnableItemMeshes(true);
						}
						ForceDisableItemMesh(reservedPlayerData.grabbingReservedItem);
						Traverse.Create((object)component).Field("previousPlayerHeldBy").SetValue((object)__instance);
						if ((Object)(object)__instance != (Object)(object)localPlayerController)
						{
							Plugin.Log("OnGrabReservedItem completed. Player: " + ((Object)__instance).name + " Item: " + info.itemName + " Switching to previous slot: " + reservedPlayerData.previousHotbarIndex);
							SwitchToItemSlot(__instance, reservedPlayerData.previousHotbarIndex);
							Animator playerBodyAnimator2 = __instance.playerBodyAnimator;
							currentAnimatorStateInfo = __instance.playerBodyAnimator.GetCurrentAnimatorStateInfo(2);
							playerBodyAnimator2.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash, 2, 1f);
							reservedPlayerData.grabbingReservedItemInfo = null;
							reservedPlayerData.grabbingReservedItem = null;
							reservedPlayerData.previousHotbarIndex = -1;
						}
						else
						{
							int num = reservedPlayerData.reservedHotbarStartIndex + reservedPlayerData.grabbingReservedItemInfo.reservedItemIndex;
							((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().SetBool("selectedSlot", false);
							((Component)HUDManager.Instance.itemSlotIconFrames[reservedPlayerData.previousHotbarIndex]).GetComponent<Animator>().SetBool("selectedSlot", true);
							((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().Play("PanelLines", 0, 1f);
							((Component)HUDManager.Instance.itemSlotIconFrames[reservedPlayerData.previousHotbarIndex]).GetComponent<Animator>().Play("PanelEnlarge", 0, 1f);
						}
						return;
					}
				}
				else if ((Object)(object)__instance == (Object)(object)localPlayerController)
				{
					Plugin.Log("Failed to validate ReservedItemGrab by the local player. Object id: " + ((NetworkObjectReference)(ref grabbedObject)).NetworkObjectId + ".");
					Traverse.Create((object)localPlayerController).Field("grabInvalidated").SetValue((object)true);
				}
				else
				{
					Plugin.Log("Failed to validate ReservedItemGrab by player with id: " + ((Object)__instance).name + ". Object id: " + ((NetworkObjectReference)(ref grabbedObject)).NetworkObjectId + ".");
				}
			}
			reservedPlayerData.grabbingReservedItemInfo = null;
			reservedPlayerData.grabbingReservedItem = null;
			reservedPlayerData.previousHotbarIndex = -1;
		}

		[HarmonyPatch(typeof(GrabbableObject), "GrabItemOnClient")]
		[HarmonyPrefix]
		public static void OnReservedItemGrabbed(GrabbableObject __instance)
		{
			if (PlayerPatcher.playerDataLocal.grabbingReservedItemInfo != null && !((Object)(object)__instance != (Object)(object)GetCurrentlyGrabbingObject(localPlayerController)))
			{
				((MonoBehaviour)localPlayerController).StartCoroutine(OnReservedItemGrabbedEndOfFrame());
			}
			IEnumerator OnReservedItemGrabbedEndOfFrame()
			{
				yield return (object)new WaitForEndOfFrame();
				SwitchToItemSlot(localPlayerController, PlayerPatcher.playerDataLocal.previousHotbarIndex);
				PlayerPatcher.playerDataLocal.grabbingReservedItemInfo = null;
				PlayerPatcher.playerDataLocal.grabbingReservedItem = null;
				PlayerPatcher.playerDataLocal.previousHotbarIndex = -1;
				__instance.EnableItemMeshes(false);
				__instance.PocketItem();
				Animator playerBodyAnimator = localPlayerController.playerBodyAnimator;
				AnimatorStateInfo currentAnimatorStateInfo = localPlayerController.playerBodyAnimator.GetCurrentAnimatorStateInfo(2);
				playerBodyAnimator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash, 2, 1f);
			}
		}

		[HarmonyPatch(typeof(HUDManager), "ClearControlTips")]
		[HarmonyPrefix]
		public static bool PreventClearControlTipsGrabbingReservedItem(HUDManager __instance)
		{
			return PlayerPatcher.playerDataLocal == null || (Object)(object)PlayerPatcher.playerDataLocal.grabbingReservedItem == (Object)null;
		}

		[HarmonyPatch(typeof(GrabbableObject), "SetControlTipsForItem")]
		[HarmonyPrefix]
		public static bool PreventUpdateControlTipsGrabbingReservedItem(GrabbableObject __instance)
		{
			return PlayerPatcher.playerDataLocal == null || (Object)(object)PlayerPatcher.playerDataLocal.grabbingReservedItem != (Object)(object)__instance;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SetSpecialGrabAnimationBool")]
		[HarmonyPrefix]
		public static bool PreventSpecialGrabAnimationReservedItem(bool setTrue, PlayerControllerB __instance, GrabbableObject currentItem = null)
		{
			return true;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")]
		[HarmonyPrefix]
		public static void DebugSwitchToItemSlot(int slot, PlayerControllerB __instance)
		{
			if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[__instance];
			if (reservedPlayerData == null)
			{
				Plugin.LogError("PlayerData null for player: " + ((Object)__instance).name);
			}
			else
			{
				if (!reservedPlayerData.IsReservedItemSlot(slot))
				{
					return;
				}
				string text = "";
				reservedPlayerData = PlayerPatcher.allPlayerData[__instance];
				if (slot < 0)
				{
					text = "Called SwitchToItemSlot on slot: " + slot;
				}
				else if (slot >= __instance.ItemSlots.Length)
				{
					text = "Called SwitchToItemSlot on slot: " + slot + " HotbarSize: " + __instance.ItemSlots.Length;
				}
				else
				{
					if (slot < HUDManager.Instance.itemSlotIconFrames.Length)
					{
						return;
					}
					text = "Called SwitchToItemSlot on slot: " + slot + " NumItemSlotsHUD: " + HUDManager.Instance.itemSlotIconFrames.Length;
				}
				text += "\n\n";
				text = text + reservedPlayerData.DumpData() + "\n\nReporting this error to Flip would be greatly appreciated!";
				Debug.LogError((object)text);
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")]
		[HarmonyPostfix]
		public static void UpdateFocusReservedHotbar(int slot, PlayerControllerB __instance)
		{
			if (HUDPatcher.hasReservedItemSlotsAndEnabled && PlayerPatcher.allPlayerData.TryGetValue(__instance, out var value))
			{
				value.inReservedHotbarSlots = value.IsReservedItemSlot(__instance.currentItemSlot);
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "FirstEmptyItemSlot")]
		[HarmonyPostfix]
		public static void GetReservedItemSlotPlacementIndex(ref int __result, PlayerControllerB __instance)
		{
			if (reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[__instance];
			ReservedItemInfo grabbingReservedItemInfo = reservedPlayerData.grabbingReservedItemInfo;
			if (grabbingReservedItemInfo != null)
			{
				if (IsItemSlotEmpty(grabbingReservedItemInfo, __instance))
				{
					__result = reservedPlayerData.reservedHotbarStartIndex + grabbingReservedItemInfo.reservedItemIndex;
					return;
				}
				reservedPlayerData.grabbingReservedItemInfo = null;
				reservedPlayerData.grabbingReservedItem = null;
				reservedPlayerData.previousHotbarIndex = -1;
			}
			if (!reservedPlayerData.IsReservedItemSlot(__result))
			{
				return;
			}
			__result = -1;
			for (int i = 0; i < __instance.ItemSlots.Length; i++)
			{
				if (!reservedPlayerData.IsReservedItemSlot(i) && (Object)(object)__instance.ItemSlots[i] == (Object)null)
				{
					__result = i;
					break;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")]
		[HarmonyPostfix]
		public static void OnNextItemSlot(ref int __result, bool forward, PlayerControllerB __instance)
		{
			if (reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[__instance];
			bool flag = reservedPlayerData.IsReservedItemSlot(__result);
			if (flag == reservedPlayerData.inReservedHotbarSlots && (!flag || (Object)(object)__instance.ItemSlots[__result] != (Object)null))
			{
				return;
			}
			int num = (forward ? 1 : (-1));
			__result = __instance.currentItemSlot + num;
			__result = ((__result < 0) ? (__instance.ItemSlots.Length - 1) : ((__result < __instance.ItemSlots.Length) ? __result : 0));
			bool flag2 = reservedPlayerData.IsReservedItemSlot(__result);
			if (!reservedPlayerData.inReservedHotbarSlots)
			{
				if (flag2)
				{
					__result = (forward ? ((reservedPlayerData.reservedHotbarStartIndex + reservedHotbarSize) % __instance.ItemSlots.Length) : (reservedPlayerData.reservedHotbarStartIndex - 1));
				}
				return;
			}
			__result = (flag2 ? __result : (forward ? reservedPlayerData.reservedHotbarStartIndex : (reservedPlayerData.reservedHotbarStartIndex + reservedHotbarSize - 1)));
			int numHeldReservedItems = reservedPlayerData.GetNumHeldReservedItems();
			while (numHeldReservedItems > 0 && __result != reservedPlayerData.currentItemSlot && (Object)(object)__instance.ItemSlots[__result] == (Object)null)
			{
				__result += num;
				__result = ((!reservedPlayerData.IsReservedItemSlot(__result)) ? (forward ? reservedPlayerData.reservedHotbarStartIndex : (reservedPlayerData.reservedHotbarStartIndex + reservedHotbarSize - 1)) : __result);
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPrefix]
		public static void RefocusReservedHotbarAfterAnimation(PlayerControllerB __instance)
		{
			if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !ConfigSettings.toggleFocusReservedHotbar.Value && Keybinds.holdingModifierKey != PlayerPatcher.playerDataLocal.currentItemSlotIsReserved && CanSwapToReservedHotbarSlot())
			{
				FocusReservedHotbarSlots(Keybinds.holdingModifierKey);
			}
		}

		public static bool CanSwapToReservedHotbarSlot()
		{
			if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
			{
				return false;
			}
			bool flag = (bool)Traverse.Create((object)localPlayerController).Field("throwingObject").GetValue();
			return !(PlayerPatcher.playerDataLocal.grabbingReservedItemInfo != null || localPlayerController.isGrabbingObjectAnimation || localPlayerController.quickMenuManager.isMenuOpen || localPlayerController.inSpecialInteractAnimation || flag) && !localPlayerController.isTypingChat && !localPlayerController.twoHanded && !localPlayerController.activatingItem && !localPlayerController.jetpackControls && !localPlayerController.disablingJetpackControls && !localPlayerController.inTerminalMenu && !localPlayerController.isPlayerDead && !(GetTimeSinceSwitchingSlots(localPlayerController) < 0.3f);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "UpdateSpecialAnimationValue")]
		[HarmonyPostfix]
		public static void OnSpecialAnimationUpdate(bool specialAnimation, PlayerControllerB __instance)
		{
			if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !specialAnimation && !ConfigSettings.toggleFocusReservedHotbar.Value && PlayerPatcher.playerDataLocal.currentItemSlotIsReserved != Keybinds.holdingModifierKey)
			{
				FocusReservedHotbarSlots(Keybinds.holdingModifierKey);
			}
		}

		public static void FocusReservedHotbarSlots(bool active)
		{
			if (!HUDPatcher.hasReservedItemSlotsAndEnabled || (reservedHotbarSize <= 0 && active) || PlayerPatcher.playerDataLocal.currentItemSlotIsReserved == active)
			{
				return;
			}
			ReservedPlayerData playerDataLocal = PlayerPatcher.playerDataLocal;
			indexInHotbar = Mathf.Clamp(indexInHotbar, 0, localPlayerController.ItemSlots.Length - 1);
			indexInHotbar = ((!playerDataLocal.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0);
			indexInReservedHotbar = Mathf.Clamp(indexInReservedHotbar, playerDataLocal.reservedHotbarStartIndex, playerDataLocal.reservedHotbarEndIndexExcluded - 1);
			int num = Mathf.Clamp(localPlayerController.currentItemSlot, 0, localPlayerController.ItemSlots.Length);
			int i = num;
			bool flag = active;
			if (flag && !playerDataLocal.IsReservedItemSlot(num))
			{
				indexInHotbar = num;
				indexInHotbar = ((!playerDataLocal.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0);
				i = indexInReservedHotbar;
				if ((Object)(object)localPlayerController.ItemSlots[i] == (Object)null && playerDataLocal.GetNumHeldReservedItems() > 0)
				{
					for (i = playerDataLocal.reservedHotbarStartIndex; i < playerDataLocal.reservedHotbarEndIndexExcluded && !((Object)(object)localPlayerController.ItemSlots[i] != (Object)null); i++)
					{
					}
				}
				Plugin.Log("Focusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + PlayerPatcher.playerDataLocal.reservedHotbarStartIndex);
			}
			else if (!flag && PlayerPatcher.playerDataLocal.IsReservedItemSlot(num))
			{
				indexInReservedHotbar = Mathf.Clamp(num, playerDataLocal.reservedHotbarStartIndex, playerDataLocal.reservedHotbarEndIndexExcluded - 1);
				i = indexInHotbar;
				Plugin.Log("Unfocusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + PlayerPatcher.playerDataLocal.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);
			}
		}

		internal static bool IsItemSlotEmpty(string itemName, PlayerControllerB playerController)
		{
			if (!SyncManager.TryGetReservedItemInfo(itemName, out var info))
			{
				return false;
			}
			return IsItemSlotEmpty(info, playerController);
		}

		internal static bool IsItemSlotEmpty(ReservedItemInfo itemInfo, PlayerControllerB playerController)
		{
			playerController = (((Object)(object)playerController == (Object)null) ? localPlayerController : playerController);
			if (reservedHotbarSize == 0)
			{
				return false;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[playerController];
			int num = reservedPlayerData.reservedHotbarStartIndex + itemInfo.reservedItemIndex;
			return num >= reservedPlayerData.reservedHotbarStartIndex && num < reservedPlayerData.reservedHotbarStartIndex + reservedHotbarSize && (Object)(object)playerController.ItemSlots[num] == (Object)null;
		}

		public static bool TryGetHeldReservedObject(string itemName, PlayerControllerB playerController, ref GrabbableObject obj)
		{
			playerController = (((Object)(object)playerController == (Object)null) ? localPlayerController : playerController);
			if ((Object)(object)playerController == (Object)null || reservedHotbarSize == 0)
			{
				return false;
			}
			if (!SyncManager.TryGetReservedItemInfo(itemName, out var info))
			{
				return false;
			}
			ReservedPlayerData reservedPlayerData = PlayerPatcher.allPlayerData[playerController];
			int num = reservedPlayerData.reservedHotbarStartIndex + info.reservedItemIndex;
			obj = playerController.ItemSlots[num];
			return (Object)(object)obj != (Object)null;
		}

		public static void ForceDisableItemMesh(GrabbableObject grabbableObject)
		{
			MeshRenderer[] componentsInChildren = ((Component)grabbableObject).GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val in componentsInChildren)
			{
				if (!((Object)val).name.Contains("ScanNode") && !((Component)val).gameObject.CompareTag("DoNotSet") && !((Component)val).gameObject.CompareTag("InteractTrigger"))
				{
					((Renderer)val).enabled = false;
				}
			}
		}

		public static bool ReservedItemIsBeingGrabbed(GrabbableObject grabbableObject)
		{
			if ((Object)(object)grabbableObject == (Object)null)
			{
				return false;
			}
			foreach (ReservedPlayerData value in PlayerPatcher.allPlayerData.Values)
			{
				if ((Object)(object)grabbableObject == (Object)(object)value.grabbingReservedItem)
				{
					return true;
				}
			}
			return false;
		}

		public static float GetTimeSinceSwitchingSlots(PlayerControllerB playerController)
		{
			return (float)Traverse.Create((object)playerController).Field("timeSinceSwitchingSlots").GetValue();
		}

		public static void SetTimeSinceSwitchingSlots(PlayerControllerB playerController, float value)
		{
			Traverse.Create((object)playerController).Field("timeSinceSwitchingSlots").SetValue((object)value);
		}

		public static void SetSpecialGrabAnimationBool(PlayerControllerB playerController, bool setTrue, GrabbableObject currentItem = null)
		{
			MethodInfo method = ((object)playerController).GetType().GetMethod("SetSpecialGrabAnimationBool", BindingFlags.Instance | BindingFlags.NonPublic);
			method.Invoke(playerController, new object[2] { setTrue, currentItem });
		}

		public static void SwitchToItemSlot(PlayerControllerB playerController, int slot, GrabbableObject fillSlotWithItem = null)
		{
			MethodInfo method = ((object)playerController).GetType().GetMethod("SwitchToItemSlot", BindingFlags.Instance | BindingFlags.NonPublic);
			method.Invoke(playerController, new object[2] { slot, fillSlotWithItem });
			SetTimeSinceSwitchingSlots(playerController, 0f);
		}
	}
	[HarmonyPatch]
	public static class PlayerPatcher
	{
		public static PlayerControllerB localPlayerController;

		public static int vanillaHotbarSize = -1;

		public static int hotbarSizeBeforeSync = -1;

		internal static Dictionary<PlayerControllerB, ReservedPlayerData> allPlayerData = new Dictionary<PlayerControllerB, ReservedPlayerData>();

		public static bool spawned = false;

		public static bool isSynced = false;

		public static int INTERACTABLE_OBJECT_MASK { get; private set; }

		public static int reservedHotbarSize => SyncManager.numReservedItemSlots;

		internal static ReservedPlayerData playerDataLocal => (allPlayerData != null && (Object)(object)localPlayerController != (Object)null && allPlayerData.ContainsKey(localPlayerController)) ? allPlayerData[localPlayerController] : null;

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPrefix]
		public static void InitSession(StartOfRound __instance)
		{
			localPlayerController = null;
			vanillaHotbarSize = -1;
			ReservedItemPatcher.indexInHotbar = 0;
			ReservedItemPatcher.indexInReservedHotbar = -1;
			Keybinds.holdingModifierKey = false;
			allPlayerData.Clear();
			isSynced = false;
			spawned = false;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Awake")]
		[HarmonyPostfix]
		public static void InitializePlayerController(PlayerControllerB __instance)
		{
			if (vanillaHotbarSize == -1)
			{
				vanillaHotbarSize = __instance.ItemSlots.Length;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Start")]
		[HarmonyPostfix]
		public static void InitializePlayerControllerLate(PlayerControllerB __instance)
		{
			allPlayerData.Add(__instance, new ReservedPlayerData
			{
				playerController = __instance,
				hotbarSize = __instance.ItemSlots.Length,
				reservedHotbarStartIndex = __instance.ItemSlots.Length
			});
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		public static void OnLocalPlayerConnect(PlayerControllerB __instance)
		{
			localPlayerController = __instance;
			INTERACTABLE_OBJECT_MASK = (int)Traverse.Create((object)__instance).Field("interactableObjectsMask").GetValue();
			((MonoBehaviour)__instance).StartCoroutine(UpdateHotbarSlotsAfterFirstSpawnAnimation());
		}

		private static IEnumerator UpdateHotbarSlotsAfterFirstSpawnAnimation()
		{
			yield return (object)new WaitForSeconds(3f);
			spawned = true;
			hotbarSizeBeforeSync = localPlayerController.ItemSlots.Length;
			if (!isSynced && (SyncManager.isSynced || SyncManager.canUseModDisabledOnHost))
			{
				OnSyncedWithServer();
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPostfix]
		public static void OnUpdate(PlayerControllerB __instance)
		{
			if (!spawned)
			{
				return;
			}
			if (SyncManager.isSynced && !isSynced)
			{
				OnSyncedWithServer();
			}
			ReservedPlayerData reservedPlayerData = allPlayerData[__instance];
			if ((!isSynced && (!SyncManager.canUseModDisabledOnHost || (Object)(object)__instance != (Object)(object)localPlayerController)) || reservedHotbarSize <= 0 || reservedPlayerData.hotbarSize == __instance.ItemSlots.Length)
			{
				return;
			}
			Plugin.Log("On update inventory size for player: " + ((Object)__instance).name + " - Old hotbar size: " + reservedPlayerData.hotbarSize + " - New hotbar size: " + __instance.ItemSlots.Length);
			reservedPlayerData.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 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 player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
							break;
						}
					}
				}
			}
			if (num == -1)
			{
				num = reservedPlayerData.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);
			}
			reservedPlayerData.reservedHotbarStartIndex = num;
			if (reservedPlayerData.reservedHotbarStartIndex < 0)
			{
				Plugin.LogError("Set new reserved start index to slot: " + reservedPlayerData.reservedHotbarStartIndex + " . Maybe share these logs with Flip? :)");
			}
			if (reservedPlayerData.reservedHotbarEndIndexExcluded - 1 >= reservedPlayerData.playerController.ItemSlots.Length)
			{
				Plugin.LogError("Set new reserved start index to slot: " + reservedPlayerData.reservedHotbarStartIndex + " Last reserved slot index: " + (reservedPlayerData.reservedHotbarEndIndexExcluded - 1) + " Inventory size: " + reservedPlayerData.playerController.ItemSlots.Length + ". Maybe share these logs with Flip? :)");
			}
			if ((Object)(object)__instance == (Object)(object)localPlayerController)
			{
				HUDPatcher.UpdateHUD();
			}
		}

		private static void OnSyncedWithServer()
		{
			isSynced = SyncManager.isSynced;
			int num = hotbarSizeBeforeSync + reservedHotbarSize;
			Plugin.Log("Finalizing sync with server. New hotbar size: " + num);
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				allPlayerData[val].reservedHotbarStartIndex = hotbarSizeBeforeSync;
				if (num != val.ItemSlots.Length)
				{
					Array.Resize(ref val.ItemSlots, num);
				}
				allPlayerData[val].hotbarSize = num;
			}
			if (HUDPatcher.reservedItemSlots != null && HUDPatcher.reservedItemSlots.Count == SyncManager.numReservedItemSlots && playerDataLocal.reservedHotbarStartIndex < HUDManager.Instance.itemSlotIconFrames.Length && (Object)(object)HUDPatcher.reservedItemSlots[0] == (Object)(object)HUDManager.Instance.itemSlotIconFrames[playerDataLocal.reservedHotbarStartIndex])
			{
				return;
			}
			if (HUDPatcher.reservedItemSlots != null && HUDPatcher.reservedItemSlots.Count > 0)
			{
				List<Image> list = new List<Image>(HUDManager.Instance.itemSlotIconFrames);
				List<Image> list2 = new List<Image>(HUDManager.Instance.itemSlotIcons);
				for (int j = 0; j < HUDManager.Instance.itemSlotIconFrames.Length; j++)
				{
					Image val2 = HUDManager.Instance.itemSlotIconFrames[j];
					Image item = HUDManager.Instance.itemSlotIcons[j];
					if (((Object)val2).name.Contains("Reserved"))
					{
						list.Remove(val2);
						list2.Remove(item);
					}
				}
				HUDManager.Instance.itemSlotIconFrames = list.ToArray();
				HUDManager.Instance.itemSlotIcons = list2.ToArray();
			}
			HUDPatcher.AddNewHotbarSlotsHud();
		}
	}
}
namespace ReservedItemSlotCore.Compatibility
{
	public class AdvancedCompanyPatcher
	{
		public static bool Enabled => Plugin.IsModLoaded("com.potatoepet.AdvancedCompany");
	}
}