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 LCVR.Managers; using LethalCompanyInputUtils.Api; 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.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("ReservedUtilitySlot")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace ReservedItemSlotCore { [HarmonyPatch] internal static class ItemNameMap { private static Dictionary originalNameToItemMap = new Dictionary(); private static Dictionary itemToNameMap = new Dictionary(); [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPrefix] private static void RecordOriginalItemNames(StartOfRound __instance) { List 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); return (itemName != null) ? 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 ""; } } [BepInPlugin("FlipMods.ReservedItemSlotCore", "ReservedItemSlotCore", "2.0.55")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin instance; private static ManualLogSource logger; public static List customItemSlots = new List(); private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown instance = this; CreateCustomLogger(); ConfigSettings.BindConfigSettings(); AddCustomItemSlots(); if (InputUtilsCompat.Enabled) { InputUtilsCompat.Init(); } _harmony = new Harmony("ReservedItemSlotCore"); PatchAll(); Log("ReservedItemSlotCore loaded"); } private void AddCustomItemSlots() { //IL_0073: 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_007d: 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) 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; foreach (string itemName in customItemSlotItems) { ReservedItemData itemData = new ReservedItemData(itemName); reservedItemSlotData.AddItemToReservedItemSlot(itemData); } customItemSlots.Add(reservedItemSlotData); } } } private void PatchAll() { IEnumerable 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.55")); } 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.55"; } [HarmonyPatch] public static class ReservedHotbarManager { public static int indexInHotbar = 0; public static int indexInReservedHotbar = 0; internal static List currentlyToggledItemSlots = new List(); 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(); return (ReservedPlayerData.localPlayerData.inReservedHotbarSlots && Keybinds.pressedToggleKey) || (currentlyToggledItemSlots != null && currentlySelectedReservedItemSlot != null && currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot)); } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] public static void InitSession(StartOfRound __instance) { currentlyToggledItemSlots = new List(); 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(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 (!LCVR_Compat.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; } return 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 && !(localPlayerData.timeSinceSwitchingSlots < 0.3f); } 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(); if ((Object)(object)component != (Object)null) { component.ignoreParentGroups = true; } } } 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(); 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 unlockedReservedItemSlots = new List(); internal static Dictionary unlockedReservedItemSlotsDict = new Dictionary(); internal static List pendingUnlockedReservedItemSlots = new List(); internal static Dictionary pendingUnlockedReservedItemSlotsDict = new Dictionary(); private static Dictionary allReservedItemData = new Dictionary(); internal static bool gameStarted = false; internal static List allUnlockableReservedItemSlots => SyncManager.unlockableReservedItemSlots; internal static Dictionary allUnlockableReservedItemSlotsDict => SyncManager.unlockableReservedItemSlotsDict; public static int numReservedItemSlotsUnlocked => (unlockedReservedItemSlots != null) ? unlockedReservedItemSlots.Count : 0; [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++) { ReservedItemSlotData reservedItemSlotData = 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 list = new List(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) { return (unlockedReservedItemSlots != null && indexInUnlockedItemSlots >= 0 && indexInUnlockedItemSlots < unlockedReservedItemSlots.Count) ? unlockedReservedItemSlots[indexInUnlockedItemSlots] : null; } public static ReservedItemSlotData GetUnlockedReservedItemSlot(string itemSlotName) { if (TryGetUnlockedItemSlotData(itemSlotName, out var itemSlotData)) { return itemSlotData; } return null; } public static bool IsItemSlotUnlocked(ReservedItemSlotData itemSlotData) { return itemSlotData != null && 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 list = new List(); 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 list2 = new List(); List list3 = new List(); 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); } } if (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.<g__Reset|0>d))] IEnumerator Reset() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass25_0.<g__Reset|0>d(0) { <>4__this = CS$<>8__locals0 }; } } internal static void SaveGameValues() { if (!NetworkManager.Singleton.IsServer || unlockedReservedItemSlots == null) { return; } List list = new List(); 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("ReservedItemSlots.UnlockedItemSlots", array, GameNetworkManager.Instance.currentSaveFileName); } internal static void LoadGameValues() { if (!NetworkManager.Singleton.IsServer || SyncManager.unlockableReservedItemSlotsDict == null) { return; } string[] array = ES3.Load("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) { string itemName = ItemNameMap.GetItemName(grabbableObject); return IsReservedItem(itemName) || ((Object)(object)grabbableObject?.itemProperties != (Object)null && IsReservedItem(grabbableObject.itemProperties.itemName)); } 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; string itemName = ItemNameMap.GetItemName(item); return TryGetUnlockedItemData(itemName, out itemData) || ((Object)(object)item?.itemProperties != (Object)null && TryGetUnlockedItemData(item.itemProperties.itemName, out itemData)); } 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__DisplayClass9_0 { public PlayerControllerB playerController; public float time; internal bool b__0() { return (Object)(object)playerController.currentlyHeldObjectServer == (Object)null || Time.time - time >= 5f; } } [CompilerGenerated] private sealed class d__9 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PlayerControllerB playerController; public int slot; private <>c__DisplayClass9_0 <>8__1; private ReservedPlayerData 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass9_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)(() => (Object)(object)<>8__1.playerController.currentlyHeldObjectServer == (Object)null || Time.time - <>8__1.time >= 5f)); <>1__state = 1; return true; } goto IL_009f; case 1: <>1__state = -1; goto IL_009f; 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 5__2)) { 5__2.CallSwitchToItemSlot(slot); } return false; } IL_009f: <>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 playersDiscardingItems = new HashSet(); private static float timeLoggedPreventedScroll = 0f; private static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; [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) { ReservedPlayerData localPlayerData = ReservedPlayerData.localPlayerData; if (localPlayerData == null) { return; } if (SessionManager.unlockedReservedItemSlots == null) { Plugin.LogErrorVerbose("[OnItemDestroy] Unlocked reserved item slots no initialized? You might want to let Flip know :) (This may be caused from another mod, or a new update)"); } else if (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; } 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(d__9))] private static IEnumerator SwitchToItemSlotAfterDelay(PlayerControllerB playerController, int slot) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(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 reservedItemSlots = new List(); public static HashSet toggledReservedItemSlots = new HashSet(); private static bool lerpToggledItemSlotFrames = false; private static float largestPositionDifference = 0f; private static bool currentApplyHotbarPlusSize; private static bool currentHideEmptySlots; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData; public static bool localPlayerUsingController => (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.localPlayerUsingController; private static float currentItemSlotScale => itemSlotWidth / defaultItemSlotSize.x; 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00b7: Unknown result type (might be due to invalid IL or missing references) CanvasScaler componentInParent = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent(); AspectRatioFitter componentInParent2 = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent(); 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(); } [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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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); 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) if (reservedItemSlots == null || SessionManager.numReservedItemSlotsUnlocked <= 0 || reservedItemSlots.Count == SessionManager.numReservedItemSlotsUnlocked) { return; } List list = new List(HUDManager.Instance.itemSlotIconFrames); List list2 = new List(HUDManager.Instance.itemSlotIcons); for (int i = reservedItemSlots.Count; i < SessionManager.numReservedItemSlotsUnlocked; i++) { GameObject val = Object.Instantiate(((Component)list[0]).gameObject, ((Component)list[0]).transform.parent); Image component = val.GetComponent(); Image component2 = ((Component)((Component)component).transform.GetChild(0)).GetComponent(); ((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 val2 = ((Component)component).gameObject.AddComponent(); val2.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value; val2.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; } int index = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + reservedItemSlots.Count; list.Insert(index, component); list2.Insert(index, component2); reservedItemSlots.Add(component); } HUDManager.Instance.itemSlotIconFrames = list.ToArray(); HUDManager.Instance.itemSlotIcons = list2.ToArray(); UpdateUI(); } public static void UpdateUI() { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_00fe: 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_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_0401: 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_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_044f: 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_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_030f: 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; } int num = 0; int num2 = 0; RectTransform val = null; Vector2 anchoredPosition = default(Vector2); for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++) { ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i); int num3 = Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, reservedItemSlots[i]); Image val2 = HUDManager.Instance.itemSlotIconFrames[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i]; Image val3 = HUDManager.Instance.itemSlotIcons[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i]; ((Graphic)val2).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIconFrames[0]).rectTransform.sizeDelta; ((Graphic)val3).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIcons[0]).rectTransform.sizeDelta; if (HotbarPlus_Compat.Enabled && !ConfigSettings.applyHotbarPlusItemSlotSize.Value) { ((Graphic)val2).rectTransform.sizeDelta = defaultItemSlotSize; ((Graphic)val3).rectTransform.sizeDelta = defaultItemIconSize; } itemSlotWidth = ((Graphic)val2).rectTransform.sizeDelta.x; itemSlotSpacing = defaultItemSlotSpacing * currentItemSlotScale; 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 || LCVR_Compat.Loaded) { 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 || LCVR_Compat.Loaded) { num2++; } else { anchoredPosition.y = -1000f; } } ((Graphic)val2).rectTransform.anchoredPosition = anchoredPosition; if ((Object)(object)reservedItem != (Object)null) { ((Behaviour)val3).enabled = true; val3.sprite = reservedItem.itemProperties.itemIcon; } else { ((Behaviour)val3).enabled = false; val3.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(); } RectTransform rectTransform = ((TMP_Text)hotkeyTooltip).rectTransform; ((Transform)rectTransform).SetParent((Transform)(object)val); if (Object.op_Implicit((Object)(object)val)) { ((Transform)rectTransform).localScale = Vector3.one; rectTransform.sizeDelta = new Vector2(val.sizeDelta.x * 2f, 10f); rectTransform.pivot = Vector2.one / 2f; rectTransform.anchoredPosition3D = new Vector3(0f, 0f - rectTransform.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)rectTransform).localScale = Vector3.zero; } } currentApplyHotbarPlusSize = ConfigSettings.applyHotbarPlusItemSlotSize.Value; currentHideEmptySlots = ConfigSettings.hideEmptyReservedItemSlots.Value; } public static void UpdateHotkeyTooltipText() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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) //IL_0070: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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 (LCVR_Compat.LoadedAndEnabled) { 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(ReservedHotbarManager.currentlyToggledItemSlots); } else { toggledReservedItemSlots.Clear(); } lerpToggledItemSlotFrames = true; largestPositionDifference = -1f; } private static float GetCurrentItemSlotSpacing() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: 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; } ReservedItemSlotData reservedItemSlotData = SessionManager.unlockedReservedItemSlots[num]; ReservedItemData reservedItemData = reservedItemSlotData.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(((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(); 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(); foreach (Light val4 in componentsInChildren2) { ((Behaviour)val4).enabled = false; } } else { Light[] componentsInChildren3 = val2.GetComponentsInChildren(); foreach (Light val5 in componentsInChildren3) { ((Behaviour)val5).enabled = true; } } GrabbableObject componentInChildren = val2.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.playerHeldBy = null; FlashlightItem val6 = (FlashlightItem)(object)((componentInChildren is FlashlightItem) ? componentInChildren : null); if ((Object)(object)val6 != (Object)null) { ((Behaviour)val6.flashlightBulb).enabled = true; ((Behaviour)val6.flashlightBulbGlow).enabled = true; if (((Renderer)val6.flashlightMesh).sharedMaterials.Length > 1 && (Object)(object)val6.bulbLight != (Object)null) { ((Renderer)val6.flashlightMesh).sharedMaterials[1] = val6.bulbLight; } } ReservedItemsPatcher.ForceEnableItemMesh(componentInChildren, enabled: true); componentInChildren.EnablePhysics(false); } Object.DestroyImmediate((Object)(object)val2.GetComponentInChildren()); Collider[] componentsInChildren4 = val2.GetComponentsInChildren(); foreach (Collider val7 in componentsInChildren4) { Object.DestroyImmediate((Object)(object)val7); } MonoBehaviour[] componentsInChildren5 = val2.GetComponentsInChildren(); foreach (MonoBehaviour val8 in componentsInChildren5) { Object.DestroyImmediate((Object)(object)val8); } } } } [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() > 0f; } } [HarmonyPatch(typeof(PlayerControllerB), "SwitchItemSlotsServerRpc")] [HarmonyPrefix] public static void CorrectReservedScrollDirectionServerRpc(ref bool forward) { if (Keybinds.scrollingReservedHotbar) { forward = Keybinds.RawScrollAction.ReadValue() > 0f; } } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool PreventInvertedScrollingReservedHotbar(CallbackContext context) { if (LCVR_Compat.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] public static class PlayerPatcher { [CompilerGenerated] private sealed class <>c__DisplayClass20_0 { public GrabbableObject __instance; } private static int INTERACTABLE_OBJECT_MASK = 0; public static int vanillaHotbarSize = 4; private static bool initialized = false; private static bool GrabObjectClientRpcFlag = false; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static Dictionary allPlayerData => ReservedPlayerData.allPlayerData; public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData; public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked; [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] private static void InitSession(StartOfRound __instance) { initialized = false; vanillaHotbarSize = 4; ReservedPlayerData.allPlayerData?.Clear(); } [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 + ". Maybe share these logs with Flip? :)"); } 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 + ". Maybe share these logs with Flip? :)"); } if (value.isLocalPlayer) { HUDPatcher.UpdateUI(); } } [HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")] [HarmonyPrefix] private static bool BeginGrabReservedItemPrefix(PlayerControllerB __instance) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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) 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; } 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, 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(); if ((Object)(object)component != (Object)null && !__instance.inSpecialInteractAnimation && !component.isHeld && !component.isPocketed) { NetworkObject networkObject = ((NetworkBehaviour)component).NetworkObject; if (Object.op_Implicit((Object)(object)component) && component.itemProperties.twoHanded) { return true; } if ((Object)(object)networkObject != (Object)null && networkObject.IsSpawned && SessionManager.TryGetUnlockedItemData(component, out var itemData)) { localPlayerData.grabbingReservedItemData = itemData; localPlayerData.grabbingReservedItem = component; localPlayerData.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1); Plugin.Log("Beginning grab on reserved item: " + itemData.itemName + " Previous item 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)) { SetSpecialGrabAnimationBool(__instance, setTrue: false); SetSpecialGrabAnimationBool(__instance, (Object)(object)localPlayerData.previouslyHeldItem != (Object)null, localPlayerData.previouslyHeldItem); __instance.playerBodyAnimator.SetBool("GrabValidated", true); __instance.playerBodyAnimator.SetBool("GrabInvalidated", false); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation"); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded"); if ((Object)(object)localPlayerData.previouslyHeldItem != (Object)null) { __instance.playerBodyAnimator.ResetTrigger(localPlayerData.previouslyHeldItem.itemProperties.pocketAnim); } __instance.twoHanded = (Object)(object)localPlayerData.previouslyHeldItem != (Object)null && localPlayerData.previouslyHeldItem.itemProperties.twoHanded; __instance.twoHandedAnimation = (Object)(object)localPlayerData.previouslyHeldItem != (Object)null && localPlayerData.previouslyHeldItem.itemProperties.twoHandedAnimation; } } [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")] [HarmonyPrefix] private static void GrabReservedItemClientRpcPrefix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance) { if (!NetworkHelper.IsServerExecStage((NetworkBehaviour)(object)__instance) || (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsHost)) { return; } GrabObjectClientRpcFlag = true; if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !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(ref val2) && 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; } } 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 (!GrabObjectClientRpcFlag) { return; } GrabObjectClientRpcFlag = false; if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !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(ref val2)) { if (SessionManager.TryGetUnlockedItemData(val2, out var itemData)) { if (!value.IsReservedItemSlot(value.previousHotbarIndex)) { 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().SetBool("selectedSlot", false); ((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent().SetBool("selectedSlot", true); ((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent().Play("PanelLines", 0, 1f); ((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent().Play("PanelEnlarge", 0, 1f); } else { SwitchToItemSlot(__instance, value.previousHotbarIndex); if (itemData.showOnPlayerWhileHolstered) { val2.EnableItemMeshes(true); } } SetSpecialGrabAnimationBool(__instance, setTrue: false); SetSpecialGrabAnimationBool(__instance, (Object)(object)value.previouslyHeldItem != (Object)null, value.previouslyHeldItem); __instance.playerBodyAnimator.SetBool("GrabValidated", true); __instance.playerBodyAnimator.SetBool("GrabInvalidated", false); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation"); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded"); if ((Object)(object)value.previouslyHeldItem != (Object)null) { __instance.playerBodyAnimator.ResetTrigger(value.previouslyHeldItem.itemProperties.pocketAnim); } __instance.twoHanded = (Object)(object)value.previouslyHeldItem != (Object)null && value.previouslyHeldItem.itemProperties.twoHanded; __instance.twoHandedAnimation = (Object)(object)value.previouslyHeldItem != (Object)null && value.previouslyHeldItem.itemProperties.twoHandedAnimation; } if (value.isLocalPlayer) { HUDPatcher.UpdateUI(); return; } value.grabbingReservedItemSlotData = null; value.grabbingReservedItemData = null; value.grabbingReservedItem = null; value.previousHotbarIndex = -1; return; } } else if (value.isLocalPlayer) { Plugin.LogWarning("Failed to validate ReservedItemGrab by the local player. Object id: " + ((NetworkObjectReference)(ref grabbedObject)).NetworkObjectId + ". Internal error?"); Traverse.Create((object)localPlayerController).Field("grabInvalidated").SetValue((object)true); } else { Plugin.LogWarning("Failed to validate ReservedItemGrab by player with id: " + ((Object)__instance).name + ". Object id: " + ((NetworkObjectReference)(ref grabbedObject)).NetworkObjectId + ". Internal error?"); } } value.grabbingReservedItemSlotData = null; value.grabbingReservedItemData = null; value.grabbingReservedItem = null; value.previousHotbarIndex = -1; } [HarmonyPatch(typeof(GrabbableObject), "GrabItemOnClient")] [HarmonyPrefix] private static void OnReservedItemGrabbed(GrabbableObject __instance) { <>c__DisplayClass20_0 CS$<>8__locals0 = new <>c__DisplayClass20_0(); CS$<>8__locals0.__instance = __instance; if (localPlayerData.grabbingReservedItemData != null && (Object)(object)CS$<>8__locals0.__instance == (Object)(object)GetCurrentlyGrabbingObject(localPlayerController)) { ((MonoBehaviour)localPlayerController).StartCoroutine(OnReservedItemGrabbedEndOfFrame()); } [IteratorStateMachine(typeof(<>c__DisplayClass20_0.<g__OnReservedItemGrabbedEndOfFrame|0>d))] IEnumerator OnReservedItemGrabbedEndOfFrame() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass20_0.<g__OnReservedItemGrabbedEndOfFrame|0>d(0) { <>4__this = CS$<>8__locals0 }; } } [HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")] [HarmonyPrefix] private static void UpdateLastSelectedHotbarIndex(int slot, PlayerControllerB __instance) { if (LCVR_Compat.LoadedAndEnabled && (Object)(object)__instance == (Object)(object)localPlayerController && LCVR_Compat.vrPlayerScrollingBetweenHotbars) { return; } int currentItemSlot = __instance.currentItemSlot; if (ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value)) { if (value.IsReservedItemSlot(currentItemSlot)) { ReservedHotbarManager.indexInReservedHotbar = currentItemSlot; } else { ReservedHotbarManager.indexInHotbar = currentItemSlot; } } } [HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")] [HarmonyPostfix] private static void UpdateFocusReservedHotbar(int slot, PlayerControllerB __instance) { if ((!LCVR_Compat.LoadedAndEnabled || !((Object)(object)__instance == (Object)(object)localPlayerController) || !LCVR_Compat.vrPlayerScrollingBetweenHotbars) && HUDPatcher.hasReservedItemSlotsAndEnabled && ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value)) { bool inReservedHotbarSlots = value.inReservedHotbarSlots; value.inReservedHotbarSlots = value.IsReservedItemSlot(__instance.currentItemSlot); bool flag = false; if (inReservedHotbarSlots != value.inReservedHotbarSlots || (value.inReservedHotbarSlots && ReservedHotbarManager.isToggledInReservedSlots && ReservedHotbarManager.currentlyToggledItemSlots != null && !ReservedHotbarManager.currentlyToggledItemSlots.Contains(value.GetCurrentlySelectedReservedItemSlot()))) { flag = true; } if (value.inReservedHotbarSlots) { ReservedHotbarManager.OnSwapToReservedHotbar(); } else { ReservedHotbarManager.OnSwapToVanillaHotbar(); } if (flag) { HUDPatcher.UpdateToggledReservedItemSlotsUI(); } } } [HarmonyPatch(typeof(PlayerControllerB), "FirstEmptyItemSlot")] [HarmonyPostfix] private static void GetReservedItemSlotPlacementIndex(ref int __result, PlayerControllerB __instance) { if (reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value)) { return; } ReservedItemData grabbingReservedItemData = value.grabbingReservedItemData; if (grabbingReservedItemData != null) { ReservedItemSlotData firstEmptySlotForReservedItem = value.GetFirstEmptySlotForReservedItem(grabbingReservedItemData.itemName); if (firstEmptySlotForReservedItem != null) { __result = firstEmptySlotForReservedItem.GetIndexInInventory(__instance); return; } value.grabbingReservedItemSlotData = null; value.grabbingReservedItemData = null; value.grabbingReservedItem = null; value.previousHotbarIndex = -1; } if (!value.IsReservedItemSlot(__result)) { return; } __result = -1; for (int i = 0; i < __instance.ItemSlots.Length; i++) { if (!value.IsReservedItemSlot(i) && (Object)(object)__instance.ItemSlots[i] == (Object)null) { __result = i; break; } } } [HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")] [HarmonyPostfix] private static void OnNextItemSlot(ref int __result, bool forward, PlayerControllerB __instance) { if (reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || (LCVR_Compat.LoadedAndEnabled && (Object)(object)__instance == (Object)(object)localPlayerController && LCVR_Compat.vrPlayerScrollingBetweenHotbars)) { return; } bool inReservedHotbarSlots = value.inReservedHotbarSlots; bool flag = value.IsReservedItemSlot(__result); bool flag2 = inReservedHotbarSlots; if (inReservedHotbarSlots) { ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(__result - value.reservedHotbarStartIndex); if (ReservedHotbarManager.isToggledInReservedSlots && !Keybinds.pressedToggleKey && !Keybinds.holdingModifierKey && ReservedHotbarManager.currentlyToggledItemSlots != null && (!flag || (Object)(object)value.itemSlots[__result] == (Object)null || !ReservedHotbarManager.currentlyToggledItemSlots.Contains(unlockedReservedItemSlot))) { __result = ReservedHotbarManager.indexInHotbar; return; } } if (flag == flag2 && (!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)); flag = value.IsReservedItemSlot(__result); if (!flag2) { if (flag) { __result = (forward ? ((value.reservedHotbarStartIndex + reservedHotbarSize) % __instance.ItemSlots.Length) : (value.reservedHotbarStartIndex - 1)); } return; } __result = (flag ? __result : (forward ? value.reservedHotbarStartIndex : (value.reservedHotbarStartIndex + reservedHotbarSize - 1))); if (!LCVR_Compat.Loaded) { int numHeldReservedItems = value.GetNumHeldReservedItems(); while (numHeldReservedItems > 0 && __result != value.currentItemSlot && (Object)(object)__instance.ItemSlots[__result] == (Object)null) { __result += num; __result = ((!value.IsReservedItemSlot(__result)) ? (forward ? value.reservedHotbarStartIndex : (value.reservedHotbarStartIndex + reservedHotbarSize - 1)) : __result); } } } [HarmonyPatch(typeof(HUDManager), "ClearControlTips")] [HarmonyPrefix] private static bool PreventClearControlTipsGrabbingReservedItem(HUDManager __instance) { return ReservedPlayerData.localPlayerData == null || (Object)(object)ReservedPlayerData.localPlayerData.grabbingReservedItem == (Object)null; } [HarmonyPatch(typeof(GrabbableObject), "SetControlTipsForItem")] [HarmonyPrefix] private static bool PreventUpdateControlTipsGrabbingReservedItem(GrabbableObject __instance) { return ReservedPlayerData.localPlayerData == null || (Object)(object)ReservedPlayerData.localPlayerData.grabbingReservedItem != (Object)(object)__instance; } 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); } public static bool ReservedItemIsBeingGrabbed(GrabbableObject grabbableObject) { if ((Object)(object)grabbableObject == (Object)null) { return false; } foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values) { if ((Object)(object)grabbableObject == (Object)(object)value.grabbingReservedItem) { return true; } } return false; } 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 }); if (ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value)) { value.timeSinceSwitchingSlots = 0f; } } } [HarmonyPatch] internal static class ReservedItemsPatcher { public static bool ignoreMeshOverride = false; internal static Dictionary previousObjectLayers = new Dictionary(); public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; [HarmonyPatch(typeof(GrabbableObject), "PocketItem")] [HarmonyPostfix] public static void OnPocketReservedItem(GrabbableObject __instance) { if (!ConfigSettings.showReservedItemsHolstered.Value || (Object)(object)__instance.playerHeldBy == (Object)null || !ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) || !SessionManager.TryGetUnlockedItemData(__instance, out var itemData) || !value.IsItemInReservedItemSlot(__instance) || !itemData.showOnPlayerWhileHolstered) { return; } MeshRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(); foreach (MeshRenderer val in componentsInChildren) { if (!previousObjectLayers.TryGetValue(((Component)val).gameObject, out var value2)) { value2 = ((Component)val).gameObject.layer; } if (((Component)val).gameObject.CompareTag("DoNotSet") || ((Component)val).gameObject.CompareTag("InteractTrigger") || !IsLayerInLocalCameraMask(value2)) { continue; } if (!previousObjectLayers.ContainsKey(((Component)val).gameObject)) { previousObjectLayers.Add(((Component)val).gameObject, value2); } if (value.isLocalPlayer && (!TooManyEmotes_Compat.Enabled || !TooManyEmotes_Compat.IsLocalPlayerPerformingCustomEmote())) { if (IsLayerInLocalCameraMask(((Component)val).gameObject.layer)) { ((Component)val).gameObject.layer = 23; } } else if (!IsLayerInLocalCameraMask(((Component)val).gameObject.layer)) { ((Component)val).gameObject.layer = 6; } } __instance.parentObject = value.boneMap.GetBone(itemData.holsteredParentBone); ForceEnableItemMesh(__instance, enabled: true); } [HarmonyPatch(typeof(GrabbableObject), "EquipItem")] [HarmonyPatch(typeof(StunGrenadeItem), "EquipItem")] [HarmonyPostfix] public static void OnEquipReservedItem(GrabbableObject __instance) { if (!ConfigSettings.showReservedItemsHolstered.Value || (Object)(object)__instance.playerHeldBy == (Object)null || !ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) || !SessionManager.TryGetUnlockedItemData(__instance, out var itemData) || !value.IsItemInReservedItemSlot(__instance) || !itemData.showOnPlayerWhileHolstered) { return; } MeshRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(); foreach (MeshRenderer val in componentsInChildren) { if (!((Component)val).gameObject.CompareTag("DoNotSet") && !((Component)val).gameObject.CompareTag("InteractTrigger") && previousObjectLayers.TryGetValue(((Component)val).gameObject, out var value2)) { ((Component)val).gameObject.layer = value2; previousObjectLayers.Remove(((Component)val).gameObject); } } __instance.parentObject = (value.isLocalPlayer ? __instance.playerHeldBy.localItemHolder : __instance.playerHeldBy.serverItemHolder); } [HarmonyPatch(typeof(GrabbableObject), "DiscardItem")] [HarmonyPostfix] public static void ResetReservedItemLayer(GrabbableObject __instance) { if (!SessionManager.TryGetUnlockedItemData(__instance, out var itemData) || !itemData.showOnPlayerWhileHolstered) { return; } MeshRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(); foreach (MeshRenderer val in componentsInChildren) { if (!((Component)val).gameObject.CompareTag("DoNotSet") && !((Component)val).gameObject.CompareTag("InteractTrigger") && previousObjectLayers.TryGetValue(((Component)val).gameObject, out var value)) { ((Component)val).gameObject.layer = value; previousObjectLayers.Remove(((Component)val).gameObject); } } } [HarmonyPatch(typeof(GrabbableObject), "LateUpdate")] [HarmonyPostfix] public static void SetHolsteredPositionRotation(GrabbableObject __instance) { //IL_00ab: 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_00b6: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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) if (ConfigSettings.showReservedItemsHolstered.Value && !((Object)(object)__instance.playerHeldBy == (Object)null) && !((Object)(object)__instance.parentObject == (Object)null) && ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) && SessionManager.TryGetUnlockedItemData(__instance, out var itemData) && value.IsItemInReservedItemSlot(__instance) && itemData.showOnPlayerWhileHolstered && (Object)(object)__instance != (Object)(object)value.currentlySelectedItem) { Transform transform = ((Component)__instance.parentObject).transform; ((Component)__instance).transform.rotation = ((Component)__instance.parentObject).transform.rotation * Quaternion.Euler(itemData.holsteredRotationOffset); ((Component)__instance).transform.position = transform.position + transform.rotation * itemData.holsteredPositionOffset; } } [HarmonyPatch(typeof(GrabbableObject), "EnableItemMeshes")] [HarmonyPrefix] public static void OnEnableItemMeshes(ref bool enable, GrabbableObject __instance) { if (ConfigSettings.showReservedItemsHolstered.Value) { if ((Object)(object)__instance.playerHeldBy != (Object)null && !ignoreMeshOverride && ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) && SessionManager.TryGetUnlockedItemData(__instance, out var itemData) && value.IsItemInReservedItemSlot(__instance) && itemData.showOnPlayerWhileHolstered && (Object)(object)value.currentlySelectedItem != (Object)(object)__instance && !PlayerPatcher.ReservedItemIsBeingGrabbed(__instance)) { enable = true; } ignoreMeshOverride = false; } } public static void ForceEnableItemMesh(GrabbableObject grabbableObject, bool enabled) { ignoreMeshOverride = true; grabbableObject.EnableItemMeshes(enabled); } public static bool IsLayerInLocalCameraMask(int layer) { if (!Object.op_Implicit((Object)(object)localPlayerController) || !Object.op_Implicit((Object)(object)localPlayerController.gameplayCamera)) { return false; } int cullingMask = localPlayerController.gameplayCamera.cullingMask; return (cullingMask & (1 << layer)) != 0; } } [HarmonyPatch] internal static class SyncAlreadyHeldObjectsPatcher { [HarmonyPatch(typeof(StartOfRound), "SyncAlreadyHeldObjectsClientRpc")] [HarmonyPrefix] private static void SyncAlreadyHeldReservedObjectsClientRpc(ref NetworkObjectReference[] gObjects, ref int[] playersHeldBy, ref int[] itemSlotNumbers, ref int[] isObjectPocketed, int syncWithClient, StartOfRound __instance) { if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsListening || !NetworkHelper.IsServerExecStage((NetworkBehaviour)(object)__instance) || (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsHost) || syncWithClient != (int)NetworkManager.Singleton.LocalClientId) { return; } bool flag = false; List list = new List(gObjects); List list2 = new List(playersHeldBy); List list3 = new List(itemSlotNumbers); List list4 = new List(isObjectPocketed); for (int num = itemSlotNumbers.Length - 1; num >= 0; num--) { if (itemSlotNumbers[num] >= __instance.localPlayerController.ItemSlots.Length && itemSlotNumbers[num] != 50) { list.RemoveAt(num); list2.RemoveAt(num); list3.RemoveAt(num); list4.Remove(num); flag = true; } } if (flag) { gObjects = list.ToArray(); playersHeldBy = list2.ToArray(); itemSlotNumbers = list3.ToArray(); isObjectPocketed = list4.ToArray(); } } } [HarmonyPatch] internal static class TerminalPatcher { public static Terminal terminalInstance; public static bool initializedTerminalNodes; public static ReservedItemSlotData purchasingItemSlot; [HarmonyPatch(typeof(Terminal), "Awake")] [HarmonyPrefix] public static void InitializeTerminal(Terminal __instance) { terminalInstance = __instance; initializedTerminalNodes = false; EditExistingTerminalNodes(); } [HarmonyPatch(typeof(Terminal), "BeginUsingTerminal")] [HarmonyPrefix] public static void OnBeginUsingTerminal(Terminal __instance) { if (!initializedTerminalNodes && SyncManager.isSynced) { EditExistingTerminalNodes(); } } public static void EditExistingTerminalNodes() { if (!SyncManager.isSynced) { return; } initializedTerminalNodes = true; if (!SyncManager.enablePurchasingItemSlots) { return; } foreach (TerminalNode specialNode in terminalInstance.terminalNodes.specialNodes) { if (((Object)specialNode).name == "Start" && !specialNode.displayText.Contains("[ReservedItemSlots]")) { string text = "Type \"Help\" for a list of commands."; int num = specialNode.displayText.IndexOf(text); if (num != -1) { num += text.Length; string value = "\n\n[ReservedItemSlots]\nType \"Reserved\" to purchase reserved item slots."; specialNode.displayText = specialNode.displayText.Insert(num, value); } else { Plugin.LogError("Failed to add reserved item slots tip to terminal. Maybe an update broke it?"); } } else if (((Object)specialNode).name == "HelpCommands" && !specialNode.displayText.Contains(">RESERVED")) { string value2 = "[numberOfItemsOnRoute]"; int num2 = specialNode.displayText.IndexOf(value2); if (num2 != -1) { string text2 = ">RESERVED\n"; text2 += "Purchase reserved item slots.\n\n"; specialNode.displayText = specialNode.displayText.Insert(num2, text2); } } } } [HarmonyPatch(typeof(Terminal), "TextPostProcess")] [HarmonyPrefix] public static void TextPostProcess(ref string modifiedDisplayText, TerminalNode node) { if (modifiedDisplayText.Length <= 0) { return; } string text = "[[[reservedItemSlotsSelectionList]]]"; if (!modifiedDisplayText.Contains(text)) { return; } int num = modifiedDisplayText.IndexOf(text); int num2 = num + text.Length; string oldValue = modifiedDisplayText.Substring(num, num2 - num); string text2 = ""; if (!SyncManager.enablePurchasingItemSlots) { text2 += "Every reserved item slot is unlocked!\n\n"; } else { text2 += "Reserved Item Slots\n------------------------------\n\n"; text2 += "To purchase a reserved item slot, type the following command.\n> RESERVED [item_slot]\n\n"; int num3 = 0; foreach (ReservedItemSlotData value in SyncManager.unlockableReservedItemSlotsDict.Values) { num3 = Mathf.Max(num3, value.slotName.Length); } foreach (ReservedItemSlotData value2 in SyncManager.unlockableReservedItemSlotsDict.Values) { string arg = (SessionManager.IsItemSlotUnlocked(value2) ? "[Purchased]" : ("$" + value2.purchasePrice)); text2 += $"* {value2.slotDisplayName}{new string(' ', num3 - value2.slotDisplayName.Length)} // {arg}\n"; } } modifiedDisplayText = modifiedDisplayText.Replace(oldValue, text2); } [HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")] [HarmonyPrefix] public static bool ParsePlayerSentence(ref TerminalNode __result, Terminal __instance) { if (__instance.screenText.text.Length <= 0) { return true; } string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).ToLower(); string[] array = text.Split(new char[1] { ' ' }); ReservedItemSlotData reservedItemSlotData = null; if (!SyncManager.isSynced) { if (text.StartsWith("reserved")) { __result = BuildTerminalNodeHostDoesNotHaveMod(); return false; } return true; } if (purchasingItemSlot != null) { if ("confirm".StartsWith(text)) { if (purchasingItemSlot.isUnlocked) { Plugin.LogWarning("Attempted to confirm purchase on reserved item slot that was already unlocked. Item slot: " + purchasingItemSlot.slotDisplayName); __result = BuildTerminalNodeAlreadyUnlocked(purchasingItemSlot); } else if (terminalInstance.groupCredits < purchasingItemSlot.purchasePrice) { Plugin.LogWarning("Attempted to confirm purchase with insufficient credits. Current credits: " + terminalInstance.groupCredits + " Required credits: " + purchasingItemSlot.purchasePrice); __result = BuildTerminalNodeInsufficientFunds(purchasingItemSlot); } else { Plugin.Log("Purchasing reserved item slot: " + purchasingItemSlot.slotDisplayName + ". Price: " + purchasingItemSlot.purchasePrice); Terminal obj = terminalInstance; obj.groupCredits -= purchasingItemSlot.purchasePrice; terminalInstance.BuyItemsServerRpc(new int[0], terminalInstance.groupCredits, terminalInstance.numberOfItemsInDropship); SyncManager.SendUnlockItemSlotUpdateToServer(purchasingItemSlot.slotId); __result = BuildTerminalNodeOnPurchased(purchasingItemSlot, terminalInstance.groupCredits); } } else { Plugin.Log("Canceling order."); __result = BuildCustomTerminalNode("Canceled order.\n\n"); } purchasingItemSlot = null; return false; } purchasingItemSlot = null; if (array.Length == 0 || array[0] != "reserved") { return true; } if (array.Length == 1) { __result = BuildTerminalNodeHome(); return false; } string text2 = text.Substring(9); reservedItemSlotData = TryGetReservedItemSlot(text2); if (reservedItemSlotData != null) { if (SessionManager.IsItemSlotUnlocked(reservedItemSlotData)) { Plugin.LogWarning("Attempted to start purchase on reserved item slot that was already unlocked. Item slot: " + reservedItemSlotData.slotName); __result = BuildTerminalNodeAlreadyUnlocked(reservedItemSlotData); } else if (terminalInstance.groupCredits < reservedItemSlotData.purchasePrice) { Plugin.LogWarning("Attempted to start purchase with insufficient credits. Current credits: " + terminalInstance.groupCredits + ". Item slot price: " + reservedItemSlotData.purchasePrice); __result = BuildTerminalNodeInsufficientFunds(reservedItemSlotData); } else { Plugin.Log("Started purchasing reserved item slot: " + reservedItemSlotData.slotName); purchasingItemSlot = reservedItemSlotData; __result = BuildTerminalNodeConfirmDenyPurchase(reservedItemSlotData); } return false; } Plugin.LogWarning("Attempted to start purchase on invalid reserved item slot. Item slot: " + text2); __result = BuildTerminalNodeInvalidReservedItemSlot(text2); return false; } private static TerminalNode BuildTerminalNodeHome() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return new TerminalNode { displayText = "[ReservedItemSlots]\n\nStore\n------------------------------\n[[[reservedItemSlotsSelectionList]]]\n\n", clearPreviousText = true, acceptAnything = false }; } private static TerminalNode BuildTerminalNodeConfirmDenyPurchase(ReservedItemSlotData itemSlotData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown TerminalNode val = new TerminalNode(); val.displayText = "You have requested to purchase a reserved item slot for $" + itemSlotData.purchasePrice + " credits.\n> [" + itemSlotData.slotDisplayName + "]\n\n"; val.isConfirmationNode = true; val.acceptAnything = false; val.clearPreviousText = true; TerminalNode val2 = val; val2.displayText = val2.displayText + "Credit balance: $" + terminalInstance.groupCredits + "\n"; val2.displayText += "\n"; val2.displayText += "Please CONFIRM or DENY.\n\n"; return val2; } private static TerminalNode BuildTerminalNodeOnPurchased(ReservedItemSlotData itemSlotData, int newGroupCredits) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = "You have successfully purchased a new reserved item slot!\n> [" + itemSlotData.slotDisplayName + "]\n\n", buyUnlockable = true, clearPreviousText = true, acceptAnything = false, playSyncedClip = 0 }; val.displayText = val.displayText + "New credit balance: $" + newGroupCredits + "\n\n"; return val; } private static TerminalNode BuildTerminalNodeAlreadyUnlocked(ReservedItemSlotData itemSlot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown return new TerminalNode { displayText = "You have already purchased this reserved item slot!\n> [" + itemSlot.slotDisplayName + "]\n\n", clearPreviousText = false, acceptAnything = false }; } private static TerminalNode BuildTerminalNodeInsufficientFunds(ReservedItemSlotData itemSlot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown TerminalNode val = new TerminalNode(); val.displayText = "You could not afford this reserved item slot!\n> [" + itemSlot.slotDisplayName + "]\n\nCredit balance is $" + terminalInstance.groupCredits + "\n"; val.clearPreviousText = true; val.acceptAnything = false; TerminalNode val2 = val; val2.displayText = val2.displayText + "Price of reserved item slot is $" + itemSlot.purchasePrice + "\n\n"; return val2; } private static TerminalNode BuildTerminalNodeInvalidReservedItemSlot(string reservedItemSlotName = "") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = "Reserved item slot does not exist.", clearPreviousText = false, acceptAnything = false }; if (reservedItemSlotName != "") { val.displayText = val.displayText + "\n\"" + reservedItemSlotName + "\""; } val.displayText += "\n"; return val; } private static TerminalNode BuildTerminalNodeHostDoesNotHaveMod(string itemSlotName = "") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = "You cannot use the reserved item slot commands until you have synced with the host.\n\nYou may also be seeing this because the host does not have this mod.\n\n", clearPreviousText = true, acceptAnything = false }; if (itemSlotName != "") { val.displayText = val.displayText + "\n\"" + itemSlotName + "\""; } val.displayText += "\n"; return val; } private static TerminalNode BuildCustomTerminalNode(string displayText, bool clearPreviousText = false, bool acceptAnything = false, bool isConfirmationNode = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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) //IL_0023: Expected O, but got Unknown return new TerminalNode { displayText = displayText, clearPreviousText = clearPreviousText, acceptAnything = false, isConfirmationNode = isConfirmationNode }; } private static ReservedItemSlotData TryGetReservedItemSlot(string itemSlotNameInput) { ReservedItemSlotData reservedItemSlotData = null; foreach (ReservedItemSlotData unlockableReservedItemSlot in SyncManager.unlockableReservedItemSlots) { string text = unlockableReservedItemSlot.slotDisplayName.ToLower(); if ((itemSlotNameInput == text || (itemSlotNameInput.Length >= 4 && text.StartsWith(itemSlotNameInput))) && (reservedItemSlotData == null || text.Length < reservedItemSlotData.slotDisplayName.Length) && !"the company".StartsWith(itemSlotNameInput) && !"company".StartsWith(itemSlotNameInput)) { reservedItemSlotData = unlockableReservedItemSlot; } } return reservedItemSlotData; } } } namespace ReservedItemSlotCore.Networking { internal static class NetworkHelper { private static int NONE_EXEC_STAGE = 0; private static int SERVER_EXEC_STAGE = 1; private static int CLIENT_EXEC_STAGE = 2; internal static int GetExecStage(NetworkBehaviour __instance) { return (int)Traverse.Create((object)__instance).Field("__rpc_exec_stage").GetValue(); } internal static bool IsClientExecStage(NetworkBehaviour __instance) { return GetExecStage(__instance) == CLIENT_EXEC_STAGE; } internal static bool IsServerExecStage(NetworkBehaviour __instance) { return GetExecStage(__instance) == SERVER_EXEC_STAGE; } internal 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 static class SyncManager { [CompilerGenerated] private sealed class d__33 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private Dictionary.ValueCollection.Enumerator <>s__1; private ReservedPlayerData 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__33(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = default(Dictionary.ValueCollection.Enumerator); 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0f); <>1__state = 1; return true; case 1: <>1__state = -1; <>s__1 = ReservedPlayerData.allPlayerData.Values.GetEnumerator(); try { while (<>s__1.MoveNext()) { 5__2 = <>s__1.Current; 5__2.hotbarSize = 5__2.itemSlots.Length; 5__2.reservedHotbarStartIndex = 5__2.hotbarSize; 5__2 = null; } } finally { ((IDisposable)<>s__1).Dispose(); } <>s__1 = default(Dictionary.ValueCollection.Enumerator); SessionManager.UnlockAllPendingItemSlots(); if (!NetworkManager.Singleton.IsServer && hostHasMod) { RequestSyncHeldObjects(); } return false; } } 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 bool requestedSyncHeldObjects = false; public static List unlockableReservedItemSlots = new List(); public static Dictionary unlockableReservedItemSlotsDict = new Dictionary(); public static List reservedItems = new List(); public static Dictionary reservedItemsDict = new Dictionary(); public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static bool enablePurchasingItemSlots { get; internal set; } = false; internal static bool canUseModDisabledOnHost => ConfigSettings.forceEnableThisModIfNotEnabledOnHost.Value; public static bool isSynced { get; internal set; } = false; public static bool hostHasMod { get; private set; } = false; public static bool IsReservedItem(string itemName) { if (itemName == null) { return false; } foreach (ReservedItemSlotData unlockableReservedItemSlot in unlockableReservedItemSlots) { if (unlockableReservedItemSlot.ContainsItem(itemName)) { return true; } } return false; } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] public static void ResetValues(StartOfRound __instance) { isSynced = false; hostHasMod = false; requestedSyncHeldObjects = false; unlockableReservedItemSlots?.Clear(); unlockableReservedItemSlotsDict?.Clear(); enablePurchasingItemSlots = false; reservedItems?.Clear(); reservedItemsDict?.Clear(); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void Init(PlayerControllerB __instance) { //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Expected O, but got Unknown //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Expected O, but got Unknown //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Expected O, but got Unknown //IL_00aa: 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_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Expected O, but got Unknown //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Expected O, but got Unknown if (NetworkManager.Singleton.IsServer) { enablePurchasingItemSlots = ConfigSettings.enablePurchasingItemSlots.Value; unlockableReservedItemSlots = new List(); unlockableReservedItemSlotsDict = new Dictionary(); foreach (ReservedItemSlotData value in ReservedItemSlotData.allReservedItemSlotData.Values) { ReservedItemSlotData reservedItemSlotData = new ReservedItemSlotData(value.slotName, value.slotPriority, (int)((float)value.purchasePrice * ConfigSettings.globalItemSlotPriceModifier.Value)); foreach (ReservedItemData value2 in value.reservedItemData.Values) { reservedItemSlotData.AddItemToReservedItemSlot(new ReservedItemData(value2.itemName, value2.holsteredParentBone, value2.holsteredPositionOffset, value2.holsteredRotationOffset)); } AddReservedItemSlotData(reservedItemSlotData); if (!enablePurchasingItemSlots) { SessionManager.UnlockReservedItemSlot(reservedItemSlotData); } } if (enablePurchasingItemSlots) { SessionManager.LoadGameValues(); } if (enablePurchasingItemSlots) { foreach (ReservedItemSlotData unlockableReservedItemSlot in unlockableReservedItemSlots) { if (!unlockableReservedItemSlot.isUnlocked && unlockableReservedItemSlot.purchasePrice <= 0) { SessionManager.UnlockReservedItemSlot(unlockableReservedItemSlot); } } } isSynced = true; hostHasMod = true; OnSyncedWithServer(); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.OnSwapHotbarServerRpc", new HandleNamedMessageDelegate(OnSwapHotbarServerRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.RequestSyncServerRpc", new HandleNamedMessageDelegate(RequestSyncServerRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.OnUnlockItemSlotServerRpc", new HandleNamedMessageDelegate(OnUnlockItemSlotServerRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.RequestSyncHeldObjectsServerRpc", new HandleNamedMessageDelegate(RequestSyncHeldObjectsServerRpc)); } else { isSynced = false; unlockableReservedItemSlotsDict = new Dictionary(); unlockableReservedItemSlots = unlockableReservedItemSlotsDict.Values.ToList(); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.OnSwapHotbarClientRpc", new HandleNamedMessageDelegate(OnSwapHotbarClientRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.RequestSyncClientRpc", new HandleNamedMessageDelegate(RequestSyncClientRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.OnUnlockItemSlotClientRpc", new HandleNamedMessageDelegate(OnUnlockItemSlotClientRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("ReservedItemSlotCore.RequestSyncHeldObjectsClientRpc", new HandleNamedMessageDelegate(RequestSyncHeldObjectsClientRpc)); RequestSyncFromServer(); } UpdateReservedItemsList(); } internal static void AddReservedItemSlotData(ReservedItemSlotData itemSlotData) { if (itemSlotData != null && unlockableReservedItemSlotsDict != null && !unlockableReservedItemSlotsDict.ContainsKey(itemSlotData.slotName)) { unlockableReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData); unlockableReservedItemSlots.Add(itemSlotData); } } internal static void UpdateReservedItemsList() { if (unlockableReservedItemSlots == null) { return; } reservedItems.Clear(); reservedItemsDict.Clear(); foreach (ReservedItemSlotData unlockableReservedItemSlot in unlockableReservedItemSlots) { if (unlockableReservedItemSlot.reservedItemData == null) { continue; } foreach (ReservedItemData value in unlockableReservedItemSlot.reservedItemData.Values) { if (!reservedItemsDict.ContainsKey(value.itemName)) { reservedItemsDict.Add(value.itemName, value); reservedItems.Add(value); } } } } private static void RequestSyncFromServer() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer) { Plugin.Log("Requesting sync with server."); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlotCore.RequestSyncServerRpc", 0uL, new FastBufferWriter(0, (Allocator)2, -1), (NetworkDelivery)3); } } private static void RequestSyncServerRpc(ulong clientId, FastBufferReader reader) { if (NetworkManager.Singleton.IsServer) { Plugin.Log("Receiving sync request from client: " + clientId); SendSyncToClient(clientId); } } public static void SendSyncToClient(ulong clientId) { SendSync(clientId); } public static void SendSyncToAllClients() { SendSync(0uL, sendToAllClients: true); } private static void SendSync(ulong clientId = 0uL, bool sendToAllClients = false) { //IL_0125: 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_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0374: 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_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer) { return; } int num = 4; foreach (ReservedItemSlotData unlockableReservedItemSlot in unlockableReservedItemSlots) { if (unlockableReservedItemSlot == null || unlockableReservedItemSlot.reservedItemData == null || unlockableReservedItemSlot.reservedItemData.Count <= 0) { continue; } num += 4; byte[] bytes = Encoding.UTF8.GetBytes(unlockableReservedItemSlot.slotName); num += bytes.Length; num += 4; num += 4; num += 4; foreach (ReservedItemData value in unlockableReservedItemSlot.reservedItemData.Values) { num += 4; byte[] bytes2 = Encoding.UTF8.GetBytes(value.itemName); num += bytes2.Length; num += 4; num += 24; } num++; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1 + num, (Allocator)2, -1); bool flag = enablePurchasingItemSlots; ((FastBufferWriter)(ref val)).WriteValue(ref flag, default(ForPrimitives)); int count = unlockableReservedItemSlots.Count; ((FastBufferWriter)(ref val)).WriteValue(ref count, default(ForPrimitives)); foreach (ReservedItemSlotData unlockableReservedItemSlot2 in unlockableReservedItemSlots) { if (unlockableReservedItemSlot2 == null || unlockableReservedItemSlot2.reservedItemData == null || unlockableReservedItemSlot2.reservedItemData.Count <= 0) { continue; } byte[] bytes3 = Encoding.UTF8.GetBytes(unlockableReservedItemSlot2.slotName); count = bytes3.Length; ((FastBufferWriter)(ref val)).WriteValue(ref count, default(ForPrimitives)); byte[] array = bytes3; for (int i = 0; i < array.Length; i++) { byte b = array[i]; ((FastBufferWriter)(ref val)).WriteValue(ref b, default(ForPrimitives)); } ((FastBufferWriter)(ref val)).WriteValue(ref unlockableReservedItemSlot2.slotPriority, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref unlockableReservedItemSlot2.purchasePrice, default(ForPrimitives)); count = unlockableReservedItemSlot2.reservedItemData.Count; ((FastBufferWriter)(ref val)).WriteValue(ref count, default(ForPrimitives)); foreach (ReservedItemData value2 in unlockableReservedItemSlot2.reservedItemData.Values) { byte[] bytes4 = Encoding.UTF8.GetBytes(value2.itemName); count = bytes4.Length; ((FastBufferWriter)(ref val)).WriteValue(ref count, default(ForPrimitives)); byte[] array2 = bytes4; for (int j = 0; j < array2.Length; j++) { byte b2 = array2[j]; ((FastBufferWriter)(ref val)).WriteValue(ref b2, default(ForPrimitives)); } count = (int)value2.holsteredParentBone; ((FastBufferWriter)(ref val)).WriteValue(ref count, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref value2.holsteredPositionOffset.x, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref value2.holsteredPositionOffset.y, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref value2.holsteredPositionOffset.z, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref value2.holsteredRotationOffset.x, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref value2.holsteredRotationOffset.y, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValue(ref value2.holsteredRotationOffset.z, default(ForPrimitives)); } Plugin.Log("Sending slot to client: " + unlockableReservedItemSlot2.slotName + " Unlocked: " + unlockableReservedItemSlot2.isUnlocked); flag = unlockableReservedItemSlot2.isUnlocked; ((FastBufferWriter)(ref val)).WriteValue(ref flag, default(ForPrimitives)); } if (sendToAllClients) { Plugin.Log("Sending sync to all clients."); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("ReservedItemSlotCore.RequestSyncClientRpc", val, (NetworkDelivery)4); } else { Plugin.Log("Sending sync to client with id: " + clientId); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlotCore.RequestSyncClientRpc", clientId, val, (NetworkDelivery)4); } } private static void RequestSyncClientRpc(ulong clientId, FastBufferReader reader) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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_01ba: 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) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer) { return; } hostHasMod = true; unlockableReservedItemSlots = new List(); unlockableReservedItemSlotsDict = new Dictionary(); Plugin.Log("Receiving sync from server."); if (SessionManager.unlockedReservedItemSlots != null && SessionManager.unlockedReservedItemSlots.Count > 0) { SessionManager.ResetProgress(force: true); } bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValue(ref flag, default(ForPrimitives)); int num = default(int); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); enablePurchasingItemSlots = flag; int num2 = default(int); int slotPriority = default(int); int purchasePrice = default(int); int num3 = default(int); int num4 = default(int); int num5 = default(int); Vector3 holsteredPositionOffset = default(Vector3); Vector3 holsteredRotationOffset = default(Vector3); bool flag2 = default(bool); for (int i = 0; i < num; i++) { ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); byte[] bytes = new byte[num2]; ((FastBufferReader)(ref reader)).ReadBytes(ref bytes, num2, 0); string @string = Encoding.UTF8.GetString(bytes); ((FastBufferReader)(ref reader)).ReadValue(ref slotPriority, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref purchasePrice, default(ForPrimitives)); ReservedItemSlotData reservedItemSlotData = new ReservedItemSlotData(@string, slotPriority, purchasePrice); ((FastBufferReader)(ref reader)).ReadValue(ref num3, default(ForPrimitives)); for (int j = 0; j < num3; j++) { ((FastBufferReader)(ref reader)).ReadValue(ref num4, default(ForPrimitives)); byte[] bytes2 = new byte[num4]; ((FastBufferReader)(ref reader)).ReadBytes(ref bytes2, num4, 0); string string2 = Encoding.UTF8.GetString(bytes2); ((FastBufferReader)(ref reader)).ReadValue(ref num5, default(ForPrimitives)); PlayerBone holsteredParentBone = (PlayerBone)num5; ((FastBufferReader)(ref reader)).ReadValue(ref holsteredPositionOffset.x, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref holsteredPositionOffset.y, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref holsteredPositionOffset.z, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref holsteredRotationOffset.x, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref holsteredRotationOffset.y, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref holsteredRotationOffset.z, default(ForPrimitives)); ReservedItemData itemData = new ReservedItemData(string2, holsteredParentBone, holsteredPositionOffset, holsteredRotationOffset); reservedItemSlotData.AddItemToReservedItemSlot(itemData); } ((FastBufferReader)(ref reader)).ReadValue(ref flag2, default(ForPrimitives)); AddReservedItemSlotData(reservedItemSlotData); if (flag2) { SessionManager.UnlockReservedItemSlot(reservedItemSlotData); } Plugin.Log("Receiving sync for reserved item slot data: - Slot: " + reservedItemSlotData.slotName + " Priority: " + reservedItemSlotData.slotPriority + " Unlocked: " + flag2); } UpdateReservedItemsList(); OnSyncedWithServer(); Plugin.Log("Received sync for " + unlockableReservedItemSlotsDict.Count + " reserved item slots."); } private static void OnSyncedWithServer() { isSynced = true; if (hostHasMod) { foreach (Item items in StartOfRound.Instance.allItemsList.itemsList) { if (IsReservedItem(items.itemName)) { items.canBeGrabbedBeforeGameStart = true; } } } ((MonoBehaviour)localPlayerController).StartCoroutine(OnSyncedWithServerDelayed()); } [IteratorStateMachine(typeof(d__33))] private static IEnumerator OnSyncedWithServerDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__33(0); } private static void RequestSyncHeldObjects() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer && !requestedSyncHeldObjects) { Plugin.Log("Requesting sync held objects from server."); requestedSyncHeldObjects = true; NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlotCore.RequestSyncHeldObjectsServerRpc", 0uL, new FastBufferWriter(0, (Allocator)2, -1), (NetworkDelivery)3); } } private static void RequestSyncHeldObjectsServerRpc(ulong clientId, FastBufferReader reader) { //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0232: 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_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer) { return; } List list = new List(); List list2 = new List(); Dictionary> dictionary = new Dictionary>(); Dictionary> dictionary2 = new Dictionary>(); int num = 2; foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values) { ushort num2 = (ushort)value.playerController.actualClientId; ushort num3 = (ushort)value.playerController.playerClientId; if (num2 == clientId || (num2 == 0 && !value.isLocalPlayer)) { continue; } for (short num4 = (short)value.reservedHotbarStartIndex; num4 < (short)value.reservedHotbarEndIndexExcluded; num4++) { short item = (short)(num4 - (short)value.reservedHotbarStartIndex); GrabbableObject val = value.itemSlots[num4]; if ((Object)(object)val != (Object)null) { if (!dictionary.ContainsKey(num3)) { dictionary.Add(num3, new List()); dictionary2.Add(num3, new List()); } dictionary[num3].Add(item); dictionary2[num3].Add(((NetworkBehaviour)val).NetworkObjectId); } } if (dictionary.ContainsKey(num3) && dictionary[num3].Count > 0) { num += 2; num += 2; num += 2; num += 10 * dictionary[num3].Count; list.Add(num3); list2.Add((short)value.currentItemSlot); } } Plugin.Log("Receiving sync held objects request from client with id: " + clientId + ". " + list.Count + " players are currently holding a reserved item."); FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(num, (Allocator)2, -1); short num5 = (short)list.Count; ((FastBufferWriter)(ref val2)).WriteValue(ref num5, default(ForPrimitives)); for (int i = 0; i < list.Count; i++) { ushort key = list[i]; short num6 = list2[i]; short num7 = (short)dictionary[key].Count; ((FastBufferWriter)(ref val2)).WriteValue(ref key, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValue(ref num6, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValue(ref num7, default(ForPrimitives)); for (int j = 0; j < num7; j++) { short num8 = dictionary[key][j]; ulong num9 = dictionary2[key][j]; ((FastBufferWriter)(ref val2)).WriteValue(ref num8, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValue(ref num9, default(ForPrimitives)); } } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlotCore.RequestSyncHeldObjectsClientRpc", clientId, val2, (NetworkDelivery)4); } private static void RequestSyncHeldObjectsClientRpc(ulong clientId, FastBufferReader reader) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer) { return; } short num = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); Plugin.Log("Receiving sync held objects from server. Number of players already holding a reserved item: " + num); ushort num2 = default(ushort); short num3 = default(short); short num4 = default(short); short num5 = default(short); ulong networkObjectId = default(ulong); for (int i = 0; i < num; i++) { ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref num3, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref num4, default(ForPrimitives)); PlayerControllerB playerControllerByPlayerId = GetPlayerControllerByPlayerId(num2); ReservedPlayerData value = null; if ((Object)(object)playerControllerByPlayerId != (Object)null) { ReservedPlayerData.allPlayerData.TryGetValue(playerControllerByPlayerId, out value); } for (int j = 0; j < num4; j++) { ((FastBufferReader)(ref reader)).ReadValue(ref num5, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValue(ref networkObjectId, default(ForPrimitives)); GrabbableObject grabbableObjectByNetworkId = GetGrabbableObjectByNetworkId(networkObjectId); if ((Object)(object)grabbableObjectByNetworkId != (Object)null && value != null && num5 >= 0 && num5 < SessionManager.numReservedItemSlotsUnlocked) { int num6 = num5 + value.reservedHotbarStartIndex; grabbableObjectByNetworkId.isHeld = true; value.itemSlots[num6] = grabbableObjectByNetworkId; grabbableObjectByNetworkId.parentObject = playerControllerByPlayerId.serverItemHolder; grabbableObjectByNetworkId.playerHeldBy = playerControllerByPlayerId; bool flag = num3 == num6; grabbableObjectByNetworkId.EnablePhysics(false); if (flag) { grabbableObjectByNetworkId.EquipItem(); playerControllerByPlayerId.currentlyHeldObjectServer = grabbableObjectByNetworkId; playerControllerByPlayerId.isHoldingObject = true; playerControllerByPlayerId.twoHanded = grabbableObjectByNetworkId.itemProperties.twoHanded; playerControllerByPlayerId.twoHandedAnimation = grabbableObjectByNetworkId.itemProperties.twoHandedAnimation; playerControllerByPlayerId.currentItemSlot = num6; } else { grabbableObjectByNetworkId.PocketItem(); } } } } } public static void SendUnlockItemSlotUpdateToServer(int reservedItemSlotId) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); Plugin.Log("Sending unlocked reserved item slot update to server. Item slot id: " + reservedItemSlotId); ((FastBufferWriter)(ref val)).WriteValue(ref reservedItemSlotId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlotCore.OnUnlockItemSlotServerRpc", 0uL, val, (NetworkDelivery)3); } private static void OnUnlockItemSlotServerRpc(ulong clientId, FastBufferReader reader) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer) { return; } int num = default(int); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if (num >= 0 && unlockableReservedItemSlots != null && num < unlockableReservedItemSlots.Count) { if (NetworkManager.Singleton.IsClient) { if (clientId != localPlayerController.actualClientId) { Plugin.Log("Receiving unlocked reserved item slot update from client for. Item slot id: " + num); } ReservedItemSlotData itemSlotData = unlockableReservedItemSlots[num]; SessionManager.UnlockReservedItemSlot(itemSlotData); } SendUnlockItemSlotToClients(num); } else { Plugin.LogError("Failed to receive unlock reserved item slot from client. Received item slot id: " + num + " Size of unlockable reserved item slots: " + unlockableReservedItemSlots.Count); } } public static void SendUnlockItemSlotToClients(int reservedItemSlotId) { //IL_0044: 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) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsServer && reservedItemSlotId >= 0 && unlockableReservedItemSlots != null && reservedItemSlotId < unlockableReservedItemSlots.Count) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue(ref reservedItemSlotId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("ReservedItemSlotCore.OnUnlockItemSlotClientRpc", val, (NetworkDelivery)3); } } private static void OnUnlockItemSlotClientRpc(ulong clientId, FastBufferReader reader) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer) { int num = default(int); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if (num >= 0 && unlockableReservedItemSlots != null && num < unlockableReservedItemSlots.Count) { Plugin.Log("Receiving unlocked reserved item slot update from server. Item slot id: " + num); ReservedItemSlotData itemSlotData = unlockableReservedItemSlots[num]; SessionManager.UnlockReservedItemSlot(itemSlotData); } else { Plugin.LogError("Failed to receive unlock reserved item slot from server. Received item slot id: " + num + " Size of unlockable reserved item slots: " + unlockableReservedItemSlots.Count); } } } private static void SendSwapHotbarUpdateToServer(int hotbarSlot) { //IL_0049: 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_0068: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsClient) { if (NetworkManager.Singleton.IsServer) { SendSwapHotbarUpdateToClients(localPlayerController.actualClientId, hotbarSlot); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(2, (Allocator)2, -1); short num = (short)hotbarSlot; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReservedItemSlotCore.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) if (NetworkManager.Singleton.IsServer) { short num = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if (NetworkManager.Singleton.IsClient && clientId != localPlayerController.actualClientId) { Plugin.Log("Receiving OnSwapReservedHotbar update from client. ClientId: " + clientId + " Slot: " + num); TryUpdateClientHotbarSlot(clientId, num); } SendSwapHotbarUpdateToClients(clientId, num); } } internal static void SendSwapHotbarUpdateToClients(ulong clientId, int hotbarIndex) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) if (NetworkManager.Singleton.IsServer) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(10, (Allocator)2, -1); short num = (short)hotbarIndex; ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); ulong num2 = clientId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref num2, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("ReservedItemSlotCore.OnSwapHotbarClientRpc", val, (NetworkDelivery)3); } } private static void OnSwapHotbarClientRpc(ulong clientId, FastBufferReader reader) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer) { return; } short hotbarSlot = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref hotbarSlot, default(ForPrimitives)); ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if (num != localPlayerController.actualClientId) { Plugin.Log("Receiving OnSwapReservedHotbar update from client. ClientId: " + num + " Slot: " + hotbarSlot); if (!TryUpdateClientHotbarSlot(num, hotbarSlot)) { Plugin.Log("Failed to receive hotbar swap index from Client: " + num); } } } private static bool TryUpdateClientHotbarSlot(ulong clientId, int hotbarSlot) { string text = ""; 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; } text = text + " " + val.actualClientId; } Plugin.LogErrorVerbose("Failed to find client with id: " + clientId + " while attempting to swap hotbar slots."); Plugin.LogErrorVerbose("Valid user ids: " + text.Trim(new char[1] { ' ' })); return false; } public static void SwapHotbarSlot(int hotbarIndex) { SendSwapHotbarUpdateToServer(hotbarIndex); CallSwitchToItemSlotMethod(localPlayerController, hotbarIndex); } internal 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", true); } PlayerPatcher.SwitchToItemSlot(playerController, hotbarIndex); if ((Object)(object)playerController.currentlyHeldObjectServer != (Object)null) { ((Component)playerController.currentlyHeldObjectServer).gameObject.GetComponent().PlayOneShot(playerController.currentlyHeldObjectServer.itemProperties.grabSFX, 0.6f); } } } internal static PlayerControllerB GetPlayerControllerByClientId(ulong clientId) { for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++) { PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[i]; if (val.actualClientId == clientId) { return val; } } return null; } internal static PlayerControllerB GetPlayerControllerByPlayerId(ulong playerId) { for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++) { PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[i]; if (val.playerClientId == playerId) { return val; } } return null; } internal static GrabbableObject GetGrabbableObjectByNetworkId(ulong networkObjectId) { if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var value)) { return ((Component)value).GetComponentInChildren(); } return null; } } } namespace ReservedItemSlotCore.Input { internal class IngameKeybinds : LcInputActions { internal static IngameKeybinds Instance; [InputAction("/leftAlt", GamepadPath = "/leftShoulder", Name = "Swap hotbars")] internal InputAction FocusReservedHotbarHotkey { get; set; } [InputAction("/rightAlt", GamepadPath = "", Name = "Toggle Swap hotbars")] internal InputAction ToggleFocusReservedHotbarHotkey { get; set; } internal static InputActionAsset GetAsset() { return ((LcInputActions)Instance).Asset; } } 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; public static InputAction ToggleFocusReservedHotbarHotkey => IngameKeybinds.Instance.ToggleFocusReservedHotbarHotkey; internal static void Init() { if (Enabled && IngameKeybinds.Instance == null) { IngameKeybinds.Instance = new IngameKeybinds(); } } } [HarmonyPatch] public static class KeybindDisplayNames { public static bool usingControllerPrevious = false; public static string[] keyboardKeywords = new string[2] { "keyboard", "mouse" }; public static string[] controllerKeywords = new string[2] { "gamepad", "controller" }; 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(); } public static string GetKeybindDisplayName(InputAction inputAction) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (inputAction == null || !inputAction.enabled) { return ""; } int num = (usingController ? 1 : 0); InputBinding val = inputAction.bindings[num]; string effectivePath = ((InputBinding)(ref val)).effectivePath; return GetKeybindDisplayName(effectivePath); } public static string GetKeybindDisplayName(string controlPath) { if (controlPath.Length <= 1) { return ""; } string text = controlPath.ToLower(); int num = text.IndexOf(">/"); text = ((num >= 0) ? text.Substring(num + 2) : text); if (text.Contains("not-bound")) { return ""; } text = text.Replace("leftalt", "L-Alt"); text = text.Replace("rightalt", "R-Alt"); text = text.Replace("leftctrl", "L-Ctrl"); text = text.Replace("rightctrl", "R-Ctrl"); text = text.Replace("leftshift", "L-Shift"); text = text.Replace("rightshift", "R-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; } } [HarmonyPatch] internal static class Keybinds { [CompilerGenerated] private sealed class <g__ResetScrollDelayed|16_0>d : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <g__ResetScrollDelayed|16_0>d(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 2; return true; case 2: <>1__state = -1; scrollingReservedHotbar = false; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static InputActionAsset Asset; public static InputActionMap ActionMap; public static InputAction FocusReservedHotbarAction; public static InputAction ToggleFocusReservedHotbarAction; public static InputAction RawScrollAction; public static bool holdingModifierKey; public static bool pressedToggleKey; public static bool scrollingReservedHotbar; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; [HarmonyPatch(typeof(PreInitSceneScript), "Awake")] [HarmonyPrefix] private static void AddToKeybindMenu() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0084: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown if (InputUtilsCompat.Enabled) { Asset = InputUtilsCompat.Asset; FocusReservedHotbarAction = InputUtilsCompat.FocusReservedHotbarHotkey; ToggleFocusReservedHotbarAction = InputUtilsCompat.ToggleFocusReservedHotbarHotkey; } else { Asset = ScriptableObject.CreateInstance(); ActionMap = new InputActionMap("ReservedItemSlots"); InputActionSetupExtensions.AddActionMap(Asset, ActionMap); FocusReservedHotbarAction = InputActionSetupExtensions.AddAction(ActionMap, "ReservedItemSlots.FocusReservedHotbar", (InputActionType)0, "/leftAlt", (string)null, (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(FocusReservedHotbarAction, "/leftShoulder", (string)null, (string)null, (string)null); ToggleFocusReservedHotbarAction = InputActionSetupExtensions.AddAction(ActionMap, "ReservedItemSlots.ToggleFocusReservedHotbar", (InputActionType)0, "/rightAlt", (string)null, (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(ToggleFocusReservedHotbarAction, "/leftShoulder", (string)null, (string)null, (string)null); } RawScrollAction = new InputAction("ReservedItemSlots.RawScroll", (InputActionType)0, "/scroll/y", (string)null, (string)null, (string)null); } [HarmonyPatch(typeof(StartOfRound), "OnEnable")] [HarmonyPrefix] private static void OnEnable() { holdingModifierKey = false; Asset.Enable(); RawScrollAction.Enable(); FocusReservedHotbarAction.performed += FocusReservedHotbarSlotsAction; FocusReservedHotbarAction.canceled += UnfocusReservedHotbarSlotsPerformed; ToggleFocusReservedHotbarAction.performed += ToggleFocusReservedHotbarSlotsAction; RawScrollAction.performed += OnScrollReservedHotbar; if (LCVR_Compat.LoadedAndEnabled) { pressedToggleKey = true; } } [HarmonyPatch(typeof(StartOfRound), "OnDisable")] [HarmonyPrefix] private static void OnDisable() { Asset.Disable(); RawScrollAction.Disable(); FocusReservedHotbarAction.performed -= FocusReservedHotbarSlotsAction; FocusReservedHotbarAction.canceled -= UnfocusReservedHotbarSlotsPerformed; ToggleFocusReservedHotbarAction.performed -= ToggleFocusReservedHotbarSlotsAction; RawScrollAction.performed -= OnScrollReservedHotbar; } private static void FocusReservedHotbarSlotsAction(CallbackContext context) { if (LCVR_Compat.LoadedAndEnabled || (Object)(object)localPlayerController == (Object)null || !((NetworkBehaviour)localPlayerController).IsOwner || !localPlayerController.isPlayerControlled || (((NetworkBehaviour)localPlayerController).IsServer && !localPlayerController.isHostPlayerObject) || SessionManager.numReservedItemSlotsUnlocked <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled) { return; } if (ReservedPlayerData.localPlayerData.GetNumHeldReservedItems() <= 0 && ConfigSettings.hideEmptyReservedItemSlots.Value) { if (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved) { ReservedHotbarManager.FocusReservedHotbarSlots(active: false); } return; } holdingModifierKey = true; pressedToggleKey = false; if (((CallbackContext)(ref context)).performed && ReservedHotbarManager.CanSwapHotbars()) { ReservedHotbarManager.FocusReservedHotbarSlots(active: true); } } private static void UnfocusReservedHotbarSlotsPerformed(CallbackContext context) { if (!LCVR_Compat.LoadedAndEnabled && !((Object)(object)localPlayerController == (Object)null) && ((NetworkBehaviour)localPlayerController).IsOwner && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject)) { holdingModifierKey = false; pressedToggleKey = false; if (((CallbackContext)(ref context)).performed && ReservedHotbarManager.CanSwapHotbars()) { ReservedHotbarManager.FocusReservedHotbarSlots(active: false); } } } private static void ToggleFocusReservedHotbarSlotsAction(CallbackContext context) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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) //IL_00fa: 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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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) if (LCVR_Compat.LoadedAndEnabled || (Object)(object)localPlayerController == (Object)null || !((NetworkBehaviour)localPlayerController).IsOwner || !localPlayerController.isPlayerControlled || (((NetworkBehaviour)localPlayerController).IsServer && !localPlayerController.isHostPlayerObject) || (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved && holdingModifierKey) || SessionManager.numReservedItemSlotsUnlocked <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled) { return; } if (ReservedPlayerData.localPlayerData.GetNumHeldReservedItems() <= 0 && ConfigSettings.hideEmptyReservedItemSlots.Value) { if (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved) { ReservedHotbarManager.FocusReservedHotbarSlots(active: false); } return; } int num = (StartOfRound.Instance.localPlayerUsingController ? 1 : 0); InputBinding val = FocusReservedHotbarAction.bindings[num]; string effectivePath = ((InputBinding)(ref val)).effectivePath; val = ToggleFocusReservedHotbarAction.bindings[num]; if (!(effectivePath == ((InputBinding)(ref val)).effectivePath)) { holdingModifierKey = false; pressedToggleKey = true; if (((CallbackContext)(ref context)).performed && ReservedHotbarManager.CanSwapHotbars()) { ReservedHotbarManager.FocusReservedHotbarSlots(!ReservedPlayerData.localPlayerData.currentItemSlotIsReserved); } } } private static void OnScrollReservedHotbar(CallbackContext context) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (!LCVR_Compat.LoadedAndEnabled && (!TooManyEmotes_Compat.Enabled || !TooManyEmotes_Compat.IsEmoteMenuOpen()) && !((Object)(object)localPlayerController == (Object)null) && ((NetworkBehaviour)localPlayerController).IsOwner && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject) && ((CallbackContext)(ref context)).performed && !localPlayerController.inTerminalMenu && !ReservedPlayerData.localPlayerData.throwingObject && !scrollingReservedHotbar && ReservedPlayerData.localPlayerData.currentItemSlotIsReserved && ReservedPlayerData.localPlayerData.grabbingReservedItemData == 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()); } [IteratorStateMachine(typeof(<g__ResetScrollDelayed|16_0>d))] static IEnumerator ResetScrollDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <g__ResetScrollDelayed|16_0>d(0); } } } } namespace ReservedItemSlotCore.Data { public class BoneMap { private Transform[] boneArray; private static List defaultBoneNames = new List { "spine", "spine.001", "spine.002", "spine.003", "spine.004", "spine.004", "shoulder.L", "arm.L_upper", "arm.L_lower", "hand.L", "shoulder.R", "arm.R_upper", "arm.R_lower", "hand.R", "thigh.L", "shin.L", "foot.L", "heel.02.L", "toe.L", "thigh.R", "shin.R", "foot.R", "heel.02.R", "toe.R" }; public List boneNames; internal Transform spine0 => (boneArray != null) ? boneArray[0] : null; internal Transform spine1 => (boneArray != null) ? boneArray[1] : null; internal Transform spine2 => (boneArray != null) ? boneArray[2] : null; internal Transform spine3 => (boneArray != null) ? boneArray[3] : null; internal Transform neck => (boneArray != null) ? boneArray[4] : null; internal Transform head => (boneArray != null) ? boneArray[5] : null; internal Transform shoulderL => (boneArray != null) ? boneArray[6] : null; internal Transform armUpperL => (boneArray != null) ? boneArray[7] : null; internal Transform armLowerL => (boneArray != null) ? boneArray[8] : null; internal Transform handL => (boneArray != null) ? boneArray[9] : null; internal Transform shoulderR => (boneArray != null) ? boneArray[10] : null; internal Transform armUpperR => (boneArray != null) ? boneArray[11] : null; internal Transform armLowerR => (boneArray != null) ? boneArray[12] : null; internal Transform handR => (boneArray != null) ? boneArray[13] : null; internal Transform thighL => (boneArray != null) ? boneArray[14] : null; internal Transform calfL => (boneArray != null) ? boneArray[15] : null; internal Transform footL => (boneArray != null) ? boneArray[16] : null; internal Transform heelL => (boneArray != null) ? boneArray[17] : null; internal Transform toeL => (boneArray != null) ? boneArray[18] : null; internal Transform thighR => (boneArray != null) ? boneArray[19] : null; internal Transform calfR => (boneArray != null) ? boneArray[20] : null; internal Transform footR => (boneArray != null) ? boneArray[21] : null; internal Transform heelR => (boneArray != null) ? boneArray[22] : null; internal Transform toeR => (boneArray != null) ? boneArray[23] : null; public void CreateBoneMap(Transform rootBone, List overrideBoneNames = null) { if (!((Object)(object)rootBone == (Object)null)) { boneNames = ((overrideBoneNames != null) ? overrideBoneNames : defaultBoneNames); if (boneNames.Count != defaultBoneNames.Count) { Plugin.LogWarning("Failed to create bonemap. Passed in custom bone names list with unsupported size. Size must be: " + defaultBoneNames.Count + ". Custom name list size: " + boneNames.Count); return; } boneArray = (Transform[])(object)new Transform[24] { spine0, spine1, spine2, spine3, neck, head, shoulderL, armUpperL, armLowerL, handL, shoulderR, armUpperR, armLowerR, handR, thighL, calfL, footL, heelL, toeL, thighR, calfR, footR, heelR, toeR }; MapBoneRecursive(rootBone); } } private void MapBoneRecursive(Transform bone) { IEnumerable enumerable = boneNames.Select((string name, int index) => (((Object)bone).name == name) ? index : (-1)); foreach (int item in enumerable) { if (item >= 0 && item < boneArray.Length && (Object)(object)boneArray[item] == (Object)null) { boneArray[item] = bone; } } for (int i = 0; i < bone.childCount; i++) { MapBoneRecursive(bone.GetChild(i)); } } public Transform GetBone(PlayerBone eBone) { if (boneArray == null) { return null; } int num = (int)(eBone - 1); return (num >= 0 && num < boneArray.Length) ? boneArray[num] : null; } } public enum PlayerBone { None, Hips, Spine1, Spine2, Spine3, Neck, Head, LeftShoulder, LeftArmUpper, LeftArmLower, LeftHand, RightShoulder, RightArmUpper, RightArmLower, RightHand, LeftThigh, LeftCalf, LeftFoot, LeftHeel, LeftToe, RightThigh, RightCalf, RightFoot, RightHeel, RightToe } [HarmonyPatch] public class MaskedEnemyData { public static Dictionary allMaskedEnemyData = new Dictionary(); public MaskedPlayerEnemy maskedEnemy; public BoneMap boneMap = new BoneMap(); public List equippedReservedItems; public PlayerControllerB originallyMimickingPlayer = null; public MaskedEnemyData(MaskedPlayerEnemy maskedEnemy) { this.maskedEnemy = maskedEnemy; boneMap = new BoneMap(); boneMap.CreateBoneMap(((Component)maskedEnemy).transform); } public Transform GetBone(PlayerBone eBone) { return boneMap?.GetBone(eBone); } public void DestroyEquippedItems() { if (equippedReservedItems == null) { return; } foreach (GameObject equippedReservedItem in equippedReservedItems) { Object.Destroy((Object)(object)equippedReservedItem.gameObject); } } } public class ReservedItemData { internal static Dictionary allReservedItems = new Dictionary(); public List parentItemSlots = new List(); public string itemName = ""; public PlayerBone holsteredParentBone; public Vector3 holsteredPositionOffset = Vector3.zero; public Vector3 holsteredRotationOffset = Vector3.zero; public bool showOnPlayerWhileHolstered => holsteredParentBone != PlayerBone.None; public ReservedItemData(string itemName, PlayerBone holsteredParentBone = PlayerBone.None, Vector3 holsteredPositionOffset = default(Vector3), Vector3 holsteredRotationOffset = default(Vector3)) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) //IL_004c: Unknown result type (might be due to invalid IL or missing references) this.itemName = itemName; this.holsteredParentBone = holsteredParentBone; this.holsteredPositionOffset = holsteredPositionOffset; this.holsteredRotationOffset = holsteredRotationOffset; } public void AddToReservedItemSlot(ReservedItemSlotData itemSlotData) { if (parentItemSlots.Contains(itemSlotData)) { Plugin.LogWarning("Item: " + itemName + " already as reserved item slot: " + itemSlotData.slotName + " set as a parent! Ignoring."); } else { parentItemSlots.Add(itemSlotData); } } public bool HasUnlockedParentSlot() { if (parentItemSlots != null) { foreach (ReservedItemSlotData parentItemSlot in parentItemSlots) { if (SessionManager.unlockedReservedItemSlots != null && SessionManager.unlockedReservedItemSlots.Contains(parentItemSlot)) { return true; } } } return false; } } [HarmonyPatch] public class ReservedItemSlotData { internal static Dictionary allReservedItemSlotData = new Dictionary(); internal static Dictionary allReservedItemSlotDataByPriority = new Dictionary(); internal static Dictionary> pendingAddReservedItemsToSlots = new Dictionary>(); public Dictionary reservedItemData = new Dictionary(); public string slotName = ""; public string slotDisplayName = ""; public int slotPriority = 0; public int purchasePrice = 200; public int slotId => (SyncManager.unlockableReservedItemSlots != null) ? SyncManager.unlockableReservedItemSlots.IndexOf(this) : (-1); public bool isUnlocked => SessionManager.IsItemSlotUnlocked(this); public int GetIndexInInventory(PlayerControllerB playerController) { if ((Object)(object)playerController == (Object)null || !isUnlocked || !ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value)) { return -1; } return GetReservedItemSlotIndex() + value.reservedHotbarStartIndex; } internal int GetIndexInInventory(ReservedPlayerData playerData) { return GetIndexInInventory(playerData?.playerController); } public GrabbableObject GetHeldObjectInSlot(PlayerControllerB playerController) { if ((Object)(object)playerController == (Object)null || !isUnlocked || !ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value)) { return null; } int indexInInventory = GetIndexInInventory(playerController); if (indexInInventory >= value.reservedHotbarStartIndex && indexInInventory < value.reservedHotbarEndIndexExcluded) { return playerController.ItemSlots[indexInInventory]; } return null; } internal GrabbableObject GetHeldObjectInSlot(ReservedPlayerData playerData) { return GetHeldObjectInSlot(playerData?.playerController); } public Image GetItemSlotFrameHUD() { if ((Object)(object)StartOfRound.Instance?.localPlayerController == (Object)null || !isUnlocked) { return null; } int reservedItemSlotIndex = GetReservedItemSlotIndex(); if (reservedItemSlotIndex < 0 || HUDPatcher.reservedItemSlots == null || reservedItemSlotIndex >= HUDPatcher.reservedItemSlots.Count) { return null; } return HUDPatcher.reservedItemSlots[reservedItemSlotIndex]; } public static void TryAddItemDataToReservedItemSlot(ReservedItemData itemData, string itemSlotName) { if (!pendingAddReservedItemsToSlots.ContainsKey(itemSlotName)) { pendingAddReservedItemsToSlots.Add(itemSlotName, new List()); } List list = pendingAddReservedItemsToSlots[itemSlotName]; if (!list.Contains(itemData)) { list.Add(itemData); } } [HarmonyPatch(typeof(PreInitSceneScript), "Awake")] [HarmonyPrefix] private static void AddPendingItemDataToItemSlots() { foreach (KeyValuePair> pendingAddReservedItemsToSlot in pendingAddReservedItemsToSlots) { string key = pendingAddReservedItemsToSlot.Key; List value = pendingAddReservedItemsToSlot.Value; if (!allReservedItemSlotData.TryGetValue(key, out var value2)) { Plugin.LogWarning("Failed to add item to reserved item slot. Item slot (" + key + ") does not exist. This is okay."); continue; } foreach (ReservedItemData item in value) { if (value2.ContainsItem(item.itemName)) { Plugin.LogWarning("Failed to add item to reserved item slot. Item already exists in slot. Item: " + item.itemName + " Item slot: " + key); } else { value2.AddItemToReservedItemSlot(item); } } } pendingAddReservedItemsToSlots.Clear(); } public static ReservedItemSlotData CreateReservedItemSlotData(string slotName, int slotPriority = 20, int purchasePrice = 200) { ReservedItemSlotData reservedItemSlotData = new ReservedItemSlotData(slotName, slotPriority, purchasePrice); ReservedItemSlotData value; bool flag = allReservedItemSlotData.TryGetValue(reservedItemSlotData.slotName, out value); ReservedItemSlotData value2; bool flag2 = allReservedItemSlotDataByPriority.TryGetValue(reservedItemSlotData.slotPriority, out value2); if (flag && flag2 && value == value2) { Plugin.LogWarning("Attempted to create a duplicate ReservedItemSlotData with the same name and priority as another. SlotName: " + slotName + ". Priority: " + slotPriority + ". ReservedSlot will not be created."); return reservedItemSlotData; } if (flag) { int num = 0; reservedItemSlotData.slotName = slotName + "_" + num; while (allReservedItemSlotData.ContainsKey(reservedItemSlotData.slotName)) { num++; reservedItemSlotData.slotName = slotName + "_" + num; } Plugin.LogWarning("Attempted to create a new ReservedItemSlotData (" + slotName + ") with the same priority as: " + value.slotName + ". Setting new slot name to: " + reservedItemSlotData.slotName); } if (flag2) { while (allReservedItemSlotDataByPriority.ContainsKey(reservedItemSlotData.slotPriority)) { reservedItemSlotData.slotPriority--; } Plugin.LogWarning("Attempted to create a new ReservedItemSlotData (" + slotName + ") with the same priority as: " + value2.slotName + ". Adjusting priority to: " + reservedItemSlotData.slotPriority); } allReservedItemSlotData.Add(reservedItemSlotData.slotName, reservedItemSlotData); allReservedItemSlotDataByPriority.Add(reservedItemSlotData.slotPriority, reservedItemSlotData); Plugin.Log("Created ReservedItemSlotData for: " + reservedItemSlotData.slotName + ". Slot priority: " + reservedItemSlotData.slotPriority); return reservedItemSlotData; } internal ReservedItemSlotData(string slotName, int slotPriority, int purchasePrice = 200) { this.slotName = slotName; this.slotPriority = slotPriority; this.purchasePrice = purchasePrice; slotDisplayName = slotName.Replace('_', ' ').Replace('-', ' ').Trim(new char[1] { ' ' }); slotDisplayName = char.ToUpper(slotDisplayName[0]) + slotDisplayName.Substring(1).ToLower(); } public ReservedItemData AddItemToReservedItemSlot(ReservedItemData itemData) { if (reservedItemData.ContainsKey(itemData.itemName)) { Plugin.LogWarning("Already added itemData to reserved item slot. Slot: " + slotName + " Item: " + itemData.itemName); return null; } reservedItemData.Add(itemData.itemName, itemData); itemData.AddToReservedItemSlot(this); return itemData; } public void RemoveItemFromReservedItemSlot(string itemName) { if (reservedItemData.ContainsKey(itemName)) { reservedItemData.Remove(itemName); } } public void RemoveItemFromReservedItemSlot(ReservedItemData itemData) { if (itemData != null && reservedItemData.ContainsKey(itemData.itemName)) { reservedItemData.Remove(itemData.itemName); } } public int GetReservedItemSlotIndex() { if (SessionManager.numReservedItemSlotsUnlocked > 0) { return SessionManager.unlockedReservedItemSlots.IndexOf(this); } return -1; } public bool ContainsItem(string itemName) { return itemName != null && reservedItemData != null && reservedItemData.ContainsKey(itemName); } public ReservedItemData GetReservedItemData(GrabbableObject grabbableObject) { if (grabbableObject?.itemProperties?.itemName == null) { return null; } string itemName = ItemNameMap.GetItemName(grabbableObject); ReservedItemData reservedItemData = GetReservedItemData(itemName); if (reservedItemData != null) { return reservedItemData; } return ((Object)(object)grabbableObject?.itemProperties != (Object)null) ? GetReservedItemData(grabbableObject.itemProperties.itemName) : null; } public ReservedItemData GetReservedItemData(Item item) { if (item?.itemName == null) { return null; } string itemName = ItemNameMap.GetItemName(item); ReservedItemData reservedItemData = GetReservedItemData(itemName); if (reservedItemData != null) { return reservedItemData; } return ((Object)(object)item != (Object)null) ? GetReservedItemData(item.itemName) : null; } public ReservedItemData GetReservedItemData(string itemName) { return (itemName != null && reservedItemData.ContainsKey(itemName)) ? reservedItemData[itemName] : null; } } [HarmonyPatch] public class ReservedPlayerData { public static Dictionary allPlayerData = new Dictionary(); public PlayerControllerB playerController; public ReservedItemData grabbingReservedItemData = null; public ReservedItemSlotData grabbingReservedItemSlotData = null; public GrabbableObject grabbingReservedItem = null; public int previousHotbarIndex = -1; public bool inReservedHotbarSlots = false; public int hotbarSize = 4; public int reservedHotbarStartIndex = 4; public BoneMap boneMap = new BoneMap(); public static ReservedPlayerData localPlayerData { get { ReservedPlayerData value; return ((Object)(object)StartOfRound.Instance?.localPlayerController != (Object)null && allPlayerData.TryGetValue(StartOfRound.Instance.localPlayerController, out value)) ? value : null; } } public bool isLocalPlayer => (Object)(object)playerController != (Object)null && (Object)(object)playerController == (Object)(object)StartOfRound.Instance?.localPlayerController; public int currentItemSlot => playerController.currentItemSlot; public GrabbableObject currentlySelectedItem => (itemSlots != null && currentItemSlot >= 0 && currentItemSlot < itemSlots.Length) ? itemSlots[currentItemSlot] : null; public bool currentItemSlotIsReserved => currentItemSlot >= reservedHotbarStartIndex && currentItemSlot < reservedHotbarStartIndex + SessionManager.numReservedItemSlotsUnlocked; public bool isGrabbingReservedItem => grabbingReservedItemData != null; public GrabbableObject previouslyHeldItem => (previousHotbarIndex >= 0 && previousHotbarIndex < playerController.ItemSlots.Length) ? playerController.ItemSlots[previousHotbarIndex] : null; public int reservedHotbarEndIndexExcluded => reservedHotbarStartIndex + SessionManager.numReservedItemSlotsUnlocked; public GrabbableObject[] itemSlots => playerController?.ItemSlots; public bool throwingObject => (bool)Traverse.Create((object)playerController).Field("throwingObject").GetValue(); public float timeSinceSwitchingSlots { get { return (float)Traverse.Create((object)playerController).Field("timeSinceSwitchingSlots").GetValue(); } set { Traverse.Create((object)playerController).Field("timeSinceSwitchingSlots").SetValue((object)value); } } public ReservedPlayerData(PlayerControllerB playerController) { this.playerController = playerController; boneMap.CreateBoneMap(((Component)((Component)playerController).transform).transform); } public bool IsReservedItemSlot(int itemSlotIndex) { return itemSlotIndex >= reservedHotbarStartIndex && itemSlotIndex < reservedHotbarStartIndex + SessionManager.numReservedItemSlotsUnlocked; } public int GetNumHeldReservedItems() { int num = 0; for (int i = reservedHotbarStartIndex; i < reservedHotbarEndIndexExcluded; i++) { GrabbableObject val = playerController.ItemSlots[i]; num += (((Object)(object)val != (Object)null) ? 1 : 0); } return num; } public GrabbableObject GetReservedItem(ReservedItemSlotData itemSlotData) { if (itemSlotData == null) { return null; } if (!SessionManager.TryGetUnlockedItemSlotData(itemSlotData.slotName, out itemSlotData)) { return null; } int indexInInventory = itemSlotData.GetIndexInInventory(this); if (indexInInventory < reservedHotbarStartIndex || indexInInventory >= reservedHotbarEndIndexExcluded) { return null; } if (indexInInventory < 0 || indexInInventory >= playerController.ItemSlots.Length) { return null; } return itemSlots[indexInInventory]; } public bool HasEmptySlotForReservedItem(GrabbableObject grabbableObject) { return (Object)(object)grabbableObject?.itemProperties != (Object)null && HasEmptySlotForReservedItem(grabbableObject.itemProperties.itemName); } public bool HasEmptySlotForReservedItem(string itemName) { if (!SessionManager.TryGetUnlockedItemData(itemName, out var itemData) || !itemData.HasUnlockedParentSlot()) { return false; } for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++) { ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i); if (unlockedReservedItemSlot.ContainsItem(itemName)) { int num = i + reservedHotbarStartIndex; if (num >= playerController.ItemSlots.Length) { return false; } if ((Object)(object)playerController.ItemSlots[num] == (Object)null) { return true; } } } return false; } public ReservedItemSlotData GetFirstEmptySlotForReservedItem(GrabbableObject grabbableObject) { return ((Object)(object)grabbableObject?.itemProperties != (Object)null) ? GetFirstEmptySlotForReservedItem(grabbableObject.itemProperties.itemName) : null; } public ReservedItemSlotData GetFirstEmptySlotForReservedItem(string itemName) { for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++) { ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i); if (unlockedReservedItemSlot.ContainsItem(itemName)) { int num = i + reservedHotbarStartIndex; if (num < 0 || num >= playerController.ItemSlots.Length) { return null; } if ((Object)(object)playerController.ItemSlots[num] == (Object)null) { return unlockedReservedItemSlot; } } } return null; } public ReservedItemSlotData GetParentReservedItemSlot(GrabbableObject grabbableObject) { if ((Object)(object)grabbableObject == (Object)null) { return null; } for (int i = reservedHotbarStartIndex; i < reservedHotbarEndIndexExcluded; i++) { GrabbableObject val = itemSlots[i]; if ((Object)(object)grabbableObject == (Object)(object)val) { int indexInUnlockedItemSlots = i - reservedHotbarStartIndex; return SessionManager.GetUnlockedReservedItemSlot(indexInUnlockedItemSlots); } } return null; } public ReservedItemSlotData GetCurrentlySelectedReservedItemSlot() { if (currentItemSlotIsReserved) { int num = currentItemSlot - reservedHotbarStartIndex; if (num >= 0 && num < SessionManager.numReservedItemSlotsUnlocked) { return SessionManager.GetUnlockedReservedItemSlot(num); } } return null; } public bool IsItemInReservedItemSlot(GrabbableObject grabbableObject) { if ((Object)(object)grabbableObject == (Object)null) { return false; } if (reservedHotbarStartIndex < 0 || reservedHotbarEndIndexExcluded - 1 >= itemSlots.Length) { Plugin.LogError("Failed to check if item was in reserved item slot. Start or end reserved item slot index was outside the bounds of the player's item slots. Start index: " + reservedHotbarStartIndex + " EndIndex: " + (reservedHotbarEndIndexExcluded - 1) + " InventorySize: " + itemSlots.Length); Plugin.LogError("Reporting this to Flip would be greatly appreciated :)"); return false; } for (int i = reservedHotbarStartIndex; i < reservedHotbarEndIndexExcluded; i++) { if ((Object)(object)grabbableObject == (Object)(object)itemSlots[i]) { return true; } } return false; } internal int CallGetNextItemSlot(bool forward) { MethodInfo method = ((object)playerController).GetType().GetMethod("NextItemSlot", BindingFlags.Instance | BindingFlags.NonPublic); return (int)method.Invoke(playerController, new object[1] { forward }); } internal void CallSwitchToItemSlot(int index, GrabbableObject fillSlotWithItem = null) { MethodInfo method = ((object)playerController).GetType().GetMethod("SwitchToItemSlot", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(playerController, new object[2] { index, fillSlotWithItem }); timeSinceSwitchingSlots = 0f; } } } namespace ReservedItemSlotCore.Config { public static class ConfigSettings { public static ConfigEntry enablePurchasingItemSlots; public static ConfigEntry globalItemSlotPriceModifier; public static ConfigEntry forceEnableThisModIfNotEnabledOnHost; public static ConfigEntry displayNegativePrioritySlotsLeftSideOfScreen; public static ConfigEntry hideEmptyReservedItemSlots; public static ConfigEntry preventReservedItemSlotFade; public static ConfigEntry hideFocusHotbarTooltip; public static ConfigEntry showReservedItemsHolstered; public static ConfigEntry showReservedItemsHolsteredMaskedEnemy; public static ConfigEntry applyHotbarPlusItemSlotSize; public static ConfigEntry disableHotbarPlusEnergyBars; public static ConfigEntry verboseLogs; public static ConfigEntry numCustomItemSlots; public static List customItemSlotConfigs = new List(); public static Dictionary currentConfigEntries = new Dictionary(); public static void BindConfigSettings() { Plugin.Log("BindingConfigs"); enablePurchasingItemSlots = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Server", "EnablePurchasingItemSlots", false, "[Host only] Set to true to enable purchasing reserved item slots. If set to false, all players will start the game with all available reserved item slots.")); globalItemSlotPriceModifier = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Server", "GlobalItemSlotPriceModifier", 1f, "[Host only] All reserved item slot prices will scale with this value.")); forceEnableThisModIfNotEnabledOnHost = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "ForceEnableThisModIfNotEnabledOnHost", false, "This is disabled by default for a reason, and it is NOT recommended to enable this, especially in public lobbies. Enabling this while the host does not have the ReservedItemSlotCore mod CAN, and likely WILL cause de-sync issues.\nNOTE: If enabled, you will not receive any reserved item slots until the game has started.\nThis setting only applies if you are a non-host client, and the host does not have this mod.")); displayNegativePrioritySlotsLeftSideOfScreen = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "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.")); hideEmptyReservedItemSlots = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "HideEmptyReservedItemSlots", false, "If true, all empty reserved item slots will be hidden from the HUD. This is a new config setting and might have bugs.")); preventReservedItemSlotFade = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "PreventReservedHotbarSlotFade", false, "If true, the reserved hotbar slots will not fade with the rest of the default slots. Currently, the reserved hotbar slots will never fade while you're in the slots.")); hideFocusHotbarTooltip = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "HideFocusHotbarTooltip", false, "This tooltip is shown next to the first reserved item slot.")); showReservedItemsHolstered = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "ShowReservedItemsHolsteredOnPlayers", true, "If true, held items in the reserved item slots that are not currently in the player's hand, will be shown holstered on the player. Example: The reserved flashlight will show up on the player's shoulder when not in their hands. This will do nothing for items that do not have a defined holstered location on the player.")); showReservedItemsHolsteredMaskedEnemy = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Client-side", "ShowReservedItemsHolsteredOnMaskedEnemies", true, "If true, masked enemies will appear to have reserved items holstered when mimicking a player. The items shown will be the same items that the player, who the masked enemy is mimicking, has in their inventory. This will do nothing for items that do not have a defined holstered location on the player.")); applyHotbarPlusItemSlotSize = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Compatibility", "ApplyHotbarPlusItemSlotSize", true, "If true, the reserved item slot SIZE will be a adjusted by HotbarPlus's formatting settings.\nThis will not do anything if HotbarPlus is not enabled.")); disableHotbarPlusEnergyBars = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Compatibility", "DisableHotbarPlusEnergyBars", false, "Disables/hides the energy bars from HotbarPlus from the reserved item slots (HUD).\nThis will not do anything if HotbarPlus is not enabled.")); numCustomItemSlots = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Custom Reserved Item Slots", "NumCustomItemSlots", 0, "[Host only] Set the number of custom reserved item slots you want to add. Custom slots will update in the config when you start the game. LIMITED TO 10")); verboseLogs = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("Other", "VerboseLogs", true, "If enabled, extra logs will be created for debugging. This may be useful for tracking down various issues.")); numCustomItemSlots.Value = Mathf.Clamp(numCustomItemSlots.Value, 0, 10); for (int i = 0; i < numCustomItemSlots.Value; i++) { ConfigEntry val = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("CustomReservedItemSlot " + (i + 1), "ItemSlotName " + (i + 1), "custom_item_slot_" + (i + 1), "[Host only] Make the name of this slot unique. This name is usually only seen in the terminal. This slot will not be created if left blank.")); ConfigEntry val2 = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("CustomReservedItemSlot " + (i + 1), "ItemsInSlot " + (i + 1), "", "[Host only] Syntax: \"Flashlight,Walkie-talkie\" (without quotes). When adding items, use the item's name as it appears in game. The names are CASE-SENSITIVE. Include spaces if there are spaces in the item name. Adding items that do not exist, or that are from a mod which is not enabled will not cause any problems. As of now, additional items added to reserved item slots cannot be seen on players while holstered.")); ConfigEntry val3 = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("CustomReservedItemSlot " + (i + 1), "ItemSlotPriority " + (i + 1), 20, "[Host only] Manually set the priority for this item slot. Higher priority slots will come first in the reserved item slots, which will appear below the other slots. Negative priority items will appear on the left side of the screen, this is disabled in the core mod's config.")); ConfigEntry val4 = AddConfigEntry(((BaseUnityPlugin)Plugin.instance).Config.Bind("CustomReservedItemSlot " + (i + 1), "ItemSlotPrice " + (i + 1), 0, "[Host only] Only applies if purchasing item slots in the terminal is enabled in the core config. Setting 0 will force this item to be unlocked immediately after the game starts.")); CustomItemSlotConfigEntry customItemSlotConfigEntry = new CustomItemSlotConfigEntry(val.Value, ParseItemNames(val2.Value), val3.Value, val4.Value); if (customItemSlotConfigEntry.customItemSlotName != "" && customItemSlotConfigEntry.customItemSlotItems.Length != 0) { customItemSlotConfigs.Add(customItemSlotConfigEntry); } } TryRemoveOldConfigSettings(); } public static string[] ParseItemNames(string itemNamesRaw) { if (itemNamesRaw == "") { return new string[0]; } itemNamesRaw = itemNamesRaw.Replace(", ", ","); List source = new List(itemNamesRaw.Split(new char[1] { ',' })); source = source.Where((string s) => s.Length >= 1).ToList(); return source.ToArray(); } public static ConfigEntry AddConfigEntry(ConfigEntry configEntry) { currentConfigEntries.Add(((ConfigEntryBase)configEntry).Definition.Key, (ConfigEntryBase)(object)configEntry); return configEntry; } public static void TryRemoveOldConfigSettings() { HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); foreach (ConfigEntryBase value in currentConfigEntries.Values) { hashSet.Add(value.Definition.Section); hashSet2.Add(value.Definition.Key); } try { 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 { } } } public class CustomItemSlotConfigEntry { public string customItemSlotName; public string[] customItemSlotItems; public int customItemSlotPriority; public int customItemSlotPrice; public CustomItemSlotConfigEntry(string customItemSlotName, string[] customItemSlotItems, int customItemSlotPriority, int customItemSlotPrice) { this.customItemSlotName = customItemSlotName; this.customItemSlotItems = customItemSlotItems; this.customItemSlotPriority = customItemSlotPriority; this.customItemSlotPrice = customItemSlotPrice; } } } namespace ReservedItemSlotCore.Compatibility { internal static class GeneralImprovements_Patcher { public static bool Enabled => Plugin.IsModLoaded("ShaosilGaming.GeneralImprovements"); public static void AddLightningIndicatorToItemSlotFrame(Image itemSlotFrame) { } } internal static class AdvancedCompany_Patcher { public static bool Enabled => Plugin.IsModLoaded("com.potatoepet.AdvancedCompany"); } internal static class HotbarPlus_Compat { public static bool Enabled => Plugin.IsModLoaded("FlipMods.HotbarPlus"); } [HarmonyPatch] internal static class LCVR_Compat { internal static bool vrPlayerScrollingBetweenHotbars = false; internal static int vrPlayerNextItemSlot = -1; internal static bool Loaded => Plugin.IsModLoaded("io.daxcess.lcvr"); internal static bool VRModeEnabled => VRSession.InVR; public static bool LoadedAndEnabled => Loaded && VRModeEnabled; private static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool OnVRPlayerScrollPre(CallbackContext context, PlayerControllerB __instance) { if (vrPlayerScrollingBetweenHotbars) { return false; } if (!LoadedAndEnabled || (Object)(object)__instance != (Object)(object)localPlayerController) { return true; } if (PlayerPatcher.reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var _)) { return true; } vrPlayerScrollingBetweenHotbars = true; vrPlayerNextItemSlot = -1; return true; } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPostfix] public static void OnVRPlayerScrollPost(CallbackContext context, PlayerControllerB __instance) { if ((Object)(object)__instance == (Object)(object)localPlayerController && vrPlayerScrollingBetweenHotbars) { vrPlayerScrollingBetweenHotbars = false; if (LoadedAndEnabled && vrPlayerNextItemSlot != -1 && ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value)) { Keybinds.pressedToggleKey = true; ReservedHotbarManager.FocusReservedHotbarSlots(!value.inReservedHotbarSlots, vrPlayerNextItemSlot); vrPlayerNextItemSlot = -1; } } } [HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")] [HarmonyPostfix] public static void OnNextItemSlot(ref int __result, bool forward, PlayerControllerB __instance) { vrPlayerNextItemSlot = -1; if (PlayerPatcher.reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value)) { return; } bool inReservedHotbarSlots = value.inReservedHotbarSlots; bool flag = value.IsReservedItemSlot(__result); if (LoadedAndEnabled && (Object)(object)__instance == (Object)(object)localPlayerController && vrPlayerScrollingBetweenHotbars) { if (inReservedHotbarSlots != flag) { vrPlayerNextItemSlot = __result; } else { vrPlayerScrollingBetweenHotbars = false; } } } [HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")] [HarmonyPatch(typeof(PlayerControllerB), "SwitchItemSlotsServerRpc")] [HarmonyPrefix] public static bool OnSwitchToItemSlot(PlayerControllerB __instance) { if (LoadedAndEnabled && (Object)(object)__instance == (Object)(object)localPlayerController && vrPlayerScrollingBetweenHotbars) { return false; } return true; } } internal static class TooManyEmotes_Compat { public static bool Enabled => Plugin.IsModLoaded("FlipMods.TooManyEmotes"); public static bool IsLocalPlayerPerformingCustomEmote() { if ((Object)(object)EmoteControllerPlayer.emoteControllerLocal != (Object)null && ((EmoteController)EmoteControllerPlayer.emoteControllerLocal).IsPerformingCustomEmote()) { return true; } return false; } public static bool CanMoveWhileEmoting() { return false; } public static bool IsEmoteMenuOpen() { return EmoteMenu.isMenuOpen; } [HarmonyPatch(typeof(ThirdPersonEmoteController), "OnStartCustomEmoteLocal")] [HarmonyPostfix] public static void OnStartTMEEmote() { ReservedPlayerData localPlayerData = ReservedPlayerData.localPlayerData; for (int i = localPlayerData.reservedHotbarStartIndex; i < localPlayerData.reservedHotbarEndIndexExcluded; i++) { if (i >= localPlayerData.itemSlots.Length) { Plugin.LogWarning("Failed to patch TooManyEmotes OnStartCustomEmoteLocal. Likely a separate mod conflicting, but this should only prevent your held reserved items from displaying during emotes."); continue; } GrabbableObject val = localPlayerData.itemSlots[i]; if (!Object.op_Implicit((Object)(object)val) || !SessionManager.TryGetUnlockedItemData(val, out var itemData) || !localPlayerData.IsItemInReservedItemSlot(val) || !itemData.showOnPlayerWhileHolstered || !((Object)(object)val != (Object)(object)localPlayerData.currentlySelectedItem)) { continue; } MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(); foreach (MeshRenderer val2 in componentsInChildren) { if (!((Component)val2).gameObject.CompareTag("DoNotSet") && !((Component)val2).gameObject.CompareTag("InteractTrigger") && ReservedItemsPatcher.previousObjectLayers.TryGetValue(((Component)val2).gameObject, out var value) && !ReservedItemsPatcher.IsLayerInLocalCameraMask(((Component)val2).gameObject.layer)) { ((Component)val2).gameObject.layer = value; } } } } [HarmonyPatch(typeof(ThirdPersonEmoteController), "OnStopCustomEmoteLocal")] [HarmonyPostfix] public static void OnStopTMEEmote() { ReservedPlayerData localPlayerData = ReservedPlayerData.localPlayerData; for (int i = localPlayerData.reservedHotbarStartIndex; i < localPlayerData.reservedHotbarEndIndexExcluded; i++) { if (i >= localPlayerData.itemSlots.Length) { continue; } GrabbableObject val = localPlayerData.itemSlots[i]; if (!Object.op_Implicit((Object)(object)val) || !SessionManager.TryGetUnlockedItemData(val, out var itemData) || !localPlayerData.IsItemInReservedItemSlot(val) || !itemData.showOnPlayerWhileHolstered || !((Object)(object)val != (Object)(object)localPlayerData.currentlySelectedItem)) { continue; } MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(); foreach (MeshRenderer val2 in componentsInChildren) { if (!((Component)val2).gameObject.CompareTag("DoNotSet") && !((Component)val2).gameObject.CompareTag("InteractTrigger") && ReservedItemsPatcher.previousObjectLayers.TryGetValue(((Component)val2).gameObject, out var _) && ReservedItemsPatcher.IsLayerInLocalCameraMask(((Component)val2).gameObject.layer)) { ((Component)val2).gameObject.layer = 23; } } } } } }