Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ReservedItemSlotCore v2.0.55
ReservedItemSlotCore.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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<string, Item> originalNameToItemMap = new Dictionary<string, Item>(); private static Dictionary<Item, string> itemToNameMap = new Dictionary<Item, string>(); [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPrefix] private static void RecordOriginalItemNames(StartOfRound __instance) { List<Item> list = __instance?.allItemsList?.itemsList; if (list == null) { Plugin.LogError("Failed to record original item names. This might be fine if you're not using translation/localization mods. (no guarantees)"); return; } foreach (Item item in list) { string text = item?.itemName; if (!string.IsNullOrEmpty(text)) { if (!itemToNameMap.ContainsKey(item)) { itemToNameMap.Add(item, text); } if (!originalNameToItemMap.ContainsKey(text)) { originalNameToItemMap.Add(text, item); } } } } internal static string GetItemName(GrabbableObject grabbableObject) { if ((Object)(object)grabbableObject?.itemProperties == (Object)null) { return ""; } string itemName = GetItemName(grabbableObject.itemProperties); 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<ReservedItemSlotData> customItemSlots = new List<ReservedItemSlotData>(); 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<Type> enumerable; try { enumerable = Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException ex) { enumerable = ex.Types.Where((Type t) => t != null); } foreach (Type item in enumerable) { try { _harmony.PatchAll(item); } catch { } } } private void CreateCustomLogger() { try { logger = Logger.CreateLogSource(string.Format("{0}-{1}", "ReservedItemSlotCore", "2.0.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<ReservedItemSlotData> currentlyToggledItemSlots = new List<ReservedItemSlotData>(); public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData; public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked; public static bool isToggledInReservedSlots { get { ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot(); 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<ReservedItemSlotData>(); ReservedPlayerData.allPlayerData.Clear(); indexInHotbar = 0; indexInReservedHotbar = -1; } public static void ForceToggleReservedHotbar(params ReservedItemSlotData[] reservedItemSlots) { if (((NetworkBehaviour)localPlayerController).IsOwner && localPlayerController.isPlayerControlled && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject) && HUDPatcher.hasReservedItemSlotsAndEnabled && reservedHotbarSize > 0 && CanSwapHotbars() && reservedItemSlots != null && reservedItemSlots.Length != 0 && !((Object)(object)localPlayerController == (Object)null)) { currentlyToggledItemSlots = new List<ReservedItemSlotData>(reservedItemSlots); int num = currentlyToggledItemSlots.First().GetReservedItemSlotIndex() + localPlayerData.reservedHotbarStartIndex; bool active = ReservedPlayerData.localPlayerData.IsReservedItemSlot(num); if (currentlyToggledItemSlots.Contains(localPlayerData.GetCurrentlySelectedReservedItemSlot())) { FocusReservedHotbarSlots(active: false); return; } HUDPatcher.UpdateToggledReservedItemSlotsUI(); FocusReservedHotbarSlots(active, num); } } public static void FocusReservedHotbarSlots(bool active, int forceSlot = -1) { if (!HUDPatcher.hasReservedItemSlotsAndEnabled || (reservedHotbarSize <= 0 && active) || (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved == active && (forceSlot == -1 || localPlayerData.currentItemSlot == forceSlot))) { return; } if (forceSlot != -1) { active = localPlayerData.IsReservedItemSlot(forceSlot); } ReservedPlayerData reservedPlayerData = ReservedPlayerData.localPlayerData; indexInHotbar = Mathf.Clamp(indexInHotbar, 0, localPlayerController.ItemSlots.Length - 1); indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0); indexInReservedHotbar = Mathf.Clamp(indexInReservedHotbar, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1); int num = Mathf.Clamp(localPlayerController.currentItemSlot, 0, localPlayerController.ItemSlots.Length); int i = num; bool flag = active; if (flag && (!reservedPlayerData.IsReservedItemSlot(num) || forceSlot != -1)) { indexInHotbar = num; indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0); if (forceSlot != -1 && reservedPlayerData.IsReservedItemSlot(forceSlot)) { indexInReservedHotbar = forceSlot; } i = indexInReservedHotbar; if (!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<CanvasGroup>(); 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<CanvasGroup>(); if ((Object)(object)component != (Object)null) { component.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value; } } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPrefix] private static void RefocusReservedHotbarAfterAnimation(PlayerControllerB __instance) { if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !Keybinds.pressedToggleKey && Keybinds.holdingModifierKey != ReservedPlayerData.localPlayerData.currentItemSlotIsReserved && !isToggledInReservedSlots && CanSwapHotbars()) { FocusReservedHotbarSlots(Keybinds.holdingModifierKey); } } [HarmonyPatch(typeof(PlayerControllerB), "UpdateSpecialAnimationValue")] [HarmonyPostfix] private static void UpdateReservedHotbarAfterAnimation(bool specialAnimation, PlayerControllerB __instance) { if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !specialAnimation && !Keybinds.pressedToggleKey && ReservedPlayerData.localPlayerData.currentItemSlotIsReserved != Keybinds.holdingModifierKey) { FocusReservedHotbarSlots(Keybinds.holdingModifierKey); } } } [HarmonyPatch] public static class SessionManager { [CompilerGenerated] private sealed class <>c__DisplayClass25_0 { public bool force; } internal static List<ReservedItemSlotData> unlockedReservedItemSlots = new List<ReservedItemSlotData>(); internal static Dictionary<string, ReservedItemSlotData> unlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>(); internal static List<ReservedItemSlotData> pendingUnlockedReservedItemSlots = new List<ReservedItemSlotData>(); internal static Dictionary<string, ReservedItemSlotData> pendingUnlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>(); private static Dictionary<string, ReservedItemData> allReservedItemData = new Dictionary<string, ReservedItemData>(); internal static bool gameStarted = false; internal static List<ReservedItemSlotData> allUnlockableReservedItemSlots => SyncManager.unlockableReservedItemSlots; internal static Dictionary<string, ReservedItemSlotData> allUnlockableReservedItemSlotsDict => SyncManager.unlockableReservedItemSlotsDict; public static int numReservedItemSlotsUnlocked => (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<GrabbableObject> list = new List<GrabbableObject>(value.itemSlots); list.Insert(index, null); value.playerController.ItemSlots = list.ToArray(); value.hotbarSize = list.Count; } } } if (ReservedHotbarManager.indexInReservedHotbar < ReservedPlayerData.localPlayerData.reservedHotbarStartIndex || ReservedHotbarManager.indexInReservedHotbar >= ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded) { ReservedHotbarManager.indexInReservedHotbar = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex; } UpdateReservedItemsList(); HUDPatcher.OnUpdateReservedItemSlots(); } internal static void UnlockAllPendingItemSlots() { foreach (ReservedItemSlotData pendingUnlockedReservedItemSlot in pendingUnlockedReservedItemSlots) { UnlockReservedItemSlot(pendingUnlockedReservedItemSlot); } pendingUnlockedReservedItemSlots.Clear(); pendingUnlockedReservedItemSlotsDict.Clear(); } public static ReservedItemSlotData GetUnlockedReservedItemSlot(int indexInUnlockedItemSlots) { 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<GrabbableObject> list = new List<GrabbableObject>(); for (int i = 0; i < itemSlots.Length; i++) { if (i < value.reservedHotbarStartIndex || i >= value.reservedHotbarEndIndexExcluded) { list.Add(itemSlots[i]); } } value.playerController.ItemSlots = list.ToArray(); } unlockedReservedItemSlots?.Clear(); unlockedReservedItemSlotsDict?.Clear(); pendingUnlockedReservedItemSlots?.Clear(); pendingUnlockedReservedItemSlotsDict?.Clear(); List<Image> list2 = new List<Image>(); List<Image> list3 = new List<Image>(); for (int j = 0; j < HUDManager.Instance.itemSlotIconFrames.Length; j++) { Image val = HUDManager.Instance.itemSlotIconFrames[j]; Image item = HUDManager.Instance.itemSlotIcons[j]; if (!HUDPatcher.reservedItemSlots.Contains(val)) { list2.Add(val); list3.Add(item); } else { Object.Destroy((Object)(object)((Component)val).gameObject); } } HUDPatcher.reservedItemSlots.Clear(); HUDManager.Instance.itemSlotIconFrames = list2.ToArray(); HUDManager.Instance.itemSlotIcons = list3.ToArray(); foreach (ReservedPlayerData value2 in ReservedPlayerData.allPlayerData.Values) { if (value2.playerController.currentItemSlot < 0 || value2.playerController.currentItemSlot >= value2.playerController.ItemSlots.Length) { PlayerPatcher.SwitchToItemSlot(value2.playerController, 0); } value2.hotbarSize = value2.itemSlots.Length; value2.reservedHotbarStartIndex = value2.hotbarSize; } foreach (ReservedItemSlotData allUnlockableReservedItemSlot in allUnlockableReservedItemSlots) { if (allUnlockableReservedItemSlot.purchasePrice <= 0) { UnlockReservedItemSlot(allUnlockableReservedItemSlot); } } 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.<<ResetProgressDelayed>g__Reset|0>d))] IEnumerator Reset() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d(0) { <>4__this = CS$<>8__locals0 }; } } internal static void SaveGameValues() { if (!NetworkManager.Singleton.IsServer || unlockedReservedItemSlots == null) { return; } List<string> list = new List<string>(); foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots) { if (!list.Contains(unlockedReservedItemSlot.slotName)) { list.Add(unlockedReservedItemSlot.slotName); } } Plugin.LogWarning("Saving " + list.Count + " unlocked reserved item slots."); string[] array = list.ToArray(); ES3.Save<string[]>("ReservedItemSlots.UnlockedItemSlots", array, GameNetworkManager.Instance.currentSaveFileName); } internal static void LoadGameValues() { if (!NetworkManager.Singleton.IsServer || SyncManager.unlockableReservedItemSlotsDict == null) { return; } string[] array = ES3.Load<string[]>("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName, new string[0]); Plugin.LogWarning("Loading " + array.Length + " unlocked reserved item slots."); int num = 0; string[] array2 = array; foreach (string key in array2) { if (SyncManager.unlockableReservedItemSlotsDict.TryGetValue(key, out var value)) { num++; UnlockReservedItemSlot(value); SyncManager.SendUnlockItemSlotToClients(value.slotId); } } Plugin.Log("Loaded " + num + " unlocked reserved items."); } public static bool IsReservedItem(GrabbableObject grabbableObject) { 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 <SwitchToItemSlotAfterDelay>b__0() { return (Object)(object)playerController.currentlyHeldObjectServer == (Object)null || Time.time - time >= 5f; } } [CompilerGenerated] private sealed class <SwitchToItemSlotAfterDelay>d__9 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PlayerControllerB playerController; public int slot; private <>c__DisplayClass9_0 <>8__1; private ReservedPlayerData <playerData>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SwitchToItemSlotAfterDelay>d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <playerData>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<bool>)(() => (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 <playerData>5__2)) { <playerData>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<PlayerControllerB> playersDiscardingItems = new HashSet<PlayerControllerB>(); 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(<SwitchToItemSlotAfterDelay>d__9))] private static IEnumerator SwitchToItemSlotAfterDelay(PlayerControllerB playerController, int slot) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SwitchToItemSlotAfterDelay>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<Image> reservedItemSlots = new List<Image>(); public static HashSet<ReservedItemSlotData> toggledReservedItemSlots = new HashSet<ReservedItemSlotData>(); private static bool lerpToggledItemSlotFrames = false; private static float largestPositionDifference = 0f; private static bool currentApplyHotbarPlusSize; private static bool currentHideEmptySlots; 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<CanvasScaler>(); AspectRatioFitter componentInParent2 = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<AspectRatioFitter>(); itemSlotWidth = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta.x; itemSlotSpacing = 1.125f * itemSlotWidth; defaultItemSlotPosX = componentInParent.referenceResolution.x / 2f / componentInParent2.aspectRatio - itemSlotWidth / 4f; defaultItemSlotSpacing = itemSlotSpacing; defaultItemSlotSize = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta; defaultItemIconSize = ((Graphic)__instance.itemSlotIcons[0]).rectTransform.sizeDelta; defaultItemSlotPosY = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.anchoredPosition.y; reservedItemSlots.Clear(); } [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<Image> list = new List<Image>(HUDManager.Instance.itemSlotIconFrames); List<Image> list2 = new List<Image>(HUDManager.Instance.itemSlotIcons); for (int i = reservedItemSlots.Count; i < SessionManager.numReservedItemSlotsUnlocked; i++) { GameObject val = Object.Instantiate<GameObject>(((Component)list[0]).gameObject, ((Component)list[0]).transform.parent); Image component = val.GetComponent<Image>(); Image component2 = ((Component)((Component)component).transform.GetChild(0)).GetComponent<Image>(); ((Component)component).transform.localScale = ((Component)list[0]).transform.localScale; ((Transform)((Graphic)component).rectTransform).eulerAngles = ((Transform)((Graphic)list[0]).rectTransform).eulerAngles; ((Transform)((Graphic)component2).rectTransform).eulerAngles = ((Transform)((Graphic)list2[0]).rectTransform).eulerAngles; CanvasGroup val2 = ((Component)component).gameObject.AddComponent<CanvasGroup>(); 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<TextMeshProUGUI>(); } 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<ReservedItemSlotData>(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<GameObject>(((Component)val).gameObject, bone); val2.transform.localEulerAngles = reservedItemData.holsteredRotationOffset; val2.transform.localPosition = reservedItemData.holsteredPositionOffset; val2.transform.localScale = ((Component)val).transform.localScale; val2.layer = 6; MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val3 in componentsInChildren) { if (!((Object)val3).name.Contains("ScanNode") && !((Component)val3).gameObject.CompareTag("DoNotSet") && !((Component)val3).gameObject.CompareTag("InteractTrigger")) { ((Component)val3).gameObject.layer = 6; } } if (val is FlashlightItem) { Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>(); foreach (Light val4 in componentsInChildren2) { ((Behaviour)val4).enabled = false; } } else { Light[] componentsInChildren3 = val2.GetComponentsInChildren<Light>(); foreach (Light val5 in componentsInChildren3) { ((Behaviour)val5).enabled = true; } } GrabbableObject componentInChildren = val2.GetComponentInChildren<GrabbableObject>(); 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<NetworkObject>()); Collider[] componentsInChildren4 = val2.GetComponentsInChildren<Collider>(); foreach (Collider val7 in componentsInChildren4) { Object.DestroyImmediate((Object)(object)val7); } MonoBehaviour[] componentsInChildren5 = val2.GetComponentsInChildren<MonoBehaviour>(); 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<float>() > 0f; } } [HarmonyPatch(typeof(PlayerControllerB), "SwitchItemSlotsServerRpc")] [HarmonyPrefix] public static void CorrectReservedScrollDirectionServerRpc(ref bool forward) { if (Keybinds.scrollingReservedHotbar) { forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f; } } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool PreventInvertedScrollingReservedHotbar(CallbackContext context) { if (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<PlayerControllerB, ReservedPlayerData> 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<GrabbableObject>(); 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<GrabbableObject>(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<GrabbableObject>(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<Animator>().SetBool("selectedSlot", false); ((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().SetBool("selectedSlot", true); ((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().Play("PanelLines", 0, 1f); ((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().Play("PanelEnlarge", 0, 1f); } else { SwitchToItemSlot(__instance, value.previousHotbarIndex); 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.<<OnReservedItemGrabbed>g__OnReservedItemGrabbedEndOfFrame|0>d))] IEnumerator OnReservedItemGrabbedEndOfFrame() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass20_0.<<OnReservedItemGrabbed>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<GameObject, int> previousObjectLayers = new Dictionary<GameObject, int>(); 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<MeshRenderer>(); 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<MeshRenderer>(); 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<MeshRenderer>(); 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<NetworkObjectReference> list = new List<NetworkObjectReference>(gObjects); List<int> list2 = new List<int>(playersHeldBy); List<int> list3 = new List<int>(itemSlotNumbers); List<int> list4 = new List<int>(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