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 PlusNonScrapSlots v1.0.7
BepInEx/plugins/ReservedItemSlotCore.dll
Decompiled 6 months 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 ReservedItemSlotCore.Compatibility; using ReservedItemSlotCore.Config; using ReservedItemSlotCore.Data; using ReservedItemSlotCore.Input; using ReservedItemSlotCore.Networking; using ReservedItemSlotCore.Patches; using TMPro; using TooManyEmotes; using TooManyEmotes.Patches; using TooManyEmotes.UI; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ReservedItemSlotCore")] [assembly: AssemblyDescription("Mod made by flipf17")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ReservedItemSlotCore")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("238ce080-e339-46b6-9b08-992a950453a1")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: InternalsVisibleTo("ReservedFlashlightSlot")] [assembly: InternalsVisibleTo("ReservedWalkieSlot")] [assembly: InternalsVisibleTo("ReservedWeaponSlot")] [assembly: InternalsVisibleTo("ReservedSprayPaintSlot")] [assembly: InternalsVisibleTo("ReservedUtilitySlot")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] internal static class LethalConfigHelper { private static bool _registered = false; private static readonly Dictionary<ConfigEntryBase, object> _lcTxtOptsByEntry = new Dictionary<ConfigEntryBase, object>(); private static readonly Dictionary<ConfigEntryBase, object> _lcTxtItemByEntry = new Dictionary<ConfigEntryBase, object>(); internal static void TryRegisterColorDisplay(ConfigEntry<string> colorEntry, string effectiveHex) { Type type = Type.GetType("LethalConfig.LethalConfigManager, LethalConfig"); if (type == null) { return; } try { string text = "Current saved color:\n<b>" + effectiveHex + "</b>"; MethodInfo methodInfo = null; Type type2 = Type.GetType("LethalConfig.ConfigItems.BaseConfigItem, LethalConfig"); if (type2 != null) { methodInfo = type.GetMethod("AddConfigItem", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type2 }, null); } if (methodInfo == null) { methodInfo = Array.Find(type.GetMethods(BindingFlags.Static | BindingFlags.Public), (MethodInfo m) => m.Name == "AddConfigItem" && m.GetParameters().Length == 1); } bool flag = false; if (!_registered) { Type type3 = Type.GetType("LethalConfig.ConfigItems.Options.TextInputFieldOptions, LethalConfig"); Type type4 = Type.GetType("LethalConfig.ConfigItems.TextInputFieldConfigItem, LethalConfig"); if (type3 != null && type4 != null && methodInfo != null) { object obj = Activator.CreateInstance(type3); type3.GetProperty("Section")?.SetValue(obj, ((ConfigEntryBase)colorEntry).Definition.Section); type3.GetProperty("Name")?.SetValue(obj, ((ConfigEntryBase)colorEntry).Definition.Key); ConfigDescription description = ((ConfigEntryBase)colorEntry).Description; string text2 = ((description != null) ? description.Description : null) ?? ""; type3.GetProperty("Description")?.SetValue(obj, string.IsNullOrWhiteSpace(text2) ? text : (text2 + "\n\n" + text)); type3.GetProperty("RequiresRestart")?.SetValue(obj, false); object obj2 = Activator.CreateInstance(type4, colorEntry, obj); methodInfo.Invoke(null, new object[1] { obj2 }); flag = true; _lcTxtOptsByEntry[(ConfigEntryBase)(object)colorEntry] = obj; _lcTxtItemByEntry[(ConfigEntryBase)(object)colorEntry] = obj2; } } else { if (_lcTxtOptsByEntry.TryGetValue((ConfigEntryBase)(object)colorEntry, out var value)) { ConfigDescription description2 = ((ConfigEntryBase)colorEntry).Description; string text3 = ((description2 != null) ? description2.Description : null) ?? ""; string value2 = (string.IsNullOrWhiteSpace(text3) ? text : (text3 + "\n\n" + text)); value.GetType().GetProperty("Description")?.SetValue(value, value2); if (_lcTxtItemByEntry.TryGetValue((ConfigEntryBase)(object)colorEntry, out var value3)) { value3.GetType().GetMethod("ApplyChanges", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(value3, null); } } else { Type type5 = Type.GetType("LethalConfig.ConfigItems.Options.TextInputFieldOptions, LethalConfig"); Type type6 = Type.GetType("LethalConfig.ConfigItems.TextInputFieldConfigItem, LethalConfig"); if (type5 != null && type6 != null && methodInfo != null) { object obj3 = Activator.CreateInstance(type5); type5.GetProperty("Section")?.SetValue(obj3, ((ConfigEntryBase)colorEntry).Definition.Section); type5.GetProperty("Name")?.SetValue(obj3, ((ConfigEntryBase)colorEntry).Definition.Key); ConfigDescription description3 = ((ConfigEntryBase)colorEntry).Description; string text4 = ((description3 != null) ? description3.Description : null) ?? ""; string value4 = (string.IsNullOrWhiteSpace(text4) ? text : (text4 + "\n\n" + text)); type5.GetProperty("Description")?.SetValue(obj3, value4); type5.GetProperty("RequiresRestart")?.SetValue(obj3, false); object obj4 = Activator.CreateInstance(type6, colorEntry, obj3); methodInfo.Invoke(null, new object[1] { obj4 }); _lcTxtOptsByEntry[(ConfigEntryBase)(object)colorEntry] = obj3; _lcTxtItemByEntry[(ConfigEntryBase)(object)colorEntry] = obj4; } else { Debug.LogWarning((object)"LethalConfig: cannot update description (no cache and no re-add path)."); } } flag = true; } if (flag) { _registered = true; type.GetMethod("SkipAutoGenFor", new Type[1] { typeof(ConfigEntryBase) })?.Invoke(null, new object[1] { colorEntry }); } else { Debug.Log((object)"LethalConfigHelper: Could not display currently active color."); } } catch (Exception arg) { Debug.Log((object)$"LethalConfig UI extras failed: {arg}"); } } } namespace ReservedItemSlotCore { [HarmonyPatch] internal static class ItemNameMap { private static Dictionary<string, Item> originalNameToItemMap = new Dictionary<string, Item>(); private static Dictionary<Item, string> itemToNameMap = new Dictionary<Item, string>(); [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPrefix] private static void RecordOriginalItemNames(StartOfRound __instance) { List<Item> list = __instance?.allItemsList?.itemsList; if (list == null) { Plugin.LogError("Failed to record original item names. This might be fine if you're not using translation/localization mods. (no guarantees)"); return; } foreach (Item item in list) { string text = item?.itemName; if (!string.IsNullOrEmpty(text)) { if (!itemToNameMap.ContainsKey(item)) { itemToNameMap.Add(item, text); } if (!originalNameToItemMap.ContainsKey(text)) { originalNameToItemMap.Add(text, item); } } } } internal static string GetItemName(GrabbableObject grabbableObject) { if ((Object)(object)grabbableObject?.itemProperties == (Object)null) { return ""; } string itemName = GetItemName(grabbableObject.itemProperties); if (itemName == null) { return ""; } return itemName; } internal static string GetItemName(Item item) { if ((Object)(object)item == (Object)null) { return ""; } if (itemToNameMap.TryGetValue(item, out var value) && value != null) { return value; } return ""; } internal static bool IsZeroValueScrap(GrabbableObject grabbable) { if ((Object)(object)grabbable == (Object)null || (Object)(object)grabbable.itemProperties == (Object)null) { return false; } try { return !grabbable.itemProperties.isScrap || (grabbable.itemProperties.isScrap && grabbable.scrapValue == 0); } catch { return false; } } } [BepInPlugin("FlipMods.ReservedItemSlotCore", "ReservedItemSlotCore", "2.0.52")] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin instance; private static ManualLogSource logger; public static List<ReservedItemSlotData> customItemSlots = new List<ReservedItemSlotData>(); private void Awake() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown instance = this; CreateCustomLogger(); ConfigSettings.BindConfigSettings(); AddCustomItemSlots(); _harmony = new Harmony("ReservedItemSlotCore"); PatchAll(); Log("ReservedItemSlotCore loaded"); } private void AddCustomItemSlots() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) foreach (CustomItemSlotConfigEntry customItemSlotConfig in ConfigSettings.customItemSlotConfigs) { if (!(customItemSlotConfig.customItemSlotName == "") && customItemSlotConfig.customItemSlotItems.Length != 0) { ReservedItemSlotData reservedItemSlotData = ReservedItemSlotData.CreateReservedItemSlotData(customItemSlotConfig.customItemSlotName, customItemSlotConfig.customItemSlotPriority, customItemSlotConfig.customItemSlotPrice); string[] customItemSlotItems = customItemSlotConfig.customItemSlotItems; for (int i = 0; i < customItemSlotItems.Length; i++) { ReservedItemData itemData = new ReservedItemData(customItemSlotItems[i]); reservedItemSlotData.AddItemToReservedItemSlot(itemData); } customItemSlots.Add(reservedItemSlotData); } } } private void PatchAll() { IEnumerable<Type> enumerable; try { enumerable = Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException ex) { enumerable = ex.Types.Where((Type t) => t != null); } foreach (Type item in enumerable) { try { _harmony.PatchAll(item); } catch { } } } private void CreateCustomLogger() { try { logger = Logger.CreateLogSource(string.Format("{0}-{1}", "ReservedItemSlotCore", "2.0.52")); } catch { logger = ((BaseUnityPlugin)this).Logger; } } public static void Log(string message) { logger.LogInfo((object)message); } public static void LogError(string message) { logger.LogError((object)message); } public static void LogWarning(string message) { logger.LogWarning((object)message); } public static void LogVerbose(string message) { if (ConfigSettings.verboseLogs.Value) { logger.LogInfo((object)("[VERBOSE] " + message)); } } public static void LogErrorVerbose(string message) { if (ConfigSettings.verboseLogs.Value) { logger.LogError((object)("[VERBOSE] " + message)); } } public static void LogWarningVerbose(string message) { if (ConfigSettings.verboseLogs.Value) { logger.LogWarning((object)("[VERBOSE] " + message)); } } public static bool IsModLoaded(string guid) { return Chainloader.PluginInfos.ContainsKey(guid); } } public static class PluginInfo { public const string PLUGIN_GUID = "FlipMods.ReservedItemSlotCore"; public const string PLUGIN_NAME = "ReservedItemSlotCore"; public const string PLUGIN_VERSION = "2.0.52"; } [HarmonyPatch] public static class ReservedHotbarManager { public static int indexInHotbar = 0; public static int indexInReservedHotbar = 0; internal static List<ReservedItemSlotData> currentlyToggledItemSlots = new List<ReservedItemSlotData>(); public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData; public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked; public static bool isToggledInReservedSlots { get { ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot(); if (!ReservedPlayerData.localPlayerData.inReservedHotbarSlots || !Keybinds.pressedToggleKey) { if (currentlyToggledItemSlots != null && currentlySelectedReservedItemSlot != null) { return currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot); } return false; } return true; } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] public static void InitSession(StartOfRound __instance) { currentlyToggledItemSlots = new List<ReservedItemSlotData>(); ReservedPlayerData.allPlayerData.Clear(); indexInHotbar = 0; indexInReservedHotbar = -1; } public static void ForceToggleReservedHotbar(params ReservedItemSlotData[] reservedItemSlots) { if (((NetworkBehaviour)localPlayerController).IsOwner && localPlayerController.isPlayerControlled && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject) && HUDPatcher.hasReservedItemSlotsAndEnabled && reservedHotbarSize > 0 && CanSwapHotbars() && reservedItemSlots != null && reservedItemSlots.Length != 0 && !((Object)(object)localPlayerController == (Object)null)) { currentlyToggledItemSlots = new List<ReservedItemSlotData>(reservedItemSlots); int num = currentlyToggledItemSlots.First().GetReservedItemSlotIndex() + localPlayerData.reservedHotbarStartIndex; bool active = ReservedPlayerData.localPlayerData.IsReservedItemSlot(num); if (currentlyToggledItemSlots.Contains(localPlayerData.GetCurrentlySelectedReservedItemSlot())) { FocusReservedHotbarSlots(active: false); return; } HUDPatcher.UpdateToggledReservedItemSlotsUI(); FocusReservedHotbarSlots(active, num); } } public static void FocusReservedHotbarSlots(bool active, int forceSlot = -1) { if (!HUDPatcher.hasReservedItemSlotsAndEnabled || (reservedHotbarSize <= 0 && active) || (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved == active && (forceSlot == -1 || localPlayerData.currentItemSlot == forceSlot))) { return; } if (forceSlot != -1) { active = localPlayerData.IsReservedItemSlot(forceSlot); } ReservedPlayerData reservedPlayerData = ReservedPlayerData.localPlayerData; indexInHotbar = Mathf.Clamp(indexInHotbar, 0, localPlayerController.ItemSlots.Length - 1); indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0); indexInReservedHotbar = Mathf.Clamp(indexInReservedHotbar, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1); int num = Mathf.Clamp(localPlayerController.currentItemSlot, 0, localPlayerController.ItemSlots.Length); int i = num; bool flag = active; if (flag && (!reservedPlayerData.IsReservedItemSlot(num) || forceSlot != -1)) { indexInHotbar = num; indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0); if (forceSlot != -1 && reservedPlayerData.IsReservedItemSlot(forceSlot)) { indexInReservedHotbar = forceSlot; } i = indexInReservedHotbar; if (!AllowScrollCompat.Loaded && (Object)(object)localPlayerController.ItemSlots[i] == (Object)null && reservedPlayerData.GetNumHeldReservedItems() > 0) { for (i = reservedPlayerData.reservedHotbarStartIndex; i < reservedPlayerData.reservedHotbarEndIndexExcluded && !((Object)(object)localPlayerController.ItemSlots[i] != (Object)null); i++) { } } Plugin.LogVerbose("Focusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + ReservedPlayerData.localPlayerData.reservedHotbarStartIndex); } else if (!flag && (ReservedPlayerData.localPlayerData.IsReservedItemSlot(num) || forceSlot != -1)) { indexInReservedHotbar = Mathf.Clamp(num, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1); if (forceSlot != -1 && !reservedPlayerData.IsReservedItemSlot(forceSlot)) { indexInHotbar = forceSlot; } i = indexInHotbar; Plugin.LogVerbose("Unfocusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + ReservedPlayerData.localPlayerData.reservedHotbarStartIndex); } if (i < 0) { Plugin.LogError("Swapping to hotbar slot: " + i + ". Maybe send these logs to Flip? :)"); } else if (i >= localPlayerController.ItemSlots.Length) { Plugin.LogError("Swapping to hotbar slot: " + i + " InventorySize: " + localPlayerController.ItemSlots.Length + ". Maybe send these logs to Flip? :)"); } SyncManager.SwapHotbarSlot(i); if (localPlayerController.currentItemSlot != i) { Plugin.LogWarning("OnFocusReservedHotbarSlots - New hotbar index does not match target hotbar index. Tried to swap to index: " + i + " Current index: " + localPlayerController.currentItemSlot + " Tried swapping to reserved hotbar: " + active); } } public static bool CanSwapHotbars() { if (!HUDPatcher.hasReservedItemSlotsAndEnabled) { return false; } if (TooManyEmotes_Compat.Enabled && TooManyEmotes_Compat.IsLocalPlayerPerformingCustomEmote() && !TooManyEmotes_Compat.CanMoveWhileEmoting()) { return false; } if (ReservedPlayerData.localPlayerData.grabbingReservedItemData == null && !localPlayerController.isGrabbingObjectAnimation && !localPlayerController.quickMenuManager.isMenuOpen && !localPlayerController.inSpecialInteractAnimation && !localPlayerData.throwingObject && !localPlayerController.isTypingChat && !localPlayerController.twoHanded && !localPlayerController.activatingItem && !localPlayerController.jetpackControls && !localPlayerController.disablingJetpackControls && !localPlayerController.inTerminalMenu && !localPlayerController.isPlayerDead) { return !(localPlayerData.timeSinceSwitchingSlots < 0.3f); } return false; } internal static void OnSwapToReservedHotbar() { if (!localPlayerData.currentItemSlotIsReserved) { return; } if (localPlayerData.currentItemSlotIsReserved) { indexInReservedHotbar = localPlayerController.currentItemSlot; } ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot(); if (isToggledInReservedSlots && currentlyToggledItemSlots != null && !currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot)) { currentlyToggledItemSlots = null; } if (HUDPatcher.reservedItemSlots == null) { return; } foreach (Image reservedItemSlot in HUDPatcher.reservedItemSlots) { CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>(); if ((Object)(object)component != (Object)null) { component.ignoreParentGroups = !HUDPatcher.IsHudHidden; } } } internal static void OnSwapToVanillaHotbar() { if (localPlayerData.currentItemSlotIsReserved) { return; } if (!localPlayerData.currentItemSlotIsReserved) { indexInHotbar = localPlayerController.currentItemSlot; } currentlyToggledItemSlots = null; if (HUDPatcher.reservedItemSlots == null) { return; } foreach (Image reservedItemSlot in HUDPatcher.reservedItemSlots) { CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>(); if ((Object)(object)component != (Object)null) { component.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value; } } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPrefix] private static void RefocusReservedHotbarAfterAnimation(PlayerControllerB __instance) { if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !Keybinds.pressedToggleKey && Keybinds.holdingModifierKey != ReservedPlayerData.localPlayerData.currentItemSlotIsReserved && !isToggledInReservedSlots && CanSwapHotbars()) { FocusReservedHotbarSlots(Keybinds.holdingModifierKey); } } [HarmonyPatch(typeof(PlayerControllerB), "UpdateSpecialAnimationValue")] [HarmonyPostfix] private static void UpdateReservedHotbarAfterAnimation(bool specialAnimation, PlayerControllerB __instance) { if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !specialAnimation && !Keybinds.pressedToggleKey && ReservedPlayerData.localPlayerData.currentItemSlotIsReserved != Keybinds.holdingModifierKey) { FocusReservedHotbarSlots(Keybinds.holdingModifierKey); } } } [HarmonyPatch] public static class SessionManager { [CompilerGenerated] private sealed class <>c__DisplayClass25_0 { public bool force; } internal static List<ReservedItemSlotData> unlockedReservedItemSlots = new List<ReservedItemSlotData>(); internal static Dictionary<string, ReservedItemSlotData> unlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>(); internal static List<ReservedItemSlotData> pendingUnlockedReservedItemSlots = new List<ReservedItemSlotData>(); internal static Dictionary<string, ReservedItemSlotData> pendingUnlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>(); private static Dictionary<string, ReservedItemData> allReservedItemData = new Dictionary<string, ReservedItemData>(); internal static bool gameStarted = false; internal static List<ReservedItemSlotData> allUnlockableReservedItemSlots => SyncManager.unlockableReservedItemSlots; internal static Dictionary<string, ReservedItemSlotData> allUnlockableReservedItemSlotsDict => SyncManager.unlockableReservedItemSlotsDict; public static int numReservedItemSlotsUnlocked { get { if (unlockedReservedItemSlots == null) { return 0; } return unlockedReservedItemSlots.Count; } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] private static void InitSession() { unlockedReservedItemSlots.Clear(); unlockedReservedItemSlotsDict.Clear(); pendingUnlockedReservedItemSlots.Clear(); pendingUnlockedReservedItemSlotsDict.Clear(); allReservedItemData.Clear(); gameStarted = false; } [HarmonyPatch(typeof(StartOfRound), "ResetPlayersLoadedValueClientRpc")] [HarmonyPostfix] private static void OnStartGame(StartOfRound __instance, bool landingShip = false) { if (gameStarted || !NetworkManager.Singleton.IsClient) { return; } if (!SyncManager.hostHasMod && SyncManager.canUseModDisabledOnHost) { Plugin.LogWarning("Starting game while host does not have this mod, and ForceEnableReservedItemSlots is enabled in the config. Unlocking: " + ReservedItemSlotData.allReservedItemSlotData.Count + " slots. THIS MAY NOT BE STABLE"); SyncManager.isSynced = true; SyncManager.enablePurchasingItemSlots = false; ReservedPlayerData.localPlayerData.reservedHotbarStartIndex = ReservedPlayerData.localPlayerData.itemSlots.Length; foreach (ReservedItemSlotData value in ReservedItemSlotData.allReservedItemSlotData.Values) { SyncManager.AddReservedItemSlotData(value); UnlockReservedItemSlot(value); } pendingUnlockedReservedItemSlots?.Clear(); pendingUnlockedReservedItemSlotsDict?.Clear(); SyncManager.UpdateReservedItemsList(); } gameStarted = true; } public static void UnlockReservedItemSlot(ReservedItemSlotData itemSlotData) { if (itemSlotData == null) { return; } Plugin.Log("Unlocking reserved item slot: " + itemSlotData.slotName); if (!SyncManager.isSynced) { if (!pendingUnlockedReservedItemSlotsDict.ContainsKey(itemSlotData.slotName)) { pendingUnlockedReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData); pendingUnlockedReservedItemSlots.Add(itemSlotData); } return; } if (!unlockedReservedItemSlotsDict.ContainsKey(itemSlotData.slotName)) { unlockedReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData); if (!unlockedReservedItemSlots.Contains(itemSlotData)) { int num = -1; for (int i = 0; i < unlockedReservedItemSlots.Count; i++) { if (itemSlotData.slotPriority > unlockedReservedItemSlots[i].slotPriority) { num = i; break; } } if (num == -1) { num = unlockedReservedItemSlots.Count; } for (int j = 0; j < unlockedReservedItemSlots.Count; j++) { _ = unlockedReservedItemSlots[j]; } unlockedReservedItemSlots.Insert(num, itemSlotData); foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values) { if (unlockedReservedItemSlots.Count == 1) { value.reservedHotbarStartIndex = value.itemSlots.Length; } int index = value.reservedHotbarStartIndex + num; List<GrabbableObject> list = new List<GrabbableObject>(value.itemSlots); list.Insert(index, null); value.playerController.ItemSlots = list.ToArray(); value.hotbarSize = list.Count; } } } if (ReservedHotbarManager.indexInReservedHotbar < ReservedPlayerData.localPlayerData.reservedHotbarStartIndex || ReservedHotbarManager.indexInReservedHotbar >= ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded) { ReservedHotbarManager.indexInReservedHotbar = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex; } UpdateReservedItemsList(); HUDPatcher.OnUpdateReservedItemSlots(); } internal static void UnlockAllPendingItemSlots() { foreach (ReservedItemSlotData pendingUnlockedReservedItemSlot in pendingUnlockedReservedItemSlots) { UnlockReservedItemSlot(pendingUnlockedReservedItemSlot); } pendingUnlockedReservedItemSlots.Clear(); pendingUnlockedReservedItemSlotsDict.Clear(); } public static ReservedItemSlotData GetUnlockedReservedItemSlot(int indexInUnlockedItemSlots) { if (unlockedReservedItemSlots == null || indexInUnlockedItemSlots < 0 || indexInUnlockedItemSlots >= unlockedReservedItemSlots.Count) { return null; } return unlockedReservedItemSlots[indexInUnlockedItemSlots]; } public static ReservedItemSlotData GetUnlockedReservedItemSlot(string itemSlotName) { if (TryGetUnlockedItemSlotData(itemSlotName, out var itemSlotData)) { return itemSlotData; } return null; } public static bool IsItemSlotUnlocked(ReservedItemSlotData itemSlotData) { if (itemSlotData == null) { return false; } return IsItemSlotUnlocked(itemSlotData.slotName); } public static bool IsItemSlotUnlocked(string itemSlotName) { return unlockedReservedItemSlotsDict.ContainsKey(itemSlotName); } internal static void UpdateReservedItemsList() { if (unlockedReservedItemSlots == null) { return; } allReservedItemData.Clear(); foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots) { if (unlockedReservedItemSlot.reservedItemData == null) { continue; } foreach (ReservedItemData value in unlockedReservedItemSlot.reservedItemData.Values) { if (!allReservedItemData.ContainsKey(value.itemName)) { allReservedItemData.Add(value.itemName, value); } } } } [HarmonyPatch(typeof(StartOfRound), "ResetShip")] [HarmonyPostfix] private static void OnResetShip() { if (SyncManager.enablePurchasingItemSlots) { ResetProgressDelayed(); } else if (!SyncManager.hostHasMod && SyncManager.canUseModDisabledOnHost) { SyncManager.isSynced = false; ResetProgressDelayed(force: true); } gameStarted = false; } [HarmonyPatch(typeof(GameNetworkManager), "SaveGameValues")] [HarmonyPostfix] private static void OnSaveGameValues() { if (NetworkManager.Singleton.IsHost && StartOfRound.Instance.inShipPhase && SyncManager.enablePurchasingItemSlots) { SaveGameValues(); } } [HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")] [HarmonyPostfix] private static void OnLoadGameValues() { if (NetworkManager.Singleton.IsServer && SyncManager.isSynced && SyncManager.enablePurchasingItemSlots) { LoadGameValues(); } } internal static void ResetProgress(bool force = false) { if (!SyncManager.enablePurchasingItemSlots && !force) { return; } Plugin.Log("Resetting progress."); foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values) { GrabbableObject[] itemSlots = value.playerController.ItemSlots; List<GrabbableObject> list = new List<GrabbableObject>(); for (int i = 0; i < itemSlots.Length; i++) { if (i < value.reservedHotbarStartIndex || i >= value.reservedHotbarEndIndexExcluded) { list.Add(itemSlots[i]); } } value.playerController.ItemSlots = list.ToArray(); } unlockedReservedItemSlots?.Clear(); unlockedReservedItemSlotsDict?.Clear(); pendingUnlockedReservedItemSlots?.Clear(); pendingUnlockedReservedItemSlotsDict?.Clear(); List<Image> list2 = new List<Image>(); List<Image> list3 = new List<Image>(); for (int j = 0; j < HUDManager.Instance.itemSlotIconFrames.Length; j++) { Image val = HUDManager.Instance.itemSlotIconFrames[j]; Image item = HUDManager.Instance.itemSlotIcons[j]; if (!HUDPatcher.reservedItemSlots.Contains(val)) { list2.Add(val); list3.Add(item); } else { Object.Destroy((Object)(object)((Component)val).gameObject); } } HUDPatcher.reservedItemSlots.Clear(); HUDManager.Instance.itemSlotIconFrames = list2.ToArray(); HUDManager.Instance.itemSlotIcons = list3.ToArray(); foreach (ReservedPlayerData value2 in ReservedPlayerData.allPlayerData.Values) { if (value2.playerController.currentItemSlot < 0 || value2.playerController.currentItemSlot >= value2.playerController.ItemSlots.Length) { PlayerPatcher.SwitchToItemSlot(value2.playerController, 0); } value2.hotbarSize = value2.itemSlots.Length; value2.reservedHotbarStartIndex = value2.hotbarSize; } foreach (ReservedItemSlotData allUnlockableReservedItemSlot in allUnlockableReservedItemSlots) { if (allUnlockableReservedItemSlot.purchasePrice <= 0) { UnlockReservedItemSlot(allUnlockableReservedItemSlot); } } _ = SyncManager.hostHasMod; HUDPatcher.OnUpdateReservedItemSlots(); if (NetworkManager.Singleton.IsServer) { ES3.DeleteKey("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName); } } internal static void ResetProgressDelayed(bool force = false) { <>c__DisplayClass25_0 CS$<>8__locals0 = new <>c__DisplayClass25_0(); CS$<>8__locals0.force = force; ((MonoBehaviour)StartOfRound.Instance).StartCoroutine(Reset()); [IteratorStateMachine(typeof(<>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d))] IEnumerator Reset() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d(0) { <>4__this = CS$<>8__locals0 }; } } internal static void SaveGameValues() { if (!NetworkManager.Singleton.IsServer || unlockedReservedItemSlots == null) { return; } List<string> list = new List<string>(); foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots) { if (!list.Contains(unlockedReservedItemSlot.slotName)) { list.Add(unlockedReservedItemSlot.slotName); } } Plugin.LogWarning("Saving " + list.Count + " unlocked reserved item slots."); string[] array = list.ToArray(); ES3.Save<string[]>("ReservedItemSlots.UnlockedItemSlots", array, GameNetworkManager.Instance.currentSaveFileName); } internal static void LoadGameValues() { if (!NetworkManager.Singleton.IsServer || SyncManager.unlockableReservedItemSlotsDict == null) { return; } string[] array = ES3.Load<string[]>("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName, new string[0]); Plugin.LogWarning("Loading " + array.Length + " unlocked reserved item slots."); int num = 0; string[] array2 = array; foreach (string key in array2) { if (SyncManager.unlockableReservedItemSlotsDict.TryGetValue(key, out var value)) { num++; UnlockReservedItemSlot(value); SyncManager.SendUnlockItemSlotToClients(value.slotId); } } Plugin.Log("Loaded " + num + " unlocked reserved items."); } public static bool IsReservedItem(GrabbableObject grabbableObject) { if (!IsReservedItem(ItemNameMap.GetItemName(grabbableObject))) { if ((Object)(object)grabbableObject?.itemProperties != (Object)null) { return IsReservedItem(grabbableObject.itemProperties.itemName); } return false; } return true; } public static bool IsReservedItem(string itemName) { return allReservedItemData.ContainsKey(itemName); } public static bool TryGetUnlockedItemSlotData(string itemSlotName, out ReservedItemSlotData itemSlotData) { itemSlotData = null; unlockedReservedItemSlotsDict.TryGetValue(itemSlotName, out itemSlotData); return itemSlotData != null; } public static bool TryGetUnlockedItemData(GrabbableObject item, out ReservedItemData itemData) { itemData = null; if (!TryGetUnlockedItemData(ItemNameMap.GetItemName(item), out itemData)) { if ((Object)(object)item?.itemProperties != (Object)null) { return TryGetUnlockedItemData(item.itemProperties.itemName, out itemData); } return false; } return true; } public static bool TryGetUnlockedItemData(string itemName, out ReservedItemData itemData) { itemData = null; return allReservedItemData.TryGetValue(itemName, out itemData); } } } namespace ReservedItemSlotCore.Patches { [HarmonyPatch] internal static class DropReservedItemPatcher { [CompilerGenerated] private sealed class <>c__DisplayClass10_0 { public PlayerControllerB playerController; public float time; internal bool <SwitchToItemSlotAfterDelay>b__0() { if (!((Object)(object)playerController.currentlyHeldObjectServer == (Object)null)) { return Time.time - time >= 5f; } return true; } } [CompilerGenerated] private sealed class <SwitchToItemSlotAfterDelay>d__10 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PlayerControllerB playerController; private <>c__DisplayClass10_0 <>8__1; public int slot; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SwitchToItemSlotAfterDelay>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass10_0(); <>8__1.playerController = playerController; <>8__1.time = Time.time; if ((Object)(object)<>8__1.playerController == (Object)(object)localPlayerController) { <>2__current = (object)new WaitUntil((Func<bool>)(() => (Object)(object)<>8__1.playerController.currentlyHeldObjectServer == (Object)null || Time.time - <>8__1.time >= 5f)); <>1__state = 1; return true; } goto IL_0091; case 1: <>1__state = -1; goto IL_0091; case 2: { <>1__state = -1; playersDiscardingItems.Remove(<>8__1.playerController); if (<>8__1.playerController.currentItemSlot != slot && Time.time - <>8__1.time < 3f && ReservedPlayerData.allPlayerData.TryGetValue(<>8__1.playerController, out var value)) { value.CallSwitchToItemSlot(slot); } return false; } IL_0091: <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static HashSet<PlayerControllerB> playersDiscardingItems = new HashSet<PlayerControllerB>(); private static float timeLoggedPreventedScroll = 0f; private static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; private static bool IsNoScrapSlotName(string name) { if (string.IsNullOrEmpty(name)) { return false; } string text = name.Trim().ToLowerInvariant(); if (!(text == "no_scrap_1")) { return text == "no_scrap_2"; } return true; } [HarmonyPatch(typeof(PlayerControllerB), "SetObjectAsNoLongerHeld")] [HarmonyPatch(typeof(PlayerControllerB), "PlaceGrabbableObject")] [HarmonyPostfix] public static void OnObjectNoLongerHeld(PlayerControllerB __instance) { OnDiscardItem(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "DestroyItemInSlot")] [HarmonyPostfix] public static void OnDestroyItem(int itemSlot, PlayerControllerB __instance) { if (ReservedPlayerData.localPlayerData != null && SessionManager.unlockedReservedItemSlots != null && itemSlot >= ReservedPlayerData.localPlayerData.reservedHotbarStartIndex && itemSlot < ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded) { if (itemSlot == __instance.currentItemSlot) { OnDiscardItem(__instance); } if ((Object)(object)__instance == (Object)(object)localPlayerController) { HUDPatcher.UpdateUI(); } } } [HarmonyPatch(typeof(PlayerControllerB), "DespawnHeldObjectOnClient")] [HarmonyPostfix] public static void OnDespawnItem(PlayerControllerB __instance) { if ((Object)(object)__instance == (Object)(object)localPlayerController) { HUDPatcher.UpdateUI(); } } [HarmonyPatch(typeof(PlayerControllerB), "DropAllHeldItems")] [HarmonyPostfix] public static void OnDropAllHeldItems(PlayerControllerB __instance) { if ((Object)(object)__instance == (Object)(object)localPlayerController) { HUDPatcher.UpdateUI(); } } private static void OnDiscardItem(PlayerControllerB playerController) { if ((Object)(object)playerController == (Object)null || playersDiscardingItems.Contains(playerController) || !ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value) || !value.currentItemSlotIsReserved || (Object)(object)value.currentlySelectedItem != (Object)null) { return; } ReservedItemSlotData currentlySelectedReservedItemSlot = value.GetCurrentlySelectedReservedItemSlot(); if (currentlySelectedReservedItemSlot != null && IsNoScrapSlotName(currentlySelectedReservedItemSlot.slotName)) { if ((Object)(object)playerController == (Object)(object)localPlayerController) { HUDPatcher.UpdateUI(); } return; } if (value.GetNumHeldReservedItems() > 0) { int num = value.CallGetNextItemSlot(forward: true); if (!value.IsReservedItemSlot(num) && !value.IsReservedItemSlot(ReservedHotbarManager.indexInHotbar)) { num = ReservedHotbarManager.indexInHotbar; } playersDiscardingItems.Add(playerController); ((MonoBehaviour)playerController).StartCoroutine(SwitchToItemSlotAfterDelay(playerController, num)); } if ((Object)(object)playerController == (Object)(object)localPlayerController) { HUDPatcher.UpdateUI(); } } [IteratorStateMachine(typeof(<SwitchToItemSlotAfterDelay>d__10))] private static IEnumerator SwitchToItemSlotAfterDelay(PlayerControllerB playerController, int slot) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SwitchToItemSlotAfterDelay>d__10(0) { playerController = playerController, slot = slot }; } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool PreventItemSwappingDroppingItem(CallbackContext context, PlayerControllerB __instance) { if ((Object)(object)__instance == (Object)(object)localPlayerController && playersDiscardingItems.Contains(__instance)) { float time = Time.time; if (ConfigSettings.verboseLogs.Value && time - timeLoggedPreventedScroll > 1f) { timeLoggedPreventedScroll = time; Plugin.LogWarning("[VERBOSE] Prevented item swap. Player is currently discarding an item? This should be fine, unless these logs are spamming."); } return false; } return true; } } [HarmonyPatch] public static class HUDPatcher { private static bool usingController = false; private static float itemSlotWidth; internal static float itemSlotSpacing; private static float defaultItemSlotPosX; private static float defaultItemSlotPosY; private static float defaultItemSlotSpacing; private static Vector2 defaultItemSlotSize; private static Vector2 defaultItemIconSize; private static TextMeshProUGUI hotkeyTooltip; public static List<Image> reservedItemSlots = new List<Image>(); public static HashSet<ReservedItemSlotData> toggledReservedItemSlots = new HashSet<ReservedItemSlotData>(); private static bool lerpToggledItemSlotFrames = false; private static float largestPositionDifference = 0f; private static bool currentApplyHotbarPlusSize; private static bool currentHideEmptySlots; private static readonly bool allowScroll = true; private static Image noScrap1Frame; private static Image noScrap2Frame; private static readonly HashSet<string> NoScrapSlotNames = new HashSet<string> { "no_scrap_1", "no_scrap_2" }; private static Color DefaultOutlineColor = new Color(0f, 0f, 0f, 0f); private static Color DefaultFrameColor = Color.white; private static bool DefaultColorsCaptured = false; private static bool baselineInit = false; private static float baselineCenterX = 0f; private static float baselineSpacingS = 0f; private static float baselineY = 0f; private static Vector2 baselineSize; private static readonly Color DefaultTint = new Color(0.9098039f, 0.7019608f, 1f, 1f); private static bool hasAlphaInConfig = false; private const string LocalColorPrefKey = "ReservedItemSlotCore.NonScrapSlotColor"; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData; public static bool localPlayerUsingController { get { if (!((Object)(object)StartOfRound.Instance != (Object)null)) { return false; } return StartOfRound.Instance.localPlayerUsingController; } } private static float currentItemSlotScale => itemSlotWidth / defaultItemSlotSize.x; public static bool hasReservedItemSlotsAndEnabled { get { if (reservedItemSlots != null && reservedItemSlots.Count > 0 && ((Component)reservedItemSlots[0]).gameObject.activeSelf) { return ((Behaviour)reservedItemSlots[0]).enabled; } return false; } } internal static Color Tint { get; private set; } = DefaultTint; internal static bool IsHudHidden { get; private set; } = false; internal static string EffectiveNonScrapHexUI { get; private set; } = "#E8B3FF"; internal static string EffectiveNonScrapHexSourceUI { get; private set; } = "default"; [HarmonyPatch(typeof(HUDManager), "HideHUD")] [HarmonyPostfix] private static void ReservedSlotsRespectHideHUD(bool hide) { IsHudHidden = hide; if (!hasReservedItemSlotsAndEnabled || reservedItemSlots == null) { return; } bool flag = ReservedPlayerData.localPlayerData?.currentItemSlotIsReserved ?? false; foreach (Image reservedItemSlot in reservedItemSlots) { if ((Object)(object)reservedItemSlot == (Object)null) { continue; } CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>(); if (!((Object)(object)component == (Object)null)) { if (hide) { component.ignoreParentGroups = false; } else { component.ignoreParentGroups = flag || ConfigSettings.preventReservedItemSlotFade.Value; } } } } private static string NormalizeHex(string s) { if (string.IsNullOrWhiteSpace(s)) { return null; } s = s.Trim(); if (!s.StartsWith("#")) { s = "#" + s; } return s.ToUpperInvariant(); } internal static void RefreshTintColor() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) string text = NormalizeHex(ConfigSettings.nonScrapSlotColorHex?.Value); ConfigEntry<string> nonScrapSlotColorHex = ConfigSettings.nonScrapSlotColorHex; string text2 = NormalizeHex(((nonScrapSlotColorHex == null) ? null : ((ConfigEntryBase)nonScrapSlotColorHex).DefaultValue?.ToString()) ?? "#E8B3FF"); bool flag = PlayerPrefs.HasKey("ReservedItemSlotCore.NonScrapSlotColor"); string text3 = NormalizeHex(flag ? PlayerPrefs.GetString("ReservedItemSlotCore.NonScrapSlotColor") : null); if (!string.IsNullOrEmpty(text) && !string.Equals(text, text2, StringComparison.OrdinalIgnoreCase)) { PlayerPrefs.SetString("ReservedItemSlotCore.NonScrapSlotColor", text); PlayerPrefs.Save(); text3 = text; flag = true; } string text4 = text; if (string.Equals(text, text2, StringComparison.OrdinalIgnoreCase)) { text4 = ((flag && !string.IsNullOrEmpty(text3)) ? text3 : text2); } EffectiveNonScrapHexUI = NormalizeHex((!string.IsNullOrEmpty(text4)) ? text4 : text2); Color tint = DefaultTint; hasAlphaInConfig = false; if (!string.IsNullOrEmpty(text4)) { string text5 = ((text4[0] == '#') ? text4.Substring(1) : text4); hasAlphaInConfig = text5.Length == 4 || text5.Length == 8; Color val = default(Color); if (ColorUtility.TryParseHtmlString(text4, ref val)) { tint = val; } else { hasAlphaInConfig = false; } } Tint = tint; UpdateUI(); } private static bool ShouldTint(ReservedItemSlotData slotData) { if (slotData == null) { return false; } return NoScrapSlotNames.Contains(slotData.slotName); } private static void ApplyTintToFrame(Image itemSlotFrame) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)itemSlotFrame == (Object)null)) { Outline obj = ((Component)itemSlotFrame).GetComponent<Outline>() ?? ((Component)itemSlotFrame).gameObject.AddComponent<Outline>(); float num = OnePixel(itemSlotFrame); ((Shadow)obj).effectDistance = new Vector2(num, 0f - num); ((Shadow)obj).effectColor = new Color(Tint.r, Tint.g, Tint.b, hasAlphaInConfig ? Tint.a : 0.1f); ((Shadow)obj).useGraphicAlpha = !hasAlphaInConfig; ((Graphic)itemSlotFrame).color = new Color(Tint.r, Tint.g, Tint.b, hasAlphaInConfig ? Tint.a : ((Graphic)itemSlotFrame).color.a); } } private static void CaptureDefaultColors(HUDManager hud) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (DefaultColorsCaptured || (Object)(object)hud == (Object)null || hud.itemSlotIconFrames == null || hud.itemSlotIconFrames.Length == 0) { return; } Image val = hud.itemSlotIconFrames[0]; if ((Object)(object)val != (Object)null) { Outline component = ((Component)val).GetComponent<Outline>(); if ((Object)(object)component != (Object)null) { DefaultOutlineColor = ((Shadow)component).effectColor; } DefaultFrameColor = ((Graphic)val).color; DefaultColorsCaptured = true; } } private static void ResetTint(Image frame) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)frame == (Object)null)) { Outline component = ((Component)frame).GetComponent<Outline>(); if ((Object)(object)component != (Object)null) { ((Shadow)component).effectColor = DefaultOutlineColor; } ((Graphic)frame).color = new Color(DefaultFrameColor.r, DefaultFrameColor.g, DefaultFrameColor.b, ((Graphic)frame).color.a); } } private static float OnePixel(Image img) { Canvas val = (((Object)(object)img != (Object)null) ? ((Graphic)img).canvas : null); float num = (((Object)(object)val != (Object)null) ? val.scaleFactor : 1f); return 1f / Mathf.Max(num, 0.01f); } private static void RecenterMainHotbarWithTwoLeftReserved() { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) HUDManager instance = HUDManager.Instance; if (!baselineInit || (Object)(object)instance == (Object)null || (Object)(object)noScrap1Frame == (Object)null || (Object)(object)noScrap2Frame == (Object)null) { return; } List<Image> list = new List<Image>(); Image[] itemSlotIconFrames = instance.itemSlotIconFrames; foreach (Image val in itemSlotIconFrames) { if (!((Object)(object)val == (Object)null) && !reservedItemSlots.Contains(val)) { list.Add(val); } } if (list.Count >= 4) { list.Sort((Image a, Image b) => ((Graphic)a).rectTransform.anchoredPosition.x.CompareTo(((Graphic)b).rectTransform.anchoredPosition.x)); float num = baselineCenterX; float num2 = baselineSpacingS; float num3 = baselineY; float[] array = new float[6]; for (int j = 0; j < 6; j++) { array[j] = num + ((float)j - 2.5f) * num2; } ((Graphic)noScrap1Frame).rectTransform.anchoredPosition = new Vector2(array[0], num3); ((Graphic)noScrap2Frame).rectTransform.anchoredPosition = new Vector2(array[1], num3); ((Graphic)list[0]).rectTransform.anchoredPosition = new Vector2(array[2], num3); ((Graphic)list[1]).rectTransform.anchoredPosition = new Vector2(array[3], num3); ((Graphic)list[2]).rectTransform.anchoredPosition = new Vector2(array[4], num3); ((Graphic)list[3]).rectTransform.anchoredPosition = new Vector2(array[5], num3); } } private static void EnsureVanillaBaseline() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) HUDManager instance = HUDManager.Instance; if ((Object)(object)instance == (Object)null) { return; } Vector2 sizeDelta = ((Graphic)instance.itemSlotIconFrames[0]).rectTransform.sizeDelta; if (baselineInit && sizeDelta == baselineSize) { return; } List<Image> list = new List<Image>(); Image[] itemSlotIconFrames = instance.itemSlotIconFrames; foreach (Image val in itemSlotIconFrames) { if (!((Object)(object)val == (Object)null) && !reservedItemSlots.Contains(val)) { list.Add(val); } } if (list.Count >= 4) { list.Sort((Image a, Image b) => ((Graphic)a).rectTransform.anchoredPosition.x.CompareTo(((Graphic)b).rectTransform.anchoredPosition.x)); baselineY = ((Graphic)list[0]).rectTransform.anchoredPosition.y; float num = Mathf.Abs(((Graphic)list[1]).rectTransform.anchoredPosition.x - ((Graphic)list[0]).rectTransform.anchoredPosition.x); float num2 = Mathf.Abs(((Graphic)list[2]).rectTransform.anchoredPosition.x - ((Graphic)list[1]).rectTransform.anchoredPosition.x); float num3 = Mathf.Abs(((Graphic)list[3]).rectTransform.anchoredPosition.x - ((Graphic)list[2]).rectTransform.anchoredPosition.x); baselineSpacingS = (num + num2 + num3) / 3f; baselineCenterX = 0f; for (int j = 0; j < 4; j++) { baselineCenterX += ((Graphic)list[j]).rectTransform.anchoredPosition.x; } baselineCenterX /= 4f; baselineSize = sizeDelta; baselineInit = true; } } [HarmonyPatch(typeof(HUDManager), "Awake")] [HarmonyPostfix] public static void Initialize(HUDManager __instance) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) CanvasScaler componentInParent = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<CanvasScaler>(); AspectRatioFitter componentInParent2 = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<AspectRatioFitter>(); itemSlotWidth = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta.x; itemSlotSpacing = 1.125f * itemSlotWidth; defaultItemSlotPosX = componentInParent.referenceResolution.x / 2f / componentInParent2.aspectRatio - itemSlotWidth / 4f; defaultItemSlotSpacing = itemSlotSpacing; defaultItemSlotSize = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta; defaultItemIconSize = ((Graphic)__instance.itemSlotIcons[0]).rectTransform.sizeDelta; defaultItemSlotPosY = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.anchoredPosition.y; reservedItemSlots.Clear(); CaptureDefaultColors(__instance); RefreshTintColor(); } [HarmonyPatch(typeof(StartOfRound), "Update")] [HarmonyPrefix] public static void UpdateUsingController(StartOfRound __instance) { if (!((Object)(object)__instance.localPlayerController == (Object)null) && !((Object)(object)hotkeyTooltip == (Object)null) && ((Component)hotkeyTooltip).gameObject.activeSelf && ((Behaviour)hotkeyTooltip).enabled) { if (__instance.localPlayerUsingController != usingController) { usingController = __instance.localPlayerUsingController; UpdateHotkeyTooltipText(); } LerpItemSlotFrames(); } } private static void LerpItemSlotFrames() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if (!lerpToggledItemSlotFrames) { return; } if (largestPositionDifference < 2f && largestPositionDifference != -1f) { lerpToggledItemSlotFrames = false; } for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++) { ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i); if (!ShouldTint(unlockedReservedItemSlot)) { Image val = HUDManager.Instance.itemSlotIconFrames[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i]; bool flag = unlockedReservedItemSlot.slotPriority >= 0 || !ConfigSettings.displayNegativePrioritySlotsLeftSideOfScreen.Value; Vector2 anchoredPosition = ((Graphic)val).rectTransform.anchoredPosition; anchoredPosition.x = (defaultItemSlotPosX + (defaultItemSlotSize.x - itemSlotWidth) / 2f) * (float)(flag ? 1 : (-1)); if (ReservedHotbarManager.isToggledInReservedSlots && ReservedHotbarManager.currentlyToggledItemSlots != null && ReservedHotbarManager.currentlyToggledItemSlots.Contains(unlockedReservedItemSlot)) { anchoredPosition.x += itemSlotWidth / 2f * (float)((!flag) ? 1 : (-1)); } float num = Mathf.Abs(anchoredPosition.x - ((Graphic)val).rectTransform.anchoredPosition.x); largestPositionDifference = Mathf.Max(largestPositionDifference, num); if (lerpToggledItemSlotFrames) { ((Graphic)val).rectTransform.anchoredPosition = Vector2.Lerp(((Graphic)val).rectTransform.anchoredPosition, anchoredPosition, Time.deltaTime * 10f); } else { ((Graphic)val).rectTransform.anchoredPosition = anchoredPosition; } } } } public static void OnUpdateReservedItemSlots() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (reservedItemSlots == null || SessionManager.numReservedItemSlotsUnlocked <= 0 || reservedItemSlots.Count == SessionManager.numReservedItemSlotsUnlocked) { return; } List<Image> list = new List<Image>(HUDManager.Instance.itemSlotIconFrames); List<Image> list2 = new List<Image>(HUDManager.Instance.itemSlotIcons); for (int i = reservedItemSlots.Count; i < SessionManager.numReservedItemSlotsUnlocked; i++) { Image component = Object.Instantiate<GameObject>(((Component)list[0]).gameObject, ((Component)list[0]).transform.parent).GetComponent<Image>(); Image component2 = ((Component)((Component)component).transform.GetChild(0)).GetComponent<Image>(); ((Component)component).transform.localScale = ((Component)list[0]).transform.localScale; ((Transform)((Graphic)component).rectTransform).eulerAngles = ((Transform)((Graphic)list[0]).rectTransform).eulerAngles; ((Transform)((Graphic)component2).rectTransform).eulerAngles = ((Transform)((Graphic)list2[0]).rectTransform).eulerAngles; CanvasGroup obj = ((Component)component).gameObject.AddComponent<CanvasGroup>(); obj.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value; obj.alpha = 1f; component.fillMethod = list[0].fillMethod; component.sprite = list[0].sprite; ((Graphic)component).material = ((Graphic)list[0]).material; if (Plugin.IsModLoaded("xuxiaolan.hotbarrd")) { component.overrideSprite = list[0].overrideSprite; } ResetTint(component); int index = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + reservedItemSlots.Count; list.Insert(index, component); list2.Insert(index, component2); reservedItemSlots.Add(component); if (ShouldTint(SessionManager.GetUnlockedReservedItemSlot(i))) { ApplyTintToFrame(component); } } HUDManager.Instance.itemSlotIconFrames = list.ToArray(); HUDManager.Instance.itemSlotIcons = list2.ToArray(); UpdateUI(); } public static void UpdateUI() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_04b2: Unknown result type (might be due to invalid IL or missing references) //IL_04e2: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) if (reservedItemSlots.Count != SessionManager.numReservedItemSlotsUnlocked) { Plugin.LogError("Called UpdateUI with mismatched unlocked reserved item slots and reserved item slot hud elements."); return; } noScrap1Frame = null; noScrap2Frame = null; int num = 0; int num2 = 0; RectTransform val = null; EnsureVanillaBaseline(); Vector2 anchoredPosition = default(Vector2); for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++) { ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i); Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, reservedItemSlots[i]); Image val2 = reservedItemSlots[i]; Image component = ((Component)((Component)reservedItemSlots[i]).transform.GetChild(0)).GetComponent<Image>(); ((Graphic)val2).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIconFrames[0]).rectTransform.sizeDelta; ((Graphic)component).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIcons[0]).rectTransform.sizeDelta; if (HotbarPlus_Compat.Enabled && !ConfigSettings.applyHotbarPlusItemSlotSize.Value) { ((Graphic)val2).rectTransform.sizeDelta = defaultItemSlotSize; ((Graphic)component).rectTransform.sizeDelta = defaultItemIconSize; } itemSlotWidth = ((Graphic)val2).rectTransform.sizeDelta.x; itemSlotSpacing = defaultItemSlotSpacing * currentItemSlotScale; if (ShouldTint(unlockedReservedItemSlot)) { float num3 = OnePixel(val2); RectTransform rectTransform = ((Graphic)val2).rectTransform; rectTransform.sizeDelta -= new Vector2(2f * num3, 2f * num3); itemSlotWidth = rectTransform.sizeDelta.x; } GrabbableObject reservedItem = ReservedPlayerData.localPlayerData.GetReservedItem(unlockedReservedItemSlot); ((Object)val2).name = "Slot" + i + " [ReservedItemSlot] (" + unlockedReservedItemSlot.slotName + ")"; ((Vector2)(ref anchoredPosition))..ctor(defaultItemSlotPosX, defaultItemSlotPosY); if (unlockedReservedItemSlot.slotPriority >= 0 || !ConfigSettings.displayNegativePrioritySlotsLeftSideOfScreen.Value) { anchoredPosition.x = defaultItemSlotPosX + (defaultItemSlotSize.x - itemSlotWidth) / 2f; anchoredPosition.y = defaultItemSlotPosY + 36f * ((itemSlotWidth / defaultItemSlotSize.x - 1f) / 2f) + itemSlotSpacing * (float)num; if (!ConfigSettings.hideEmptyReservedItemSlots.Value || (Object)(object)reservedItem != (Object)null || allowScroll) { if (!Object.op_Implicit((Object)(object)val)) { val = ((Graphic)val2).rectTransform; } num++; } else { anchoredPosition.y = -1000f; } } else { anchoredPosition.x = 0f - defaultItemSlotPosX - (defaultItemSlotSize.x - itemSlotWidth) / 2f; anchoredPosition.y = defaultItemSlotPosY + 36f * ((itemSlotWidth / defaultItemSlotSize.x - 1f) / 2f) + itemSlotSpacing * (float)num2; if (!ConfigSettings.hideEmptyReservedItemSlots.Value || (Object)(object)reservedItem != (Object)null || allowScroll) { num2++; } else { anchoredPosition.y = -1000f; } } if (!ShouldTint(unlockedReservedItemSlot)) { ((Graphic)val2).rectTransform.anchoredPosition = anchoredPosition; } else if (unlockedReservedItemSlot.slotName == "no_scrap_1") { noScrap1Frame = val2; } else if (unlockedReservedItemSlot.slotName == "no_scrap_2") { noScrap2Frame = val2; } ResetTint(val2); if (ShouldTint(unlockedReservedItemSlot)) { ApplyTintToFrame(val2); } if ((Object)(object)reservedItem != (Object)null) { ((Behaviour)component).enabled = true; component.sprite = reservedItem.itemProperties.itemIcon; } else { ((Behaviour)component).enabled = false; component.sprite = null; } } if (SessionManager.numReservedItemSlotsUnlocked > 0 && !ConfigSettings.hideFocusHotbarTooltip.Value) { if ((Object)(object)hotkeyTooltip == (Object)null) { hotkeyTooltip = new GameObject("ReservedItemSlotTooltip", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }).GetComponent<TextMeshProUGUI>(); } RectTransform rectTransform2 = ((TMP_Text)hotkeyTooltip).rectTransform; ((Transform)rectTransform2).SetParent((Transform)(object)val); if (Object.op_Implicit((Object)(object)val)) { ((Transform)rectTransform2).localScale = Vector3.one; rectTransform2.sizeDelta = new Vector2(val.sizeDelta.x * 2f, 10f); rectTransform2.pivot = Vector2.one / 2f; rectTransform2.anchoredPosition3D = new Vector3(0f, 0f - rectTransform2.sizeDelta.x / 2f - itemSlotWidth / 2f - 5f, 0f); ((TMP_Text)hotkeyTooltip).font = ((TMP_Text)HUDManager.Instance.controlTipLines[0]).font; ((TMP_Text)hotkeyTooltip).fontSize = 7f * (val.sizeDelta.x / defaultItemSlotSize.x); ((TMP_Text)hotkeyTooltip).alignment = (TextAlignmentOptions)4100; UpdateHotkeyTooltipText(); } else { ((Transform)rectTransform2).localScale = Vector3.zero; } } RecenterMainHotbarWithTwoLeftReserved(); if ((Object)(object)noScrap1Frame != (Object)null) { ResetTint(noScrap1Frame); ApplyTintToFrame(noScrap1Frame); } if ((Object)(object)noScrap2Frame != (Object)null) { ResetTint(noScrap2Frame); ApplyTintToFrame(noScrap2Frame); } currentApplyHotbarPlusSize = ConfigSettings.applyHotbarPlusItemSlotSize.Value; currentHideEmptySlots = ConfigSettings.hideEmptyReservedItemSlots.Value; } public static void UpdateHotkeyTooltipText() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)localPlayerController == (Object)null || (Object)(object)hotkeyTooltip == (Object)null || Keybinds.FocusReservedHotbarAction == null) { return; } int num = (localPlayerUsingController ? 1 : 0); string text = ""; string text2 = ""; InputBinding val; if (num >= 0 && num < Keybinds.FocusReservedHotbarAction.bindings.Count) { val = Keybinds.FocusReservedHotbarAction.bindings[num]; text = KeybindDisplayNames.GetKeybindDisplayName(((InputBinding)(ref val)).effectivePath); } else { Plugin.LogError("Failed to update FocusReservedHotbar keybind tooltip. Using controller: " + localPlayerUsingController + " NumFocusReservedHotbarActionBindings: " + Keybinds.FocusReservedHotbarAction.bindings.Count); } if (num >= 0 && num < Keybinds.ToggleFocusReservedHotbarAction.bindings.Count) { val = Keybinds.ToggleFocusReservedHotbarAction.bindings[num]; text2 = KeybindDisplayNames.GetKeybindDisplayName(((InputBinding)(ref val)).effectivePath); } else { Plugin.LogError("Failed to update ToggleFocusReservedHotbar keybind tooltip. Using controller: " + localPlayerUsingController + " NumToggleFocusReservedHotbarActionBindings: " + Keybinds.ToggleFocusReservedHotbarAction.bindings.Count); } ((TMP_Text)hotkeyTooltip).text = ""; if (allowScroll) { return; } if (text != "") { ((TMP_Text)hotkeyTooltip).text = $"Hold: [{text}]"; } if (text2 != "" && text2 != text) { if (((TMP_Text)hotkeyTooltip).text != "") { TextMeshProUGUI obj = hotkeyTooltip; ((TMP_Text)obj).text = ((TMP_Text)obj).text + "\n"; } TextMeshProUGUI obj2 = hotkeyTooltip; ((TMP_Text)obj2).text = ((TMP_Text)obj2).text + $"Toggle: [{text2}]"; } } public static void UpdateToggledReservedItemSlotsUI() { if (ReservedHotbarManager.currentlyToggledItemSlots != null) { toggledReservedItemSlots = new HashSet<ReservedItemSlotData>(ReservedHotbarManager.currentlyToggledItemSlots); } else { toggledReservedItemSlots.Clear(); } lerpToggledItemSlotFrames = true; largestPositionDifference = -1f; } private static float GetCurrentItemSlotSpacing() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) try { Image val = HUDManager.Instance.itemSlotIconFrames[0]; Image val2 = HUDManager.Instance.itemSlotIconFrames[1]; if (((Object)val).name.ToLower().Contains("reserved") || ((Object)val2).name.ToLower().Contains("reserved")) { return defaultItemSlotSpacing; } return Mathf.Abs(((Graphic)val2).rectTransform.anchoredPosition.x - ((Graphic)val).rectTransform.anchoredPosition.x); } catch { } return defaultItemSlotSpacing; } [HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")] [HarmonyPostfix] public static void OnCloseQuickMenu() { if (HotbarPlus_Compat.Enabled || currentHideEmptySlots != ConfigSettings.hideEmptyReservedItemSlots.Value) { UpdateUI(); } } } [HarmonyPatch] internal class MaskedEnemyPatcher { [HarmonyPatch(typeof(MaskedPlayerEnemy), "Awake")] [HarmonyPrefix] public static void InitMaskedEnemy(MaskedPlayerEnemy __instance) { if (ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value && !MaskedEnemyData.allMaskedEnemyData.ContainsKey(__instance)) { MaskedEnemyData.allMaskedEnemyData.Add(__instance, new MaskedEnemyData(__instance)); } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "OnDestroy")] [HarmonyPrefix] public static void OnDestroy(MaskedPlayerEnemy __instance) { if (MaskedEnemyData.allMaskedEnemyData.TryGetValue(__instance, out var value)) { value.DestroyEquippedItems(); MaskedEnemyData.allMaskedEnemyData.Remove(__instance); } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "Update")] [HarmonyPostfix] public static void Update(MaskedPlayerEnemy __instance) { if (ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value && MaskedEnemyData.allMaskedEnemyData.TryGetValue(__instance, out var value) && (Object)(object)value.originallyMimickingPlayer == (Object)null && (Object)(object)value.maskedEnemy.mimickingPlayer != (Object)null) { AddReservedItemsToMaskedEnemy(__instance); } } public static void AddReservedItemsToMaskedEnemy(MaskedPlayerEnemy maskedEnemy) { //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) if (!ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value || !MaskedEnemyData.allMaskedEnemyData.TryGetValue(maskedEnemy, out var value)) { return; } value.originallyMimickingPlayer = value.maskedEnemy.mimickingPlayer; if (!ReservedPlayerData.allPlayerData.TryGetValue(value.originallyMimickingPlayer, out var value2)) { Plugin.LogWarning("Failed to mimic player's equipped reserved items. Could not retrieve player data from: " + value.originallyMimickingPlayer.playerUsername); return; } for (int i = value2.reservedHotbarStartIndex; i < Mathf.Min(value2.reservedHotbarEndIndexExcluded, value2.playerController.ItemSlots.Length); i++) { GrabbableObject val = value2.playerController.ItemSlots[i]; if ((Object)(object)val == (Object)null) { continue; } int num = i - value2.reservedHotbarStartIndex; if (num < 0 || num >= SessionManager.unlockedReservedItemSlots.Count) { Plugin.LogWarning("Failed to add reserved item to MaskedEnemy. Could not get ReservedItemSlot at index: " + num + " Item: " + val.itemProperties.itemName + " SlotIndexInInventory: " + i + " ReservedHotbarStartIndex: " + value2.reservedHotbarStartIndex); continue; } ReservedItemData reservedItemData = SessionManager.unlockedReservedItemSlots[num].GetReservedItemData(val); if (reservedItemData.holsteredParentBone == PlayerBone.None) { continue; } Transform bone = value.boneMap.GetBone(reservedItemData.holsteredParentBone); if ((Object)(object)bone == (Object)null) { Plugin.LogWarning("Failed to get bone from masked enemy: " + reservedItemData.holsteredParentBone); continue; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, bone); val2.transform.localEulerAngles = reservedItemData.holsteredRotationOffset; val2.transform.localPosition = reservedItemData.holsteredPositionOffset; val2.transform.localScale = ((Component)val).transform.localScale; val2.layer = 6; MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val3 in componentsInChildren) { if (!((Object)val3).name.Contains("ScanNode") && !((Component)val3).gameObject.CompareTag("DoNotSet") && !((Component)val3).gameObject.CompareTag("InteractTrigger")) { ((Component)val3).gameObject.layer = 6; } } if (val is FlashlightItem) { Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>(); for (int j = 0; j < componentsInChildren2.Length; j++) { ((Behaviour)componentsInChildren2[j]).enabled = false; } } else { Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>(); for (int j = 0; j < componentsInChildren2.Length; j++) { ((Behaviour)componentsInChildren2[j]).enabled = true; } } GrabbableObject componentInChildren = val2.GetComponentInChildren<GrabbableObject>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.playerHeldBy = null; FlashlightItem val4 = (FlashlightItem)(object)((componentInChildren is FlashlightItem) ? componentInChildren : null); if ((Object)(object)val4 != (Object)null) { ((Behaviour)val4.flashlightBulb).enabled = true; ((Behaviour)val4.flashlightBulbGlow).enabled = true; if (((Renderer)val4.flashlightMesh).sharedMaterials.Length > 1 && (Object)(object)val4.bulbLight != (Object)null) { ((Renderer)val4.flashlightMesh).sharedMaterials[1] = val4.bulbLight; } } ReservedItemsPatcher.ForceEnableItemMesh(componentInChildren, enabled: true); componentInChildren.EnablePhysics(false); } Object.DestroyImmediate((Object)(object)val2.GetComponentInChildren<NetworkObject>()); Collider[] componentsInChildren3 = val2.GetComponentsInChildren<Collider>(); for (int j = 0; j < componentsInChildren3.Length; j++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[j]); } MonoBehaviour[] componentsInChildren4 = val2.GetComponentsInChildren<MonoBehaviour>(); for (int j = 0; j < componentsInChildren4.Length; j++) { Object.DestroyImmediate((Object)(object)componentsInChildren4[j]); } } } } [HarmonyPatch] internal static class MouseScrollPatcher { private static float timeLoggedPreventedScroll; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; [HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")] [HarmonyPrefix] public static void CorrectReservedScrollDirectionNextItemSlot(ref bool forward) { if (Keybinds.scrollingReservedHotbar) { forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f; } } [HarmonyPatch(typeof(PlayerControllerB), "SwitchItemSlotsServerRpc")] [HarmonyPrefix] public static void CorrectReservedScrollDirectionServerRpc(ref bool forward) { if (Keybinds.scrollingReservedHotbar) { forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f; } } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool PreventInvertedScrollingReservedHotbar(CallbackContext context) { if (AllowScrollCompat.LoadedAndEnabled) { return true; } if (StartOfRound.Instance.localPlayerUsingController || SessionManager.numReservedItemSlotsUnlocked <= 0 || HUDPatcher.reservedItemSlots == null || localPlayerController.inTerminalMenu) { return true; } if (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved) { if (!HUDPatcher.hasReservedItemSlotsAndEnabled) { return true; } float time = Time.time; if (!Keybinds.scrollingReservedHotbar) { return false; } if (ReservedPlayerData.localPlayerData.GetNumHeldReservedItems() == 1 && (Object)(object)ReservedPlayerData.localPlayerData.currentlySelectedItem != (Object)null && !ReservedHotbarManager.isToggledInReservedSlots) { if (ConfigSettings.verboseLogs.Value && time - timeLoggedPreventedScroll > 1f) { timeLoggedPreventedScroll = time; } return false; } } return true; } } [HarmonyPatch] internal static class PlayerPatcher { [CompilerGenerated] private sealed class <>c__DisplayClass25_0 { public GrabbableObject __instance; } private static int INTERACTABLE_OBJECT_MASK = 0; public static int vanillaHotbarSize = 4; private static bool initialized = false; private static bool suppressNextAutoSwitchFromNoScrapDrop = false; private static int suppressedNoScrapSlotIndex = -1; private static int suppressExpireFrame = -1; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static Dictionary<PlayerControllerB, ReservedPlayerData> allPlayerData => ReservedPlayerData.allPlayerData; public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData; public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked; private static bool IsNoScrapSlotName(string name) { if (string.IsNullOrEmpty(name)) { return false; } string text = name.Trim().ToLowerInvariant(); if (!(text == "no_scrap_1")) { return text == "no_scrap_2"; } return true; } private static void ArmNoScrapDropSuppression(PlayerControllerB controller, ReservedPlayerData playerData) { if (!((Object)(object)controller == (Object)null) && playerData != null && playerData.IsReservedItemSlot(controller.currentItemSlot)) { ReservedItemSlotData currentlySelectedReservedItemSlot = playerData.GetCurrentlySelectedReservedItemSlot(); if (currentlySelectedReservedItemSlot != null && IsNoScrapSlotName(currentlySelectedReservedItemSlot.slotName)) { suppressedNoScrapSlotIndex = controller.currentItemSlot; suppressNextAutoSwitchFromNoScrapDrop = true; suppressExpireFrame = Time.frameCount + 6; Plugin.Log($"[NO_SCRAP] Armed keep-focus suppression at slot {suppressedNoScrapSlotIndex} (expires frame {suppressExpireFrame})."); } } } private static void ClearNoScrapDropSuppression() { suppressNextAutoSwitchFromNoScrapDrop = false; suppressedNoScrapSlotIndex = -1; suppressExpireFrame = -1; } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] private static void InitSession(StartOfRound __instance) { initialized = false; vanillaHotbarSize = 4; ReservedPlayerData.allPlayerData?.Clear(); ClearNoScrapDropSuppression(); } [HarmonyPatch(typeof(PlayerControllerB), "Awake")] [HarmonyPostfix] private static void InitializePlayerController(PlayerControllerB __instance) { if (!initialized) { vanillaHotbarSize = __instance.ItemSlots.Length; INTERACTABLE_OBJECT_MASK = (int)Traverse.Create((object)__instance).Field("interactableObjectsMask").GetValue(); initialized = true; } } [HarmonyPatch(typeof(PlayerControllerB), "Start")] [HarmonyPrefix] private static void InitializePlayerControllerLate(PlayerControllerB __instance) { ReservedPlayerData value = new ReservedPlayerData(__instance); if (!allPlayerData.ContainsKey(__instance)) { Plugin.Log("Initializing ReservedPlayerData for player: " + ((Object)__instance).name); allPlayerData.Add(__instance, value); } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] private static void CheckForChangedInventorySize(PlayerControllerB __instance) { if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || reservedHotbarSize <= 0 || value.hotbarSize == __instance.ItemSlots.Length) { return; } value.hotbarSize = __instance.ItemSlots.Length; int num = -1; if ((Object)(object)__instance == (Object)(object)localPlayerController) { if (HUDPatcher.reservedItemSlots != null && HUDPatcher.reservedItemSlots.Count > 0) { num = Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, HUDPatcher.reservedItemSlots[0]); Plugin.Log("OnUpdateInventorySize A for local player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num); } if (num == -1) { for (int i = 0; i < HUDManager.Instance.itemSlotIconFrames.Length; i++) { if (((Object)HUDManager.Instance.itemSlotIconFrames[i]).name.ToLower().Contains("reserved")) { num = i; Plugin.Log("OnUpdateInventorySize B for local player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num); break; } } } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (ReservedPlayerData.allPlayerData.TryGetValue(val, out var value2) && value2 != value && reservedHotbarSize > 0 && value2.hotbarSize != val.ItemSlots.Length) { value2.reservedHotbarStartIndex = num; } } } if (num == -1) { num = value.reservedHotbarStartIndex; Plugin.Log("OnUpdateInventorySize C for player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num); } if (num == -1) { num = vanillaHotbarSize; Plugin.Log("OnUpdateInventorySize D for player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num); } value.reservedHotbarStartIndex = num; if (value.reservedHotbarStartIndex < 0) { Plugin.LogError("Set new reserved start index to slot: " + value.reservedHotbarStartIndex + "."); } if (value.reservedHotbarEndIndexExcluded - 1 >= value.playerController.ItemSlots.Length) { Plugin.LogError("Set new reserved start index to slot: " + value.reservedHotbarStartIndex + " Last reserved slot index: " + (value.reservedHotbarEndIndexExcluded - 1) + " Inventory size: " + value.playerController.ItemSlots.Length + "."); } if (value.isLocalPlayer) { HUDPatcher.UpdateUI(); } } [HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")] [HarmonyPrefix] private static bool BeginGrabReservedItemPrefix(PlayerControllerB __instance) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !HUDPatcher.hasReservedItemSlotsAndEnabled) { return true; } localPlayerData.grabbingReservedItemSlotData = null; localPlayerData.grabbingReservedItemData = null; localPlayerData.grabbingReservedItem = null; localPlayerData.previousHotbarIndex = -1; if (__instance.twoHanded || __instance.sinkingValue > 0.73f) { return true; } RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Ray(((Component)__instance.gameplayCamera).transform.position, ((Component)__instance.gameplayCamera).transform.forward), ref val, __instance.grabDistance, INTERACTABLE_OBJECT_MASK) && ((Component)((RaycastHit)(ref val)).collider).gameObject.layer != 8 && ((Component)((RaycastHit)(ref val)).collider).tag == "PhysicsProp") { GrabbableObject component = ((Component)((Component)((RaycastHit)(ref val)).collider).transform).gameObject.GetComponent<GrabbableObject>(); if ((Object)(object)component != (Object)null && !__instance.inSpecialInteractAnimation && !component.isHeld && !component.isPocketed) { NetworkObject networkObject = ((NetworkBehaviour)component).NetworkObject; if ((Object)(object)networkObject != (Object)null && networkObject.IsSpawned) { if (SessionManager.TryGetUnlockedItemData(component, out var itemData)) { localPlayerData.grabbingReservedItemData = itemData; localPlayerData.grabbingReservedItem = component; localPlayerData.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1); ReservedItemSlotData firstEmptySlotForReservedItem = localPlayerData.GetFirstEmptySlotForReservedItem(itemData.itemName); if (firstEmptySlotForReservedItem != null) { localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForReservedItem; Plugin.Log($"Beginning grab on reserved item: {itemData.itemName} -> slot {firstEmptySlotForReservedItem.slotName} (prev slot {localPlayerData.previousHotbarIndex})"); } else if (ItemNameMap.IsZeroValueScrap(component)) { ReservedItemSlotData firstEmptySlotForZeroValueScrap = localPlayerData.GetFirstEmptySlotForZeroValueScrap(); if (firstEmptySlotForZeroValueScrap != null) { localPlayerData.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__"); localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap; Plugin.Log($"Reserved full; routing IsZeroValueScrap into {firstEmptySlotForZeroValueScrap.slotName} (prev slot {localPlayerData.previousHotbarIndex})"); } } } else if (ItemNameMap.IsZeroValueScrap(component)) { ReservedItemSlotData firstEmptySlotForZeroValueScrap2 = localPlayerData.GetFirstEmptySlotForZeroValueScrap(); if (firstEmptySlotForZeroValueScrap2 != null) { localPlayerData.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__"); localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap2; localPlayerData.grabbingReservedItem = component; localPlayerData.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1); Plugin.Log($"Beginning grab on zero-value scrap into slot: {firstEmptySlotForZeroValueScrap2.slotName} (prev slot {localPlayerData.previousHotbarIndex})"); } } } } } return true; } [HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")] [HarmonyPostfix] private static void BeginGrabReservedItemPostfix(PlayerControllerB __instance) { if (localPlayerData == null || !localPlayerData.isGrabbingReservedItem || localPlayerData.IsReservedItemSlot(localPlayerData.previousHotbarIndex)) { return; } if (localPlayerData.grabbingReservedItemSlotData == null && localPlayerData.grabbingReservedItemData != null) { ReservedItemSlotData firstEmptySlotForReservedItem = localPlayerData.GetFirstEmptySlotForReservedItem(localPlayerData.grabbingReservedItemData.itemName); if (firstEmptySlotForReservedItem != null) { localPlayerData.grabbingReservedItemSlotData = firstEmptySlotForReservedItem; } } if (localPlayerData.grabbingReservedItemSlotData == null || (!localPlayerData.grabbingReservedItemSlotData.AutoSwitchOnPickup && !IsNoScrapSlotName(localPlayerData.grabbingReservedItemSlotData.slotName))) { SetSpecialGrabAnimationBool(__instance, setTrue: false, __instance.currentlyHeldObjectServer); GrabbableObject previouslyHeldItem = localPlayerData.previouslyHeldItem; if ((Object)(object)previouslyHeldItem != (Object)null) { SetSpecialGrabAnimationBool(__instance, setTrue: true, previouslyHeldItem); } __instance.playerBodyAnimator.SetBool("GrabValidated", true); __instance.playerBodyAnimator.SetBool("GrabInvalidated", false); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation"); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded"); if ((Object)(object)previouslyHeldItem != (Object)null) { __instance.playerBodyAnimator.ResetTrigger(previouslyHeldItem.itemProperties.pocketAnim); } __instance.twoHanded = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHanded; __instance.twoHandedAnimation = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHandedAnimation; } } [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")] [HarmonyPrefix] private static void GrabReservedItemClientRpcPrefix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !NetworkHelper.IsClientExecStage((NetworkBehaviour)(object)__instance) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value)) { return; } NetworkObject val = default(NetworkObject); GrabbableObject val2 = default(GrabbableObject); if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening && grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2)) { if (SessionManager.TryGetUnlockedItemData(val2, out var itemData)) { ReservedItemSlotData firstEmptySlotForReservedItem = value.GetFirstEmptySlotForReservedItem(itemData.itemName); if (firstEmptySlotForReservedItem != null) { value.grabbingReservedItemSlotData = firstEmptySlotForReservedItem; value.grabbingReservedItemData = itemData; value.grabbingReservedItem = val2; value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1); return; } if (ItemNameMap.IsZeroValueScrap(val2)) { ReservedItemSlotData firstEmptySlotForZeroValueScrap = value.GetFirstEmptySlotForZeroValueScrap(); if (firstEmptySlotForZeroValueScrap != null) { value.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap; value.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__"); value.grabbingReservedItem = val2; value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1); return; } } } else if (ItemNameMap.IsZeroValueScrap(val2)) { ReservedItemSlotData firstEmptySlotForZeroValueScrap2 = value.GetFirstEmptySlotForZeroValueScrap(); if (firstEmptySlotForZeroValueScrap2 != null) { value.grabbingReservedItemSlotData = firstEmptySlotForZeroValueScrap2; value.grabbingReservedItemData = new ReservedItemData("__ZERO_VALUE_SCRAP__"); value.grabbingReservedItem = val2; value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1); return; } } } value.grabbingReservedItemSlotData = null; value.grabbingReservedItemData = null; value.grabbingReservedItem = null; value.previousHotbarIndex = -1; } [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")] [HarmonyPostfix] private static void GrabReservedItemClientRpcPostfix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance) { if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !NetworkHelper.IsClientExecStage((NetworkBehaviour)(object)__instance) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || !value.isGrabbingReservedItem) { return; } if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening) { NetworkObject val = default(NetworkObject); GrabbableObject val2 = default(GrabbableObject); if (grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2)) { if (value.grabbingReservedItemSlotData != null) { bool flag = value.grabbingReservedItemSlotData.AutoSwitchOnPickup || IsNoScrapSlotName(value.grabbingReservedItemSlotData.slotName); if (!value.IsReservedItemSlot(value.previousHotbarIndex)) { if (!flag) { if ((Object)(object)value.previouslyHeldItem != (Object)null) { value.previouslyHeldItem.EnableItemMeshes(true); } ReservedItemsPatcher.ForceEnableItemMesh(value.grabbingReservedItem, enabled: false); Traverse.Create((object)val2).Field("previousPlayerHeldBy").SetValue((object)__instance); if (value.isLocalPlayer) { int num = value.reservedHotbarStartIndex + value.grabbingReservedItemSlotData.GetReservedItemSlotIndex(); ((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().SetBool("selectedSlot", false); ((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().SetBool("selectedSlot", true); ((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().Play("PanelLines", 0, 1f); ((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().Play("PanelEnlarge", 0, 1f); } else { SwitchToItemSlot(__instance, value.previousHotbarIndex); } SetSpecialGrabAnimationBool(__instance, setTrue: false, __instance.currentlyHeldObjectServer); GrabbableObject previouslyHeldItem = value.previouslyHeldItem; if ((Object)(object)previouslyHeldItem != (Object)null) { SetSpecialGrabAnimationBool(__instance, setTrue: true, previouslyHeldItem); } __instance.playerBodyAnimator.SetBool("GrabValidated", true); __instance.playerBodyAnimator.SetBool("GrabInvalidated", false); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation"); __instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded"); if ((Object)(object)previouslyHeldItem != (Object)null) { __instance.playerBodyAnimator.ResetTrigger(previouslyHeldItem.itemProperties.pocketAnim); } __instance.twoHanded = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHanded; __instance.twoHandedAnimation = (Object)(object)previouslyHeldItem != (Object)null && previouslyHeldItem.itemProperties.twoHandedAnimation; } else { int num2 = value.reservedHotbarStartIndex + val