using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LCVR.Managers;
using LethalCompanyInputUtils.Api;
using ReservedItemSlotCore.Compatibility;
using ReservedItemSlotCore.Config;
using ReservedItemSlotCore.Data;
using ReservedItemSlotCore.Input;
using ReservedItemSlotCore.Networking;
using ReservedItemSlotCore.Patches;
using TMPro;
using TooManyEmotes;
using TooManyEmotes.Patches;
using TooManyEmotes.UI;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ReservedItemSlotCore")]
[assembly: AssemblyDescription("Mod made by flipf17")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReservedItemSlotCore")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("238ce080-e339-46b6-9b08-992a950453a1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("ReservedFlashlightSlot")]
[assembly: InternalsVisibleTo("ReservedWalkieSlot")]
[assembly: InternalsVisibleTo("ReservedWeaponSlot")]
[assembly: InternalsVisibleTo("ReservedSprayPaintSlot")]
[assembly: InternalsVisibleTo("ReservedUtilitySlot")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ReservedItemSlotCore
{
[HarmonyPatch]
internal static class ItemNameMap
{
private static Dictionary<string, Item> originalNameToItemMap = new Dictionary<string, Item>();
private static Dictionary<Item, string> itemToNameMap = new Dictionary<Item, string>();
[HarmonyPatch(typeof(StartOfRound), "Start")]
[HarmonyPrefix]
private static void RecordOriginalItemNames(StartOfRound __instance)
{
List<Item> list = __instance?.allItemsList?.itemsList;
if (list == null)
{
Plugin.LogError("Failed to record original item names. This might be fine if you're not using translation/localization mods. (no guarantees)");
return;
}
foreach (Item item in list)
{
string text = item?.itemName;
if (!string.IsNullOrEmpty(text))
{
if (!itemToNameMap.ContainsKey(item))
{
itemToNameMap.Add(item, text);
}
if (!originalNameToItemMap.ContainsKey(text))
{
originalNameToItemMap.Add(text, item);
}
}
}
}
internal static string GetItemName(GrabbableObject grabbableObject)
{
if ((Object)(object)grabbableObject?.itemProperties == (Object)null)
{
return "";
}
string itemName = GetItemName(grabbableObject.itemProperties);
return (itemName != null) ? itemName : "";
}
internal static string GetItemName(Item item)
{
if ((Object)(object)item == (Object)null)
{
return "";
}
if (itemToNameMap.TryGetValue(item, out var value) && value != null)
{
return value;
}
return "";
}
}
[BepInPlugin("FlipMods.ReservedItemSlotCore", "ReservedItemSlotCore", "2.0.55")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal class Plugin : BaseUnityPlugin
{
private Harmony _harmony;
public static Plugin instance;
private static ManualLogSource logger;
public static List<ReservedItemSlotData> customItemSlots = new List<ReservedItemSlotData>();
private void Awake()
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
instance = this;
CreateCustomLogger();
ConfigSettings.BindConfigSettings();
AddCustomItemSlots();
if (InputUtilsCompat.Enabled)
{
InputUtilsCompat.Init();
}
_harmony = new Harmony("ReservedItemSlotCore");
PatchAll();
Log("ReservedItemSlotCore loaded");
}
private void AddCustomItemSlots()
{
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
foreach (CustomItemSlotConfigEntry customItemSlotConfig in ConfigSettings.customItemSlotConfigs)
{
if (!(customItemSlotConfig.customItemSlotName == "") && customItemSlotConfig.customItemSlotItems.Length != 0)
{
ReservedItemSlotData reservedItemSlotData = ReservedItemSlotData.CreateReservedItemSlotData(customItemSlotConfig.customItemSlotName, customItemSlotConfig.customItemSlotPriority, customItemSlotConfig.customItemSlotPrice);
string[] customItemSlotItems = customItemSlotConfig.customItemSlotItems;
foreach (string itemName in customItemSlotItems)
{
ReservedItemData itemData = new ReservedItemData(itemName);
reservedItemSlotData.AddItemToReservedItemSlot(itemData);
}
customItemSlots.Add(reservedItemSlotData);
}
}
}
private void PatchAll()
{
IEnumerable<Type> enumerable;
try
{
enumerable = Assembly.GetExecutingAssembly().GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
enumerable = ex.Types.Where((Type t) => t != null);
}
foreach (Type item in enumerable)
{
try
{
_harmony.PatchAll(item);
}
catch
{
}
}
}
private void CreateCustomLogger()
{
try
{
logger = Logger.CreateLogSource(string.Format("{0}-{1}", "ReservedItemSlotCore", "2.0.55"));
}
catch
{
logger = ((BaseUnityPlugin)this).Logger;
}
}
public static void Log(string message)
{
logger.LogInfo((object)message);
}
public static void LogError(string message)
{
logger.LogError((object)message);
}
public static void LogWarning(string message)
{
logger.LogWarning((object)message);
}
public static void LogVerbose(string message)
{
if (ConfigSettings.verboseLogs.Value)
{
logger.LogInfo((object)("[VERBOSE] " + message));
}
}
public static void LogErrorVerbose(string message)
{
if (ConfigSettings.verboseLogs.Value)
{
logger.LogError((object)("[VERBOSE] " + message));
}
}
public static void LogWarningVerbose(string message)
{
if (ConfigSettings.verboseLogs.Value)
{
logger.LogWarning((object)("[VERBOSE] " + message));
}
}
public static bool IsModLoaded(string guid)
{
return Chainloader.PluginInfos.ContainsKey(guid);
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "FlipMods.ReservedItemSlotCore";
public const string PLUGIN_NAME = "ReservedItemSlotCore";
public const string PLUGIN_VERSION = "2.0.55";
}
[HarmonyPatch]
public static class ReservedHotbarManager
{
public static int indexInHotbar = 0;
public static int indexInReservedHotbar = 0;
internal static List<ReservedItemSlotData> currentlyToggledItemSlots = new List<ReservedItemSlotData>();
public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData;
public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked;
public static bool isToggledInReservedSlots
{
get
{
ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot();
return (ReservedPlayerData.localPlayerData.inReservedHotbarSlots && Keybinds.pressedToggleKey) || (currentlyToggledItemSlots != null && currentlySelectedReservedItemSlot != null && currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot));
}
}
[HarmonyPatch(typeof(StartOfRound), "Awake")]
[HarmonyPrefix]
public static void InitSession(StartOfRound __instance)
{
currentlyToggledItemSlots = new List<ReservedItemSlotData>();
ReservedPlayerData.allPlayerData.Clear();
indexInHotbar = 0;
indexInReservedHotbar = -1;
}
public static void ForceToggleReservedHotbar(params ReservedItemSlotData[] reservedItemSlots)
{
if (((NetworkBehaviour)localPlayerController).IsOwner && localPlayerController.isPlayerControlled && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject) && HUDPatcher.hasReservedItemSlotsAndEnabled && reservedHotbarSize > 0 && CanSwapHotbars() && reservedItemSlots != null && reservedItemSlots.Length != 0 && !((Object)(object)localPlayerController == (Object)null))
{
currentlyToggledItemSlots = new List<ReservedItemSlotData>(reservedItemSlots);
int num = currentlyToggledItemSlots.First().GetReservedItemSlotIndex() + localPlayerData.reservedHotbarStartIndex;
bool active = ReservedPlayerData.localPlayerData.IsReservedItemSlot(num);
if (currentlyToggledItemSlots.Contains(localPlayerData.GetCurrentlySelectedReservedItemSlot()))
{
FocusReservedHotbarSlots(active: false);
return;
}
HUDPatcher.UpdateToggledReservedItemSlotsUI();
FocusReservedHotbarSlots(active, num);
}
}
public static void FocusReservedHotbarSlots(bool active, int forceSlot = -1)
{
if (!HUDPatcher.hasReservedItemSlotsAndEnabled || (reservedHotbarSize <= 0 && active) || (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved == active && (forceSlot == -1 || localPlayerData.currentItemSlot == forceSlot)))
{
return;
}
if (forceSlot != -1)
{
active = localPlayerData.IsReservedItemSlot(forceSlot);
}
ReservedPlayerData reservedPlayerData = ReservedPlayerData.localPlayerData;
indexInHotbar = Mathf.Clamp(indexInHotbar, 0, localPlayerController.ItemSlots.Length - 1);
indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0);
indexInReservedHotbar = Mathf.Clamp(indexInReservedHotbar, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1);
int num = Mathf.Clamp(localPlayerController.currentItemSlot, 0, localPlayerController.ItemSlots.Length);
int i = num;
bool flag = active;
if (flag && (!reservedPlayerData.IsReservedItemSlot(num) || forceSlot != -1))
{
indexInHotbar = num;
indexInHotbar = ((!reservedPlayerData.IsReservedItemSlot(indexInHotbar)) ? indexInHotbar : 0);
if (forceSlot != -1 && reservedPlayerData.IsReservedItemSlot(forceSlot))
{
indexInReservedHotbar = forceSlot;
}
i = indexInReservedHotbar;
if (!LCVR_Compat.Loaded && (Object)(object)localPlayerController.ItemSlots[i] == (Object)null && reservedPlayerData.GetNumHeldReservedItems() > 0)
{
for (i = reservedPlayerData.reservedHotbarStartIndex; i < reservedPlayerData.reservedHotbarEndIndexExcluded && !((Object)(object)localPlayerController.ItemSlots[i] != (Object)null); i++)
{
}
}
Plugin.LogVerbose("Focusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + ReservedPlayerData.localPlayerData.reservedHotbarStartIndex);
}
else if (!flag && (ReservedPlayerData.localPlayerData.IsReservedItemSlot(num) || forceSlot != -1))
{
indexInReservedHotbar = Mathf.Clamp(num, reservedPlayerData.reservedHotbarStartIndex, reservedPlayerData.reservedHotbarEndIndexExcluded - 1);
if (forceSlot != -1 && !reservedPlayerData.IsReservedItemSlot(forceSlot))
{
indexInHotbar = forceSlot;
}
i = indexInHotbar;
Plugin.LogVerbose("Unfocusing reserved hotbar slots. NewIndex: " + i + " OldIndex: " + num + " ReservedStartIndex: " + ReservedPlayerData.localPlayerData.reservedHotbarStartIndex);
}
if (i < 0)
{
Plugin.LogError("Swapping to hotbar slot: " + i + ". Maybe send these logs to Flip? :)");
}
else if (i >= localPlayerController.ItemSlots.Length)
{
Plugin.LogError("Swapping to hotbar slot: " + i + " InventorySize: " + localPlayerController.ItemSlots.Length + ". Maybe send these logs to Flip? :)");
}
SyncManager.SwapHotbarSlot(i);
if (localPlayerController.currentItemSlot != i)
{
Plugin.LogWarning("OnFocusReservedHotbarSlots - New hotbar index does not match target hotbar index. Tried to swap to index: " + i + " Current index: " + localPlayerController.currentItemSlot + " Tried swapping to reserved hotbar: " + active);
}
}
public static bool CanSwapHotbars()
{
if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
{
return false;
}
if (TooManyEmotes_Compat.Enabled && TooManyEmotes_Compat.IsLocalPlayerPerformingCustomEmote() && !TooManyEmotes_Compat.CanMoveWhileEmoting())
{
return false;
}
return ReservedPlayerData.localPlayerData.grabbingReservedItemData == null && !localPlayerController.isGrabbingObjectAnimation && !localPlayerController.quickMenuManager.isMenuOpen && !localPlayerController.inSpecialInteractAnimation && !localPlayerData.throwingObject && !localPlayerController.isTypingChat && !localPlayerController.twoHanded && !localPlayerController.activatingItem && !localPlayerController.jetpackControls && !localPlayerController.disablingJetpackControls && !localPlayerController.inTerminalMenu && !localPlayerController.isPlayerDead && !(localPlayerData.timeSinceSwitchingSlots < 0.3f);
}
internal static void OnSwapToReservedHotbar()
{
if (!localPlayerData.currentItemSlotIsReserved)
{
return;
}
if (localPlayerData.currentItemSlotIsReserved)
{
indexInReservedHotbar = localPlayerController.currentItemSlot;
}
ReservedItemSlotData currentlySelectedReservedItemSlot = localPlayerData.GetCurrentlySelectedReservedItemSlot();
if (isToggledInReservedSlots && currentlyToggledItemSlots != null && !currentlyToggledItemSlots.Contains(currentlySelectedReservedItemSlot))
{
currentlyToggledItemSlots = null;
}
if (HUDPatcher.reservedItemSlots == null)
{
return;
}
foreach (Image reservedItemSlot in HUDPatcher.reservedItemSlots)
{
CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>();
if ((Object)(object)component != (Object)null)
{
component.ignoreParentGroups = true;
}
}
}
internal static void OnSwapToVanillaHotbar()
{
if (localPlayerData.currentItemSlotIsReserved)
{
return;
}
if (!localPlayerData.currentItemSlotIsReserved)
{
indexInHotbar = localPlayerController.currentItemSlot;
}
currentlyToggledItemSlots = null;
if (HUDPatcher.reservedItemSlots == null)
{
return;
}
foreach (Image reservedItemSlot in HUDPatcher.reservedItemSlots)
{
CanvasGroup component = ((Component)reservedItemSlot).GetComponent<CanvasGroup>();
if ((Object)(object)component != (Object)null)
{
component.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value;
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
[HarmonyPrefix]
private static void RefocusReservedHotbarAfterAnimation(PlayerControllerB __instance)
{
if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !Keybinds.pressedToggleKey && Keybinds.holdingModifierKey != ReservedPlayerData.localPlayerData.currentItemSlotIsReserved && !isToggledInReservedSlots && CanSwapHotbars())
{
FocusReservedHotbarSlots(Keybinds.holdingModifierKey);
}
}
[HarmonyPatch(typeof(PlayerControllerB), "UpdateSpecialAnimationValue")]
[HarmonyPostfix]
private static void UpdateReservedHotbarAfterAnimation(bool specialAnimation, PlayerControllerB __instance)
{
if (HUDPatcher.hasReservedItemSlotsAndEnabled && !((Object)(object)__instance != (Object)(object)localPlayerController) && !specialAnimation && !Keybinds.pressedToggleKey && ReservedPlayerData.localPlayerData.currentItemSlotIsReserved != Keybinds.holdingModifierKey)
{
FocusReservedHotbarSlots(Keybinds.holdingModifierKey);
}
}
}
[HarmonyPatch]
public static class SessionManager
{
[CompilerGenerated]
private sealed class <>c__DisplayClass25_0
{
public bool force;
}
internal static List<ReservedItemSlotData> unlockedReservedItemSlots = new List<ReservedItemSlotData>();
internal static Dictionary<string, ReservedItemSlotData> unlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>();
internal static List<ReservedItemSlotData> pendingUnlockedReservedItemSlots = new List<ReservedItemSlotData>();
internal static Dictionary<string, ReservedItemSlotData> pendingUnlockedReservedItemSlotsDict = new Dictionary<string, ReservedItemSlotData>();
private static Dictionary<string, ReservedItemData> allReservedItemData = new Dictionary<string, ReservedItemData>();
internal static bool gameStarted = false;
internal static List<ReservedItemSlotData> allUnlockableReservedItemSlots => SyncManager.unlockableReservedItemSlots;
internal static Dictionary<string, ReservedItemSlotData> allUnlockableReservedItemSlotsDict => SyncManager.unlockableReservedItemSlotsDict;
public static int numReservedItemSlotsUnlocked => (unlockedReservedItemSlots != null) ? unlockedReservedItemSlots.Count : 0;
[HarmonyPatch(typeof(StartOfRound), "Awake")]
[HarmonyPrefix]
private static void InitSession()
{
unlockedReservedItemSlots.Clear();
unlockedReservedItemSlotsDict.Clear();
pendingUnlockedReservedItemSlots.Clear();
pendingUnlockedReservedItemSlotsDict.Clear();
allReservedItemData.Clear();
gameStarted = false;
}
[HarmonyPatch(typeof(StartOfRound), "ResetPlayersLoadedValueClientRpc")]
[HarmonyPostfix]
private static void OnStartGame(StartOfRound __instance, bool landingShip = false)
{
if (gameStarted || !NetworkManager.Singleton.IsClient)
{
return;
}
if (!SyncManager.hostHasMod && SyncManager.canUseModDisabledOnHost)
{
Plugin.LogWarning("Starting game while host does not have this mod, and ForceEnableReservedItemSlots is enabled in the config. Unlocking: " + ReservedItemSlotData.allReservedItemSlotData.Count + " slots. THIS MAY NOT BE STABLE");
SyncManager.isSynced = true;
SyncManager.enablePurchasingItemSlots = false;
ReservedPlayerData.localPlayerData.reservedHotbarStartIndex = ReservedPlayerData.localPlayerData.itemSlots.Length;
foreach (ReservedItemSlotData value in ReservedItemSlotData.allReservedItemSlotData.Values)
{
SyncManager.AddReservedItemSlotData(value);
UnlockReservedItemSlot(value);
}
pendingUnlockedReservedItemSlots?.Clear();
pendingUnlockedReservedItemSlotsDict?.Clear();
SyncManager.UpdateReservedItemsList();
}
gameStarted = true;
}
public static void UnlockReservedItemSlot(ReservedItemSlotData itemSlotData)
{
if (itemSlotData == null)
{
return;
}
Plugin.Log("Unlocking reserved item slot: " + itemSlotData.slotName);
if (!SyncManager.isSynced)
{
if (!pendingUnlockedReservedItemSlotsDict.ContainsKey(itemSlotData.slotName))
{
pendingUnlockedReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData);
pendingUnlockedReservedItemSlots.Add(itemSlotData);
}
return;
}
if (!unlockedReservedItemSlotsDict.ContainsKey(itemSlotData.slotName))
{
unlockedReservedItemSlotsDict.Add(itemSlotData.slotName, itemSlotData);
if (!unlockedReservedItemSlots.Contains(itemSlotData))
{
int num = -1;
for (int i = 0; i < unlockedReservedItemSlots.Count; i++)
{
if (itemSlotData.slotPriority > unlockedReservedItemSlots[i].slotPriority)
{
num = i;
break;
}
}
if (num == -1)
{
num = unlockedReservedItemSlots.Count;
}
for (int j = 0; j < unlockedReservedItemSlots.Count; j++)
{
ReservedItemSlotData reservedItemSlotData = unlockedReservedItemSlots[j];
}
unlockedReservedItemSlots.Insert(num, itemSlotData);
foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values)
{
if (unlockedReservedItemSlots.Count == 1)
{
value.reservedHotbarStartIndex = value.itemSlots.Length;
}
int index = value.reservedHotbarStartIndex + num;
List<GrabbableObject> list = new List<GrabbableObject>(value.itemSlots);
list.Insert(index, null);
value.playerController.ItemSlots = list.ToArray();
value.hotbarSize = list.Count;
}
}
}
if (ReservedHotbarManager.indexInReservedHotbar < ReservedPlayerData.localPlayerData.reservedHotbarStartIndex || ReservedHotbarManager.indexInReservedHotbar >= ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded)
{
ReservedHotbarManager.indexInReservedHotbar = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex;
}
UpdateReservedItemsList();
HUDPatcher.OnUpdateReservedItemSlots();
}
internal static void UnlockAllPendingItemSlots()
{
foreach (ReservedItemSlotData pendingUnlockedReservedItemSlot in pendingUnlockedReservedItemSlots)
{
UnlockReservedItemSlot(pendingUnlockedReservedItemSlot);
}
pendingUnlockedReservedItemSlots.Clear();
pendingUnlockedReservedItemSlotsDict.Clear();
}
public static ReservedItemSlotData GetUnlockedReservedItemSlot(int indexInUnlockedItemSlots)
{
return (unlockedReservedItemSlots != null && indexInUnlockedItemSlots >= 0 && indexInUnlockedItemSlots < unlockedReservedItemSlots.Count) ? unlockedReservedItemSlots[indexInUnlockedItemSlots] : null;
}
public static ReservedItemSlotData GetUnlockedReservedItemSlot(string itemSlotName)
{
if (TryGetUnlockedItemSlotData(itemSlotName, out var itemSlotData))
{
return itemSlotData;
}
return null;
}
public static bool IsItemSlotUnlocked(ReservedItemSlotData itemSlotData)
{
return itemSlotData != null && IsItemSlotUnlocked(itemSlotData.slotName);
}
public static bool IsItemSlotUnlocked(string itemSlotName)
{
return unlockedReservedItemSlotsDict.ContainsKey(itemSlotName);
}
internal static void UpdateReservedItemsList()
{
if (unlockedReservedItemSlots == null)
{
return;
}
allReservedItemData.Clear();
foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots)
{
if (unlockedReservedItemSlot.reservedItemData == null)
{
continue;
}
foreach (ReservedItemData value in unlockedReservedItemSlot.reservedItemData.Values)
{
if (!allReservedItemData.ContainsKey(value.itemName))
{
allReservedItemData.Add(value.itemName, value);
}
}
}
}
[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
[HarmonyPostfix]
private static void OnResetShip()
{
if (SyncManager.enablePurchasingItemSlots)
{
ResetProgressDelayed();
}
else if (!SyncManager.hostHasMod && SyncManager.canUseModDisabledOnHost)
{
SyncManager.isSynced = false;
ResetProgressDelayed(force: true);
}
gameStarted = false;
}
[HarmonyPatch(typeof(GameNetworkManager), "SaveGameValues")]
[HarmonyPostfix]
private static void OnSaveGameValues()
{
if (NetworkManager.Singleton.IsHost && StartOfRound.Instance.inShipPhase && SyncManager.enablePurchasingItemSlots)
{
SaveGameValues();
}
}
[HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")]
[HarmonyPostfix]
private static void OnLoadGameValues()
{
if (NetworkManager.Singleton.IsServer && SyncManager.isSynced && SyncManager.enablePurchasingItemSlots)
{
LoadGameValues();
}
}
internal static void ResetProgress(bool force = false)
{
if (!SyncManager.enablePurchasingItemSlots && !force)
{
return;
}
Plugin.Log("Resetting progress.");
foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values)
{
GrabbableObject[] itemSlots = value.playerController.ItemSlots;
List<GrabbableObject> list = new List<GrabbableObject>();
for (int i = 0; i < itemSlots.Length; i++)
{
if (i < value.reservedHotbarStartIndex || i >= value.reservedHotbarEndIndexExcluded)
{
list.Add(itemSlots[i]);
}
}
value.playerController.ItemSlots = list.ToArray();
}
unlockedReservedItemSlots?.Clear();
unlockedReservedItemSlotsDict?.Clear();
pendingUnlockedReservedItemSlots?.Clear();
pendingUnlockedReservedItemSlotsDict?.Clear();
List<Image> list2 = new List<Image>();
List<Image> list3 = new List<Image>();
for (int j = 0; j < HUDManager.Instance.itemSlotIconFrames.Length; j++)
{
Image val = HUDManager.Instance.itemSlotIconFrames[j];
Image item = HUDManager.Instance.itemSlotIcons[j];
if (!HUDPatcher.reservedItemSlots.Contains(val))
{
list2.Add(val);
list3.Add(item);
}
else
{
Object.Destroy((Object)(object)((Component)val).gameObject);
}
}
HUDPatcher.reservedItemSlots.Clear();
HUDManager.Instance.itemSlotIconFrames = list2.ToArray();
HUDManager.Instance.itemSlotIcons = list3.ToArray();
foreach (ReservedPlayerData value2 in ReservedPlayerData.allPlayerData.Values)
{
if (value2.playerController.currentItemSlot < 0 || value2.playerController.currentItemSlot >= value2.playerController.ItemSlots.Length)
{
PlayerPatcher.SwitchToItemSlot(value2.playerController, 0);
}
value2.hotbarSize = value2.itemSlots.Length;
value2.reservedHotbarStartIndex = value2.hotbarSize;
}
foreach (ReservedItemSlotData allUnlockableReservedItemSlot in allUnlockableReservedItemSlots)
{
if (allUnlockableReservedItemSlot.purchasePrice <= 0)
{
UnlockReservedItemSlot(allUnlockableReservedItemSlot);
}
}
if (SyncManager.hostHasMod)
{
}
HUDPatcher.OnUpdateReservedItemSlots();
if (NetworkManager.Singleton.IsServer)
{
ES3.DeleteKey("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName);
}
}
internal static void ResetProgressDelayed(bool force = false)
{
<>c__DisplayClass25_0 CS$<>8__locals0 = new <>c__DisplayClass25_0();
CS$<>8__locals0.force = force;
((MonoBehaviour)StartOfRound.Instance).StartCoroutine(Reset());
[IteratorStateMachine(typeof(<>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d))]
IEnumerator Reset()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <>c__DisplayClass25_0.<<ResetProgressDelayed>g__Reset|0>d(0)
{
<>4__this = CS$<>8__locals0
};
}
}
internal static void SaveGameValues()
{
if (!NetworkManager.Singleton.IsServer || unlockedReservedItemSlots == null)
{
return;
}
List<string> list = new List<string>();
foreach (ReservedItemSlotData unlockedReservedItemSlot in unlockedReservedItemSlots)
{
if (!list.Contains(unlockedReservedItemSlot.slotName))
{
list.Add(unlockedReservedItemSlot.slotName);
}
}
Plugin.LogWarning("Saving " + list.Count + " unlocked reserved item slots.");
string[] array = list.ToArray();
ES3.Save<string[]>("ReservedItemSlots.UnlockedItemSlots", array, GameNetworkManager.Instance.currentSaveFileName);
}
internal static void LoadGameValues()
{
if (!NetworkManager.Singleton.IsServer || SyncManager.unlockableReservedItemSlotsDict == null)
{
return;
}
string[] array = ES3.Load<string[]>("ReservedItemSlots.UnlockedItemSlots", GameNetworkManager.Instance.currentSaveFileName, new string[0]);
Plugin.LogWarning("Loading " + array.Length + " unlocked reserved item slots.");
int num = 0;
string[] array2 = array;
foreach (string key in array2)
{
if (SyncManager.unlockableReservedItemSlotsDict.TryGetValue(key, out var value))
{
num++;
UnlockReservedItemSlot(value);
SyncManager.SendUnlockItemSlotToClients(value.slotId);
}
}
Plugin.Log("Loaded " + num + " unlocked reserved items.");
}
public static bool IsReservedItem(GrabbableObject grabbableObject)
{
string itemName = ItemNameMap.GetItemName(grabbableObject);
return IsReservedItem(itemName) || ((Object)(object)grabbableObject?.itemProperties != (Object)null && IsReservedItem(grabbableObject.itemProperties.itemName));
}
public static bool IsReservedItem(string itemName)
{
return allReservedItemData.ContainsKey(itemName);
}
public static bool TryGetUnlockedItemSlotData(string itemSlotName, out ReservedItemSlotData itemSlotData)
{
itemSlotData = null;
unlockedReservedItemSlotsDict.TryGetValue(itemSlotName, out itemSlotData);
return itemSlotData != null;
}
public static bool TryGetUnlockedItemData(GrabbableObject item, out ReservedItemData itemData)
{
itemData = null;
string itemName = ItemNameMap.GetItemName(item);
return TryGetUnlockedItemData(itemName, out itemData) || ((Object)(object)item?.itemProperties != (Object)null && TryGetUnlockedItemData(item.itemProperties.itemName, out itemData));
}
public static bool TryGetUnlockedItemData(string itemName, out ReservedItemData itemData)
{
itemData = null;
return allReservedItemData.TryGetValue(itemName, out itemData);
}
}
}
namespace ReservedItemSlotCore.Patches
{
[HarmonyPatch]
internal static class DropReservedItemPatcher
{
[CompilerGenerated]
private sealed class <>c__DisplayClass9_0
{
public PlayerControllerB playerController;
public float time;
internal bool <SwitchToItemSlotAfterDelay>b__0()
{
return (Object)(object)playerController.currentlyHeldObjectServer == (Object)null || Time.time - time >= 5f;
}
}
[CompilerGenerated]
private sealed class <SwitchToItemSlotAfterDelay>d__9 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public PlayerControllerB playerController;
public int slot;
private <>c__DisplayClass9_0 <>8__1;
private ReservedPlayerData <playerData>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <SwitchToItemSlotAfterDelay>d__9(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>8__1 = null;
<playerData>5__2 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Expected O, but got Unknown
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>8__1 = new <>c__DisplayClass9_0();
<>8__1.playerController = playerController;
<>8__1.time = Time.time;
if ((Object)(object)<>8__1.playerController == (Object)(object)localPlayerController)
{
<>2__current = (object)new WaitUntil((Func<bool>)(() => (Object)(object)<>8__1.playerController.currentlyHeldObjectServer == (Object)null || Time.time - <>8__1.time >= 5f));
<>1__state = 1;
return true;
}
goto IL_009f;
case 1:
<>1__state = -1;
goto IL_009f;
case 2:
{
<>1__state = -1;
playersDiscardingItems.Remove(<>8__1.playerController);
if (<>8__1.playerController.currentItemSlot != slot && Time.time - <>8__1.time < 3f && ReservedPlayerData.allPlayerData.TryGetValue(<>8__1.playerController, out <playerData>5__2))
{
<playerData>5__2.CallSwitchToItemSlot(slot);
}
return false;
}
IL_009f:
<>2__current = (object)new WaitForEndOfFrame();
<>1__state = 2;
return true;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private static HashSet<PlayerControllerB> playersDiscardingItems = new HashSet<PlayerControllerB>();
private static float timeLoggedPreventedScroll = 0f;
private static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
[HarmonyPatch(typeof(PlayerControllerB), "SetObjectAsNoLongerHeld")]
[HarmonyPatch(typeof(PlayerControllerB), "PlaceGrabbableObject")]
[HarmonyPostfix]
public static void OnObjectNoLongerHeld(PlayerControllerB __instance)
{
OnDiscardItem(__instance);
}
[HarmonyPatch(typeof(PlayerControllerB), "DestroyItemInSlot")]
[HarmonyPostfix]
public static void OnDestroyItem(int itemSlot, PlayerControllerB __instance)
{
ReservedPlayerData localPlayerData = ReservedPlayerData.localPlayerData;
if (localPlayerData == null)
{
return;
}
if (SessionManager.unlockedReservedItemSlots == null)
{
Plugin.LogErrorVerbose("[OnItemDestroy] Unlocked reserved item slots no initialized? You might want to let Flip know :) (This may be caused from another mod, or a new update)");
}
else if (itemSlot >= ReservedPlayerData.localPlayerData.reservedHotbarStartIndex && itemSlot < ReservedPlayerData.localPlayerData.reservedHotbarEndIndexExcluded)
{
if (itemSlot == __instance.currentItemSlot)
{
OnDiscardItem(__instance);
}
if ((Object)(object)__instance == (Object)(object)localPlayerController)
{
HUDPatcher.UpdateUI();
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "DespawnHeldObjectOnClient")]
[HarmonyPostfix]
public static void OnDespawnItem(PlayerControllerB __instance)
{
if ((Object)(object)__instance == (Object)(object)localPlayerController)
{
HUDPatcher.UpdateUI();
}
}
[HarmonyPatch(typeof(PlayerControllerB), "DropAllHeldItems")]
[HarmonyPostfix]
public static void OnDropAllHeldItems(PlayerControllerB __instance)
{
if ((Object)(object)__instance == (Object)(object)localPlayerController)
{
HUDPatcher.UpdateUI();
}
}
private static void OnDiscardItem(PlayerControllerB playerController)
{
if (!((Object)(object)playerController != (Object)null) || playersDiscardingItems.Contains(playerController) || !ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value) || !value.currentItemSlotIsReserved || !((Object)(object)value.currentlySelectedItem == (Object)null))
{
return;
}
if (value.GetNumHeldReservedItems() > 0)
{
int num = value.CallGetNextItemSlot(forward: true);
if (!value.IsReservedItemSlot(num) && !value.IsReservedItemSlot(ReservedHotbarManager.indexInHotbar))
{
num = ReservedHotbarManager.indexInHotbar;
}
playersDiscardingItems.Add(playerController);
((MonoBehaviour)playerController).StartCoroutine(SwitchToItemSlotAfterDelay(playerController, num));
}
if ((Object)(object)playerController == (Object)(object)localPlayerController)
{
HUDPatcher.UpdateUI();
}
}
[IteratorStateMachine(typeof(<SwitchToItemSlotAfterDelay>d__9))]
private static IEnumerator SwitchToItemSlotAfterDelay(PlayerControllerB playerController, int slot)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <SwitchToItemSlotAfterDelay>d__9(0)
{
playerController = playerController,
slot = slot
};
}
[HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")]
[HarmonyPrefix]
public static bool PreventItemSwappingDroppingItem(CallbackContext context, PlayerControllerB __instance)
{
if ((Object)(object)__instance == (Object)(object)localPlayerController && playersDiscardingItems.Contains(__instance))
{
float time = Time.time;
if (ConfigSettings.verboseLogs.Value && time - timeLoggedPreventedScroll > 1f)
{
timeLoggedPreventedScroll = time;
Plugin.LogWarning("[VERBOSE] Prevented item swap. Player is currently discarding an item? This should be fine, unless these logs are spamming.");
}
return false;
}
return true;
}
}
[HarmonyPatch]
public static class HUDPatcher
{
private static bool usingController = false;
private static float itemSlotWidth;
internal static float itemSlotSpacing;
private static float defaultItemSlotPosX;
private static float defaultItemSlotPosY;
private static float defaultItemSlotSpacing;
private static Vector2 defaultItemSlotSize;
private static Vector2 defaultItemIconSize;
private static TextMeshProUGUI hotkeyTooltip;
public static List<Image> reservedItemSlots = new List<Image>();
public static HashSet<ReservedItemSlotData> toggledReservedItemSlots = new HashSet<ReservedItemSlotData>();
private static bool lerpToggledItemSlotFrames = false;
private static float largestPositionDifference = 0f;
private static bool currentApplyHotbarPlusSize;
private static bool currentHideEmptySlots;
public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData;
public static bool localPlayerUsingController => (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.localPlayerUsingController;
private static float currentItemSlotScale => itemSlotWidth / defaultItemSlotSize.x;
public static bool hasReservedItemSlotsAndEnabled => reservedItemSlots != null && reservedItemSlots.Count > 0 && ((Component)reservedItemSlots[0]).gameObject.activeSelf && ((Behaviour)reservedItemSlots[0]).enabled;
[HarmonyPatch(typeof(HUDManager), "Awake")]
[HarmonyPostfix]
public static void Initialize(HUDManager __instance)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
CanvasScaler componentInParent = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<CanvasScaler>();
AspectRatioFitter componentInParent2 = ((Component)__instance.itemSlotIconFrames[0]).GetComponentInParent<AspectRatioFitter>();
itemSlotWidth = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta.x;
itemSlotSpacing = 1.125f * itemSlotWidth;
defaultItemSlotPosX = componentInParent.referenceResolution.x / 2f / componentInParent2.aspectRatio - itemSlotWidth / 4f;
defaultItemSlotSpacing = itemSlotSpacing;
defaultItemSlotSize = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.sizeDelta;
defaultItemIconSize = ((Graphic)__instance.itemSlotIcons[0]).rectTransform.sizeDelta;
defaultItemSlotPosY = ((Graphic)__instance.itemSlotIconFrames[0]).rectTransform.anchoredPosition.y;
reservedItemSlots.Clear();
}
[HarmonyPatch(typeof(StartOfRound), "Update")]
[HarmonyPrefix]
public static void UpdateUsingController(StartOfRound __instance)
{
if (!((Object)(object)__instance.localPlayerController == (Object)null) && !((Object)(object)hotkeyTooltip == (Object)null) && ((Component)hotkeyTooltip).gameObject.activeSelf && ((Behaviour)hotkeyTooltip).enabled)
{
if (__instance.localPlayerUsingController != usingController)
{
usingController = __instance.localPlayerUsingController;
UpdateHotkeyTooltipText();
}
LerpItemSlotFrames();
}
}
private static void LerpItemSlotFrames()
{
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
if (!lerpToggledItemSlotFrames)
{
return;
}
if (largestPositionDifference < 2f && largestPositionDifference != -1f)
{
lerpToggledItemSlotFrames = false;
}
for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++)
{
ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i);
Image val = HUDManager.Instance.itemSlotIconFrames[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i];
bool flag = unlockedReservedItemSlot.slotPriority >= 0 || !ConfigSettings.displayNegativePrioritySlotsLeftSideOfScreen.Value;
Vector2 anchoredPosition = ((Graphic)val).rectTransform.anchoredPosition;
anchoredPosition.x = (defaultItemSlotPosX + (defaultItemSlotSize.x - itemSlotWidth) / 2f) * (float)(flag ? 1 : (-1));
if (ReservedHotbarManager.isToggledInReservedSlots && ReservedHotbarManager.currentlyToggledItemSlots != null && ReservedHotbarManager.currentlyToggledItemSlots.Contains(unlockedReservedItemSlot))
{
anchoredPosition.x += itemSlotWidth / 2f * (float)((!flag) ? 1 : (-1));
}
float num = Mathf.Abs(anchoredPosition.x - ((Graphic)val).rectTransform.anchoredPosition.x);
largestPositionDifference = Mathf.Max(largestPositionDifference, num);
if (lerpToggledItemSlotFrames)
{
((Graphic)val).rectTransform.anchoredPosition = Vector2.Lerp(((Graphic)val).rectTransform.anchoredPosition, anchoredPosition, Time.deltaTime * 10f);
}
else
{
((Graphic)val).rectTransform.anchoredPosition = anchoredPosition;
}
}
}
public static void OnUpdateReservedItemSlots()
{
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
if (reservedItemSlots == null || SessionManager.numReservedItemSlotsUnlocked <= 0 || reservedItemSlots.Count == SessionManager.numReservedItemSlotsUnlocked)
{
return;
}
List<Image> list = new List<Image>(HUDManager.Instance.itemSlotIconFrames);
List<Image> list2 = new List<Image>(HUDManager.Instance.itemSlotIcons);
for (int i = reservedItemSlots.Count; i < SessionManager.numReservedItemSlotsUnlocked; i++)
{
GameObject val = Object.Instantiate<GameObject>(((Component)list[0]).gameObject, ((Component)list[0]).transform.parent);
Image component = val.GetComponent<Image>();
Image component2 = ((Component)((Component)component).transform.GetChild(0)).GetComponent<Image>();
((Component)component).transform.localScale = ((Component)list[0]).transform.localScale;
((Transform)((Graphic)component).rectTransform).eulerAngles = ((Transform)((Graphic)list[0]).rectTransform).eulerAngles;
((Transform)((Graphic)component2).rectTransform).eulerAngles = ((Transform)((Graphic)list2[0]).rectTransform).eulerAngles;
CanvasGroup val2 = ((Component)component).gameObject.AddComponent<CanvasGroup>();
val2.ignoreParentGroups = ConfigSettings.preventReservedItemSlotFade.Value;
val2.alpha = 1f;
component.fillMethod = list[0].fillMethod;
component.sprite = list[0].sprite;
((Graphic)component).material = ((Graphic)list[0]).material;
if (Plugin.IsModLoaded("xuxiaolan.hotbarrd"))
{
component.overrideSprite = list[0].overrideSprite;
}
int index = ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + reservedItemSlots.Count;
list.Insert(index, component);
list2.Insert(index, component2);
reservedItemSlots.Add(component);
}
HUDManager.Instance.itemSlotIconFrames = list.ToArray();
HUDManager.Instance.itemSlotIcons = list2.ToArray();
UpdateUI();
}
public static void UpdateUI()
{
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0401: Unknown result type (might be due to invalid IL or missing references)
//IL_040f: Unknown result type (might be due to invalid IL or missing references)
//IL_0424: Unknown result type (might be due to invalid IL or missing references)
//IL_0431: Unknown result type (might be due to invalid IL or missing references)
//IL_043b: Unknown result type (might be due to invalid IL or missing references)
//IL_044f: Unknown result type (might be due to invalid IL or missing references)
//IL_0477: Unknown result type (might be due to invalid IL or missing references)
//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
//IL_030f: Unknown result type (might be due to invalid IL or missing references)
if (reservedItemSlots.Count != SessionManager.numReservedItemSlotsUnlocked)
{
Plugin.LogError("Called UpdateUI with mismatched unlocked reserved item slots and reserved item slot hud elements.");
return;
}
int num = 0;
int num2 = 0;
RectTransform val = null;
Vector2 anchoredPosition = default(Vector2);
for (int i = 0; i < SessionManager.numReservedItemSlotsUnlocked; i++)
{
ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(i);
int num3 = Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, reservedItemSlots[i]);
Image val2 = HUDManager.Instance.itemSlotIconFrames[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i];
Image val3 = HUDManager.Instance.itemSlotIcons[ReservedPlayerData.localPlayerData.reservedHotbarStartIndex + i];
((Graphic)val2).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIconFrames[0]).rectTransform.sizeDelta;
((Graphic)val3).rectTransform.sizeDelta = ((Graphic)HUDManager.Instance.itemSlotIcons[0]).rectTransform.sizeDelta;
if (HotbarPlus_Compat.Enabled && !ConfigSettings.applyHotbarPlusItemSlotSize.Value)
{
((Graphic)val2).rectTransform.sizeDelta = defaultItemSlotSize;
((Graphic)val3).rectTransform.sizeDelta = defaultItemIconSize;
}
itemSlotWidth = ((Graphic)val2).rectTransform.sizeDelta.x;
itemSlotSpacing = defaultItemSlotSpacing * currentItemSlotScale;
GrabbableObject reservedItem = ReservedPlayerData.localPlayerData.GetReservedItem(unlockedReservedItemSlot);
((Object)val2).name = "Slot" + i + " [ReservedItemSlot] (" + unlockedReservedItemSlot.slotName + ")";
((Vector2)(ref anchoredPosition))..ctor(defaultItemSlotPosX, defaultItemSlotPosY);
if (unlockedReservedItemSlot.slotPriority >= 0 || !ConfigSettings.displayNegativePrioritySlotsLeftSideOfScreen.Value)
{
anchoredPosition.x = defaultItemSlotPosX + (defaultItemSlotSize.x - itemSlotWidth) / 2f;
anchoredPosition.y = defaultItemSlotPosY + 36f * ((itemSlotWidth / defaultItemSlotSize.x - 1f) / 2f) + itemSlotSpacing * (float)num;
if (!ConfigSettings.hideEmptyReservedItemSlots.Value || (Object)(object)reservedItem != (Object)null || LCVR_Compat.Loaded)
{
if (!Object.op_Implicit((Object)(object)val))
{
val = ((Graphic)val2).rectTransform;
}
num++;
}
else
{
anchoredPosition.y = -1000f;
}
}
else
{
anchoredPosition.x = 0f - defaultItemSlotPosX - (defaultItemSlotSize.x - itemSlotWidth) / 2f;
anchoredPosition.y = defaultItemSlotPosY + 36f * ((itemSlotWidth / defaultItemSlotSize.x - 1f) / 2f) + itemSlotSpacing * (float)num2;
if (!ConfigSettings.hideEmptyReservedItemSlots.Value || (Object)(object)reservedItem != (Object)null || LCVR_Compat.Loaded)
{
num2++;
}
else
{
anchoredPosition.y = -1000f;
}
}
((Graphic)val2).rectTransform.anchoredPosition = anchoredPosition;
if ((Object)(object)reservedItem != (Object)null)
{
((Behaviour)val3).enabled = true;
val3.sprite = reservedItem.itemProperties.itemIcon;
}
else
{
((Behaviour)val3).enabled = false;
val3.sprite = null;
}
}
if (SessionManager.numReservedItemSlotsUnlocked > 0 && !ConfigSettings.hideFocusHotbarTooltip.Value)
{
if ((Object)(object)hotkeyTooltip == (Object)null)
{
hotkeyTooltip = new GameObject("ReservedItemSlotTooltip", new Type[2]
{
typeof(RectTransform),
typeof(TextMeshProUGUI)
}).GetComponent<TextMeshProUGUI>();
}
RectTransform rectTransform = ((TMP_Text)hotkeyTooltip).rectTransform;
((Transform)rectTransform).SetParent((Transform)(object)val);
if (Object.op_Implicit((Object)(object)val))
{
((Transform)rectTransform).localScale = Vector3.one;
rectTransform.sizeDelta = new Vector2(val.sizeDelta.x * 2f, 10f);
rectTransform.pivot = Vector2.one / 2f;
rectTransform.anchoredPosition3D = new Vector3(0f, 0f - rectTransform.sizeDelta.x / 2f - itemSlotWidth / 2f - 5f, 0f);
((TMP_Text)hotkeyTooltip).font = ((TMP_Text)HUDManager.Instance.controlTipLines[0]).font;
((TMP_Text)hotkeyTooltip).fontSize = 7f * (val.sizeDelta.x / defaultItemSlotSize.x);
((TMP_Text)hotkeyTooltip).alignment = (TextAlignmentOptions)4100;
UpdateHotkeyTooltipText();
}
else
{
((Transform)rectTransform).localScale = Vector3.zero;
}
}
currentApplyHotbarPlusSize = ConfigSettings.applyHotbarPlusItemSlotSize.Value;
currentHideEmptySlots = ConfigSettings.hideEmptyReservedItemSlots.Value;
}
public static void UpdateHotkeyTooltipText()
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)localPlayerController == (Object)null || (Object)(object)hotkeyTooltip == (Object)null || Keybinds.FocusReservedHotbarAction == null)
{
return;
}
int num = (localPlayerUsingController ? 1 : 0);
string text = "";
string text2 = "";
InputBinding val;
if (num >= 0 && num < Keybinds.FocusReservedHotbarAction.bindings.Count)
{
val = Keybinds.FocusReservedHotbarAction.bindings[num];
text = KeybindDisplayNames.GetKeybindDisplayName(((InputBinding)(ref val)).effectivePath);
}
else
{
Plugin.LogError("Failed to update FocusReservedHotbar keybind tooltip. Using controller: " + localPlayerUsingController + " NumFocusReservedHotbarActionBindings: " + Keybinds.FocusReservedHotbarAction.bindings.Count);
}
if (num >= 0 && num < Keybinds.ToggleFocusReservedHotbarAction.bindings.Count)
{
val = Keybinds.ToggleFocusReservedHotbarAction.bindings[num];
text2 = KeybindDisplayNames.GetKeybindDisplayName(((InputBinding)(ref val)).effectivePath);
}
else
{
Plugin.LogError("Failed to update ToggleFocusReservedHotbar keybind tooltip. Using controller: " + localPlayerUsingController + " NumToggleFocusReservedHotbarActionBindings: " + Keybinds.ToggleFocusReservedHotbarAction.bindings.Count);
}
((TMP_Text)hotkeyTooltip).text = "";
if (LCVR_Compat.LoadedAndEnabled)
{
return;
}
if (text != "")
{
((TMP_Text)hotkeyTooltip).text = $"Hold: [{text}]";
}
if (text2 != "" && text2 != text)
{
if (((TMP_Text)hotkeyTooltip).text != "")
{
TextMeshProUGUI obj = hotkeyTooltip;
((TMP_Text)obj).text = ((TMP_Text)obj).text + "\n";
}
TextMeshProUGUI obj2 = hotkeyTooltip;
((TMP_Text)obj2).text = ((TMP_Text)obj2).text + $"Toggle: [{text2}]";
}
}
public static void UpdateToggledReservedItemSlotsUI()
{
if (ReservedHotbarManager.currentlyToggledItemSlots != null)
{
toggledReservedItemSlots = new HashSet<ReservedItemSlotData>(ReservedHotbarManager.currentlyToggledItemSlots);
}
else
{
toggledReservedItemSlots.Clear();
}
lerpToggledItemSlotFrames = true;
largestPositionDifference = -1f;
}
private static float GetCurrentItemSlotSpacing()
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
try
{
Image val = HUDManager.Instance.itemSlotIconFrames[0];
Image val2 = HUDManager.Instance.itemSlotIconFrames[1];
if (((Object)val).name.ToLower().Contains("reserved") || ((Object)val2).name.ToLower().Contains("reserved"))
{
return defaultItemSlotSpacing;
}
return Mathf.Abs(((Graphic)val2).rectTransform.anchoredPosition.x - ((Graphic)val).rectTransform.anchoredPosition.x);
}
catch
{
}
return defaultItemSlotSpacing;
}
[HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")]
[HarmonyPostfix]
public static void OnCloseQuickMenu()
{
if (HotbarPlus_Compat.Enabled || currentHideEmptySlots != ConfigSettings.hideEmptyReservedItemSlots.Value)
{
UpdateUI();
}
}
}
[HarmonyPatch]
internal class MaskedEnemyPatcher
{
[HarmonyPatch(typeof(MaskedPlayerEnemy), "Awake")]
[HarmonyPrefix]
public static void InitMaskedEnemy(MaskedPlayerEnemy __instance)
{
if (ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value && !MaskedEnemyData.allMaskedEnemyData.ContainsKey(__instance))
{
MaskedEnemyData.allMaskedEnemyData.Add(__instance, new MaskedEnemyData(__instance));
}
}
[HarmonyPatch(typeof(MaskedPlayerEnemy), "OnDestroy")]
[HarmonyPrefix]
public static void OnDestroy(MaskedPlayerEnemy __instance)
{
if (MaskedEnemyData.allMaskedEnemyData.TryGetValue(__instance, out var value))
{
value.DestroyEquippedItems();
MaskedEnemyData.allMaskedEnemyData.Remove(__instance);
}
}
[HarmonyPatch(typeof(MaskedPlayerEnemy), "Update")]
[HarmonyPostfix]
public static void Update(MaskedPlayerEnemy __instance)
{
if (ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value && MaskedEnemyData.allMaskedEnemyData.TryGetValue(__instance, out var value) && (Object)(object)value.originallyMimickingPlayer == (Object)null && (Object)(object)value.maskedEnemy.mimickingPlayer != (Object)null)
{
AddReservedItemsToMaskedEnemy(__instance);
}
}
public static void AddReservedItemsToMaskedEnemy(MaskedPlayerEnemy maskedEnemy)
{
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
if (!ConfigSettings.showReservedItemsHolsteredMaskedEnemy.Value || !MaskedEnemyData.allMaskedEnemyData.TryGetValue(maskedEnemy, out var value))
{
return;
}
value.originallyMimickingPlayer = value.maskedEnemy.mimickingPlayer;
if (!ReservedPlayerData.allPlayerData.TryGetValue(value.originallyMimickingPlayer, out var value2))
{
Plugin.LogWarning("Failed to mimic player's equipped reserved items. Could not retrieve player data from: " + value.originallyMimickingPlayer.playerUsername);
return;
}
for (int i = value2.reservedHotbarStartIndex; i < Mathf.Min(value2.reservedHotbarEndIndexExcluded, value2.playerController.ItemSlots.Length); i++)
{
GrabbableObject val = value2.playerController.ItemSlots[i];
if ((Object)(object)val == (Object)null)
{
continue;
}
int num = i - value2.reservedHotbarStartIndex;
if (num < 0 || num >= SessionManager.unlockedReservedItemSlots.Count)
{
Plugin.LogWarning("Failed to add reserved item to MaskedEnemy. Could not get ReservedItemSlot at index: " + num + " Item: " + val.itemProperties.itemName + " SlotIndexInInventory: " + i + " ReservedHotbarStartIndex: " + value2.reservedHotbarStartIndex);
continue;
}
ReservedItemSlotData reservedItemSlotData = SessionManager.unlockedReservedItemSlots[num];
ReservedItemData reservedItemData = reservedItemSlotData.GetReservedItemData(val);
if (reservedItemData.holsteredParentBone == PlayerBone.None)
{
continue;
}
Transform bone = value.boneMap.GetBone(reservedItemData.holsteredParentBone);
if ((Object)(object)bone == (Object)null)
{
Plugin.LogWarning("Failed to get bone from masked enemy: " + reservedItemData.holsteredParentBone);
continue;
}
GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, bone);
val2.transform.localEulerAngles = reservedItemData.holsteredRotationOffset;
val2.transform.localPosition = reservedItemData.holsteredPositionOffset;
val2.transform.localScale = ((Component)val).transform.localScale;
val2.layer = 6;
MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer val3 in componentsInChildren)
{
if (!((Object)val3).name.Contains("ScanNode") && !((Component)val3).gameObject.CompareTag("DoNotSet") && !((Component)val3).gameObject.CompareTag("InteractTrigger"))
{
((Component)val3).gameObject.layer = 6;
}
}
if (val is FlashlightItem)
{
Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>();
foreach (Light val4 in componentsInChildren2)
{
((Behaviour)val4).enabled = false;
}
}
else
{
Light[] componentsInChildren3 = val2.GetComponentsInChildren<Light>();
foreach (Light val5 in componentsInChildren3)
{
((Behaviour)val5).enabled = true;
}
}
GrabbableObject componentInChildren = val2.GetComponentInChildren<GrabbableObject>();
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.playerHeldBy = null;
FlashlightItem val6 = (FlashlightItem)(object)((componentInChildren is FlashlightItem) ? componentInChildren : null);
if ((Object)(object)val6 != (Object)null)
{
((Behaviour)val6.flashlightBulb).enabled = true;
((Behaviour)val6.flashlightBulbGlow).enabled = true;
if (((Renderer)val6.flashlightMesh).sharedMaterials.Length > 1 && (Object)(object)val6.bulbLight != (Object)null)
{
((Renderer)val6.flashlightMesh).sharedMaterials[1] = val6.bulbLight;
}
}
ReservedItemsPatcher.ForceEnableItemMesh(componentInChildren, enabled: true);
componentInChildren.EnablePhysics(false);
}
Object.DestroyImmediate((Object)(object)val2.GetComponentInChildren<NetworkObject>());
Collider[] componentsInChildren4 = val2.GetComponentsInChildren<Collider>();
foreach (Collider val7 in componentsInChildren4)
{
Object.DestroyImmediate((Object)(object)val7);
}
MonoBehaviour[] componentsInChildren5 = val2.GetComponentsInChildren<MonoBehaviour>();
foreach (MonoBehaviour val8 in componentsInChildren5)
{
Object.DestroyImmediate((Object)(object)val8);
}
}
}
}
[HarmonyPatch]
internal static class MouseScrollPatcher
{
private static float timeLoggedPreventedScroll;
public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
[HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")]
[HarmonyPrefix]
public static void CorrectReservedScrollDirectionNextItemSlot(ref bool forward)
{
if (Keybinds.scrollingReservedHotbar)
{
forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "SwitchItemSlotsServerRpc")]
[HarmonyPrefix]
public static void CorrectReservedScrollDirectionServerRpc(ref bool forward)
{
if (Keybinds.scrollingReservedHotbar)
{
forward = Keybinds.RawScrollAction.ReadValue<float>() > 0f;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")]
[HarmonyPrefix]
public static bool PreventInvertedScrollingReservedHotbar(CallbackContext context)
{
if (LCVR_Compat.LoadedAndEnabled)
{
return true;
}
if (StartOfRound.Instance.localPlayerUsingController || SessionManager.numReservedItemSlotsUnlocked <= 0 || HUDPatcher.reservedItemSlots == null || localPlayerController.inTerminalMenu)
{
return true;
}
if (ReservedPlayerData.localPlayerData.currentItemSlotIsReserved)
{
if (!HUDPatcher.hasReservedItemSlotsAndEnabled)
{
return true;
}
float time = Time.time;
if (!Keybinds.scrollingReservedHotbar)
{
return false;
}
if (ReservedPlayerData.localPlayerData.GetNumHeldReservedItems() == 1 && (Object)(object)ReservedPlayerData.localPlayerData.currentlySelectedItem != (Object)null && !ReservedHotbarManager.isToggledInReservedSlots)
{
if (ConfigSettings.verboseLogs.Value && time - timeLoggedPreventedScroll > 1f)
{
timeLoggedPreventedScroll = time;
}
return false;
}
}
return true;
}
}
[HarmonyPatch]
public static class PlayerPatcher
{
[CompilerGenerated]
private sealed class <>c__DisplayClass20_0
{
public GrabbableObject __instance;
}
private static int INTERACTABLE_OBJECT_MASK = 0;
public static int vanillaHotbarSize = 4;
private static bool initialized = false;
private static bool GrabObjectClientRpcFlag = false;
public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
public static Dictionary<PlayerControllerB, ReservedPlayerData> allPlayerData => ReservedPlayerData.allPlayerData;
public static ReservedPlayerData localPlayerData => ReservedPlayerData.localPlayerData;
public static int reservedHotbarSize => SessionManager.numReservedItemSlotsUnlocked;
[HarmonyPatch(typeof(StartOfRound), "Awake")]
[HarmonyPrefix]
private static void InitSession(StartOfRound __instance)
{
initialized = false;
vanillaHotbarSize = 4;
ReservedPlayerData.allPlayerData?.Clear();
}
[HarmonyPatch(typeof(PlayerControllerB), "Awake")]
[HarmonyPostfix]
private static void InitializePlayerController(PlayerControllerB __instance)
{
if (!initialized)
{
vanillaHotbarSize = __instance.ItemSlots.Length;
INTERACTABLE_OBJECT_MASK = (int)Traverse.Create((object)__instance).Field("interactableObjectsMask").GetValue();
initialized = true;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Start")]
[HarmonyPrefix]
private static void InitializePlayerControllerLate(PlayerControllerB __instance)
{
ReservedPlayerData value = new ReservedPlayerData(__instance);
if (!allPlayerData.ContainsKey(__instance))
{
Plugin.Log("Initializing ReservedPlayerData for player: " + ((Object)__instance).name);
allPlayerData.Add(__instance, value);
}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
[HarmonyPostfix]
private static void CheckForChangedInventorySize(PlayerControllerB __instance)
{
if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || reservedHotbarSize <= 0 || value.hotbarSize == __instance.ItemSlots.Length)
{
return;
}
value.hotbarSize = __instance.ItemSlots.Length;
int num = -1;
if ((Object)(object)__instance == (Object)(object)localPlayerController)
{
if (HUDPatcher.reservedItemSlots != null && HUDPatcher.reservedItemSlots.Count > 0)
{
num = Array.IndexOf(HUDManager.Instance.itemSlotIconFrames, HUDPatcher.reservedItemSlots[0]);
Plugin.Log("OnUpdateInventorySize A for local player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
}
if (num == -1)
{
for (int i = 0; i < HUDManager.Instance.itemSlotIconFrames.Length; i++)
{
if (((Object)HUDManager.Instance.itemSlotIconFrames[i]).name.ToLower().Contains("reserved"))
{
num = i;
Plugin.Log("OnUpdateInventorySize B for local player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
break;
}
}
}
PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
foreach (PlayerControllerB val in allPlayerScripts)
{
if (ReservedPlayerData.allPlayerData.TryGetValue(val, out var value2) && value2 != value && reservedHotbarSize > 0 && value2.hotbarSize != val.ItemSlots.Length)
{
value2.reservedHotbarStartIndex = num;
}
}
}
if (num == -1)
{
num = value.reservedHotbarStartIndex;
Plugin.Log("OnUpdateInventorySize C for player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
}
if (num == -1)
{
num = vanillaHotbarSize;
Plugin.Log("OnUpdateInventorySize D for player: " + ((Object)__instance).name + " NewReservedItemsStartIndex: " + num);
}
value.reservedHotbarStartIndex = num;
if (value.reservedHotbarStartIndex < 0)
{
Plugin.LogError("Set new reserved start index to slot: " + value.reservedHotbarStartIndex + ". Maybe share these logs with Flip? :)");
}
if (value.reservedHotbarEndIndexExcluded - 1 >= value.playerController.ItemSlots.Length)
{
Plugin.LogError("Set new reserved start index to slot: " + value.reservedHotbarStartIndex + " Last reserved slot index: " + (value.reservedHotbarEndIndexExcluded - 1) + " Inventory size: " + value.playerController.ItemSlots.Length + ". Maybe share these logs with Flip? :)");
}
if (value.isLocalPlayer)
{
HUDPatcher.UpdateUI();
}
}
[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
[HarmonyPrefix]
private static bool BeginGrabReservedItemPrefix(PlayerControllerB __instance)
{
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !HUDPatcher.hasReservedItemSlotsAndEnabled)
{
return true;
}
localPlayerData.grabbingReservedItemSlotData = null;
localPlayerData.grabbingReservedItemData = null;
localPlayerData.grabbingReservedItem = null;
localPlayerData.previousHotbarIndex = -1;
if (__instance.twoHanded || __instance.sinkingValue > 0.73f)
{
return true;
}
Ray val = default(Ray);
((Ray)(ref val))..ctor(((Component)__instance.gameplayCamera).transform.position, ((Component)__instance.gameplayCamera).transform.forward);
RaycastHit val2 = default(RaycastHit);
if (Physics.Raycast(val, ref val2, __instance.grabDistance, INTERACTABLE_OBJECT_MASK) && ((Component)((RaycastHit)(ref val2)).collider).gameObject.layer != 8 && ((Component)((RaycastHit)(ref val2)).collider).tag == "PhysicsProp")
{
GrabbableObject component = ((Component)((Component)((RaycastHit)(ref val2)).collider).transform).gameObject.GetComponent<GrabbableObject>();
if ((Object)(object)component != (Object)null && !__instance.inSpecialInteractAnimation && !component.isHeld && !component.isPocketed)
{
NetworkObject networkObject = ((NetworkBehaviour)component).NetworkObject;
if (Object.op_Implicit((Object)(object)component) && component.itemProperties.twoHanded)
{
return true;
}
if ((Object)(object)networkObject != (Object)null && networkObject.IsSpawned && SessionManager.TryGetUnlockedItemData(component, out var itemData))
{
localPlayerData.grabbingReservedItemData = itemData;
localPlayerData.grabbingReservedItem = component;
localPlayerData.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
Plugin.Log("Beginning grab on reserved item: " + itemData.itemName + " Previous item slot: " + localPlayerData.previousHotbarIndex);
}
}
}
return true;
}
[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
[HarmonyPostfix]
private static void BeginGrabReservedItemPostfix(PlayerControllerB __instance)
{
if (localPlayerData != null && localPlayerData.isGrabbingReservedItem && !localPlayerData.IsReservedItemSlot(localPlayerData.previousHotbarIndex))
{
SetSpecialGrabAnimationBool(__instance, setTrue: false);
SetSpecialGrabAnimationBool(__instance, (Object)(object)localPlayerData.previouslyHeldItem != (Object)null, localPlayerData.previouslyHeldItem);
__instance.playerBodyAnimator.SetBool("GrabValidated", true);
__instance.playerBodyAnimator.SetBool("GrabInvalidated", false);
__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation");
__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded");
if ((Object)(object)localPlayerData.previouslyHeldItem != (Object)null)
{
__instance.playerBodyAnimator.ResetTrigger(localPlayerData.previouslyHeldItem.itemProperties.pocketAnim);
}
__instance.twoHanded = (Object)(object)localPlayerData.previouslyHeldItem != (Object)null && localPlayerData.previouslyHeldItem.itemProperties.twoHanded;
__instance.twoHandedAnimation = (Object)(object)localPlayerData.previouslyHeldItem != (Object)null && localPlayerData.previouslyHeldItem.itemProperties.twoHandedAnimation;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
[HarmonyPrefix]
private static void GrabReservedItemClientRpcPrefix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance)
{
if (!NetworkHelper.IsServerExecStage((NetworkBehaviour)(object)__instance) || (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsHost))
{
return;
}
GrabObjectClientRpcFlag = true;
if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value))
{
return;
}
NetworkObject val = default(NetworkObject);
GrabbableObject val2 = default(GrabbableObject);
if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening && grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2) && SessionManager.TryGetUnlockedItemData(val2, out var itemData))
{
ReservedItemSlotData firstEmptySlotForReservedItem = value.GetFirstEmptySlotForReservedItem(itemData.itemName);
if (firstEmptySlotForReservedItem != null)
{
value.grabbingReservedItemSlotData = firstEmptySlotForReservedItem;
value.grabbingReservedItemData = itemData;
value.grabbingReservedItem = val2;
value.previousHotbarIndex = Mathf.Clamp(__instance.currentItemSlot, 0, __instance.ItemSlots.Length - 1);
return;
}
}
value.grabbingReservedItemSlotData = null;
value.grabbingReservedItemData = null;
value.grabbingReservedItem = null;
value.previousHotbarIndex = -1;
}
[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
[HarmonyPostfix]
private static void GrabReservedItemClientRpcPostfix(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance)
{
if (!GrabObjectClientRpcFlag)
{
return;
}
GrabObjectClientRpcFlag = false;
if ((!SyncManager.isSynced && !SyncManager.canUseModDisabledOnHost) || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || !value.isGrabbingReservedItem)
{
return;
}
if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening)
{
NetworkObject val = default(NetworkObject);
GrabbableObject val2 = default(GrabbableObject);
if (grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2))
{
if (SessionManager.TryGetUnlockedItemData(val2, out var itemData))
{
if (!value.IsReservedItemSlot(value.previousHotbarIndex))
{
if ((Object)(object)value.previouslyHeldItem != (Object)null)
{
value.previouslyHeldItem.EnableItemMeshes(true);
}
ReservedItemsPatcher.ForceEnableItemMesh(value.grabbingReservedItem, enabled: false);
Traverse.Create((object)val2).Field("previousPlayerHeldBy").SetValue((object)__instance);
if (value.isLocalPlayer)
{
int num = value.reservedHotbarStartIndex + value.grabbingReservedItemSlotData.GetReservedItemSlotIndex();
((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().SetBool("selectedSlot", false);
((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().SetBool("selectedSlot", true);
((Component)HUDManager.Instance.itemSlotIconFrames[num]).GetComponent<Animator>().Play("PanelLines", 0, 1f);
((Component)HUDManager.Instance.itemSlotIconFrames[value.previousHotbarIndex]).GetComponent<Animator>().Play("PanelEnlarge", 0, 1f);
}
else
{
SwitchToItemSlot(__instance, value.previousHotbarIndex);
if (itemData.showOnPlayerWhileHolstered)
{
val2.EnableItemMeshes(true);
}
}
SetSpecialGrabAnimationBool(__instance, setTrue: false);
SetSpecialGrabAnimationBool(__instance, (Object)(object)value.previouslyHeldItem != (Object)null, value.previouslyHeldItem);
__instance.playerBodyAnimator.SetBool("GrabValidated", true);
__instance.playerBodyAnimator.SetBool("GrabInvalidated", false);
__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimation");
__instance.playerBodyAnimator.ResetTrigger("SwitchHoldAnimationTwoHanded");
if ((Object)(object)value.previouslyHeldItem != (Object)null)
{
__instance.playerBodyAnimator.ResetTrigger(value.previouslyHeldItem.itemProperties.pocketAnim);
}
__instance.twoHanded = (Object)(object)value.previouslyHeldItem != (Object)null && value.previouslyHeldItem.itemProperties.twoHanded;
__instance.twoHandedAnimation = (Object)(object)value.previouslyHeldItem != (Object)null && value.previouslyHeldItem.itemProperties.twoHandedAnimation;
}
if (value.isLocalPlayer)
{
HUDPatcher.UpdateUI();
return;
}
value.grabbingReservedItemSlotData = null;
value.grabbingReservedItemData = null;
value.grabbingReservedItem = null;
value.previousHotbarIndex = -1;
return;
}
}
else if (value.isLocalPlayer)
{
Plugin.LogWarning("Failed to validate ReservedItemGrab by the local player. Object id: " + ((NetworkObjectReference)(ref grabbedObject)).NetworkObjectId + ". Internal error?");
Traverse.Create((object)localPlayerController).Field("grabInvalidated").SetValue((object)true);
}
else
{
Plugin.LogWarning("Failed to validate ReservedItemGrab by player with id: " + ((Object)__instance).name + ". Object id: " + ((NetworkObjectReference)(ref grabbedObject)).NetworkObjectId + ". Internal error?");
}
}
value.grabbingReservedItemSlotData = null;
value.grabbingReservedItemData = null;
value.grabbingReservedItem = null;
value.previousHotbarIndex = -1;
}
[HarmonyPatch(typeof(GrabbableObject), "GrabItemOnClient")]
[HarmonyPrefix]
private static void OnReservedItemGrabbed(GrabbableObject __instance)
{
<>c__DisplayClass20_0 CS$<>8__locals0 = new <>c__DisplayClass20_0();
CS$<>8__locals0.__instance = __instance;
if (localPlayerData.grabbingReservedItemData != null && (Object)(object)CS$<>8__locals0.__instance == (Object)(object)GetCurrentlyGrabbingObject(localPlayerController))
{
((MonoBehaviour)localPlayerController).StartCoroutine(OnReservedItemGrabbedEndOfFrame());
}
[IteratorStateMachine(typeof(<>c__DisplayClass20_0.<<OnReservedItemGrabbed>g__OnReservedItemGrabbedEndOfFrame|0>d))]
IEnumerator OnReservedItemGrabbedEndOfFrame()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <>c__DisplayClass20_0.<<OnReservedItemGrabbed>g__OnReservedItemGrabbedEndOfFrame|0>d(0)
{
<>4__this = CS$<>8__locals0
};
}
}
[HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")]
[HarmonyPrefix]
private static void UpdateLastSelectedHotbarIndex(int slot, PlayerControllerB __instance)
{
if (LCVR_Compat.LoadedAndEnabled && (Object)(object)__instance == (Object)(object)localPlayerController && LCVR_Compat.vrPlayerScrollingBetweenHotbars)
{
return;
}
int currentItemSlot = __instance.currentItemSlot;
if (ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value))
{
if (value.IsReservedItemSlot(currentItemSlot))
{
ReservedHotbarManager.indexInReservedHotbar = currentItemSlot;
}
else
{
ReservedHotbarManager.indexInHotbar = currentItemSlot;
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")]
[HarmonyPostfix]
private static void UpdateFocusReservedHotbar(int slot, PlayerControllerB __instance)
{
if ((!LCVR_Compat.LoadedAndEnabled || !((Object)(object)__instance == (Object)(object)localPlayerController) || !LCVR_Compat.vrPlayerScrollingBetweenHotbars) && HUDPatcher.hasReservedItemSlotsAndEnabled && ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value))
{
bool inReservedHotbarSlots = value.inReservedHotbarSlots;
value.inReservedHotbarSlots = value.IsReservedItemSlot(__instance.currentItemSlot);
bool flag = false;
if (inReservedHotbarSlots != value.inReservedHotbarSlots || (value.inReservedHotbarSlots && ReservedHotbarManager.isToggledInReservedSlots && ReservedHotbarManager.currentlyToggledItemSlots != null && !ReservedHotbarManager.currentlyToggledItemSlots.Contains(value.GetCurrentlySelectedReservedItemSlot())))
{
flag = true;
}
if (value.inReservedHotbarSlots)
{
ReservedHotbarManager.OnSwapToReservedHotbar();
}
else
{
ReservedHotbarManager.OnSwapToVanillaHotbar();
}
if (flag)
{
HUDPatcher.UpdateToggledReservedItemSlotsUI();
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "FirstEmptyItemSlot")]
[HarmonyPostfix]
private static void GetReservedItemSlotPlacementIndex(ref int __result, PlayerControllerB __instance)
{
if (reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value))
{
return;
}
ReservedItemData grabbingReservedItemData = value.grabbingReservedItemData;
if (grabbingReservedItemData != null)
{
ReservedItemSlotData firstEmptySlotForReservedItem = value.GetFirstEmptySlotForReservedItem(grabbingReservedItemData.itemName);
if (firstEmptySlotForReservedItem != null)
{
__result = firstEmptySlotForReservedItem.GetIndexInInventory(__instance);
return;
}
value.grabbingReservedItemSlotData = null;
value.grabbingReservedItemData = null;
value.grabbingReservedItem = null;
value.previousHotbarIndex = -1;
}
if (!value.IsReservedItemSlot(__result))
{
return;
}
__result = -1;
for (int i = 0; i < __instance.ItemSlots.Length; i++)
{
if (!value.IsReservedItemSlot(i) && (Object)(object)__instance.ItemSlots[i] == (Object)null)
{
__result = i;
break;
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "NextItemSlot")]
[HarmonyPostfix]
private static void OnNextItemSlot(ref int __result, bool forward, PlayerControllerB __instance)
{
if (reservedHotbarSize <= 0 || !HUDPatcher.hasReservedItemSlotsAndEnabled || !ReservedPlayerData.allPlayerData.TryGetValue(__instance, out var value) || (LCVR_Compat.LoadedAndEnabled && (Object)(object)__instance == (Object)(object)localPlayerController && LCVR_Compat.vrPlayerScrollingBetweenHotbars))
{
return;
}
bool inReservedHotbarSlots = value.inReservedHotbarSlots;
bool flag = value.IsReservedItemSlot(__result);
bool flag2 = inReservedHotbarSlots;
if (inReservedHotbarSlots)
{
ReservedItemSlotData unlockedReservedItemSlot = SessionManager.GetUnlockedReservedItemSlot(__result - value.reservedHotbarStartIndex);
if (ReservedHotbarManager.isToggledInReservedSlots && !Keybinds.pressedToggleKey && !Keybinds.holdingModifierKey && ReservedHotbarManager.currentlyToggledItemSlots != null && (!flag || (Object)(object)value.itemSlots[__result] == (Object)null || !ReservedHotbarManager.currentlyToggledItemSlots.Contains(unlockedReservedItemSlot)))
{
__result = ReservedHotbarManager.indexInHotbar;
return;
}
}
if (flag == flag2 && (!flag || (Object)(object)__instance.ItemSlots[__result] != (Object)null))
{
return;
}
int num = (forward ? 1 : (-1));
__result = __instance.currentItemSlot + num;
__result = ((__result < 0) ? (__instance.ItemSlots.Length - 1) : ((__result < __instance.ItemSlots.Length) ? __result : 0));
flag = value.IsReservedItemSlot(__result);
if (!flag2)
{
if (flag)
{
__result = (forward ? ((value.reservedHotbarStartIndex + reservedHotbarSize) % __instance.ItemSlots.Length) : (value.reservedHotbarStartIndex - 1));
}
return;
}
__result = (flag ? __result : (forward ? value.reservedHotbarStartIndex : (value.reservedHotbarStartIndex + reservedHotbarSize - 1)));
if (!LCVR_Compat.Loaded)
{
int numHeldReservedItems = value.GetNumHeldReservedItems();
while (numHeldReservedItems > 0 && __result != value.currentItemSlot && (Object)(object)__instance.ItemSlots[__result] == (Object)null)
{
__result += num;
__result = ((!value.IsReservedItemSlot(__result)) ? (forward ? value.reservedHotbarStartIndex : (value.reservedHotbarStartIndex + reservedHotbarSize - 1)) : __result);
}
}
}
[HarmonyPatch(typeof(HUDManager), "ClearControlTips")]
[HarmonyPrefix]
private static bool PreventClearControlTipsGrabbingReservedItem(HUDManager __instance)
{
return ReservedPlayerData.localPlayerData == null || (Object)(object)ReservedPlayerData.localPlayerData.grabbingReservedItem == (Object)null;
}
[HarmonyPatch(typeof(GrabbableObject), "SetControlTipsForItem")]
[HarmonyPrefix]
private static bool PreventUpdateControlTipsGrabbingReservedItem(GrabbableObject __instance)
{
return ReservedPlayerData.localPlayerData == null || (Object)(object)ReservedPlayerData.localPlayerData.grabbingReservedItem != (Object)(object)__instance;
}
private static GrabbableObject GetCurrentlyGrabbingObject(PlayerControllerB playerController)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
return (GrabbableObject)Traverse.Create((object)playerController).Field("currentlyGrabbingObject").GetValue();
}
private static void SetCurrentlyGrabbingObject(PlayerControllerB playerController, GrabbableObject grabbable)
{
Traverse.Create((object)playerController).Field("currentlyGrabbingObject").SetValue((object)grabbable);
}
public static bool ReservedItemIsBeingGrabbed(GrabbableObject grabbableObject)
{
if ((Object)(object)grabbableObject == (Object)null)
{
return false;
}
foreach (ReservedPlayerData value in ReservedPlayerData.allPlayerData.Values)
{
if ((Object)(object)grabbableObject == (Object)(object)value.grabbingReservedItem)
{
return true;
}
}
return false;
}
public static void SetSpecialGrabAnimationBool(PlayerControllerB playerController, bool setTrue, GrabbableObject currentItem = null)
{
MethodInfo method = ((object)playerController).GetType().GetMethod("SetSpecialGrabAnimationBool", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(playerController, new object[2] { setTrue, currentItem });
}
public static void SwitchToItemSlot(PlayerControllerB playerController, int slot, GrabbableObject fillSlotWithItem = null)
{
MethodInfo method = ((object)playerController).GetType().GetMethod("SwitchToItemSlot", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(playerController, new object[2] { slot, fillSlotWithItem });
if (ReservedPlayerData.allPlayerData.TryGetValue(playerController, out var value))
{
value.timeSinceSwitchingSlots = 0f;
}
}
}
[HarmonyPatch]
internal static class ReservedItemsPatcher
{
public static bool ignoreMeshOverride = false;
internal static Dictionary<GameObject, int> previousObjectLayers = new Dictionary<GameObject, int>();
public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
[HarmonyPatch(typeof(GrabbableObject), "PocketItem")]
[HarmonyPostfix]
public static void OnPocketReservedItem(GrabbableObject __instance)
{
if (!ConfigSettings.showReservedItemsHolstered.Value || (Object)(object)__instance.playerHeldBy == (Object)null || !ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) || !SessionManager.TryGetUnlockedItemData(__instance, out var itemData) || !value.IsItemInReservedItemSlot(__instance) || !itemData.showOnPlayerWhileHolstered)
{
return;
}
MeshRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer val in componentsInChildren)
{
if (!previousObjectLayers.TryGetValue(((Component)val).gameObject, out var value2))
{
value2 = ((Component)val).gameObject.layer;
}
if (((Component)val).gameObject.CompareTag("DoNotSet") || ((Component)val).gameObject.CompareTag("InteractTrigger") || !IsLayerInLocalCameraMask(value2))
{
continue;
}
if (!previousObjectLayers.ContainsKey(((Component)val).gameObject))
{
previousObjectLayers.Add(((Component)val).gameObject, value2);
}
if (value.isLocalPlayer && (!TooManyEmotes_Compat.Enabled || !TooManyEmotes_Compat.IsLocalPlayerPerformingCustomEmote()))
{
if (IsLayerInLocalCameraMask(((Component)val).gameObject.layer))
{
((Component)val).gameObject.layer = 23;
}
}
else if (!IsLayerInLocalCameraMask(((Component)val).gameObject.layer))
{
((Component)val).gameObject.layer = 6;
}
}
__instance.parentObject = value.boneMap.GetBone(itemData.holsteredParentBone);
ForceEnableItemMesh(__instance, enabled: true);
}
[HarmonyPatch(typeof(GrabbableObject), "EquipItem")]
[HarmonyPatch(typeof(StunGrenadeItem), "EquipItem")]
[HarmonyPostfix]
public static void OnEquipReservedItem(GrabbableObject __instance)
{
if (!ConfigSettings.showReservedItemsHolstered.Value || (Object)(object)__instance.playerHeldBy == (Object)null || !ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) || !SessionManager.TryGetUnlockedItemData(__instance, out var itemData) || !value.IsItemInReservedItemSlot(__instance) || !itemData.showOnPlayerWhileHolstered)
{
return;
}
MeshRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer val in componentsInChildren)
{
if (!((Component)val).gameObject.CompareTag("DoNotSet") && !((Component)val).gameObject.CompareTag("InteractTrigger") && previousObjectLayers.TryGetValue(((Component)val).gameObject, out var value2))
{
((Component)val).gameObject.layer = value2;
previousObjectLayers.Remove(((Component)val).gameObject);
}
}
__instance.parentObject = (value.isLocalPlayer ? __instance.playerHeldBy.localItemHolder : __instance.playerHeldBy.serverItemHolder);
}
[HarmonyPatch(typeof(GrabbableObject), "DiscardItem")]
[HarmonyPostfix]
public static void ResetReservedItemLayer(GrabbableObject __instance)
{
if (!SessionManager.TryGetUnlockedItemData(__instance, out var itemData) || !itemData.showOnPlayerWhileHolstered)
{
return;
}
MeshRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer val in componentsInChildren)
{
if (!((Component)val).gameObject.CompareTag("DoNotSet") && !((Component)val).gameObject.CompareTag("InteractTrigger") && previousObjectLayers.TryGetValue(((Component)val).gameObject, out var value))
{
((Component)val).gameObject.layer = value;
previousObjectLayers.Remove(((Component)val).gameObject);
}
}
}
[HarmonyPatch(typeof(GrabbableObject), "LateUpdate")]
[HarmonyPostfix]
public static void SetHolsteredPositionRotation(GrabbableObject __instance)
{
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
if (ConfigSettings.showReservedItemsHolstered.Value && !((Object)(object)__instance.playerHeldBy == (Object)null) && !((Object)(object)__instance.parentObject == (Object)null) && ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) && SessionManager.TryGetUnlockedItemData(__instance, out var itemData) && value.IsItemInReservedItemSlot(__instance) && itemData.showOnPlayerWhileHolstered && (Object)(object)__instance != (Object)(object)value.currentlySelectedItem)
{
Transform transform = ((Component)__instance.parentObject).transform;
((Component)__instance).transform.rotation = ((Component)__instance.parentObject).transform.rotation * Quaternion.Euler(itemData.holsteredRotationOffset);
((Component)__instance).transform.position = transform.position + transform.rotation * itemData.holsteredPositionOffset;
}
}
[HarmonyPatch(typeof(GrabbableObject), "EnableItemMeshes")]
[HarmonyPrefix]
public static void OnEnableItemMeshes(ref bool enable, GrabbableObject __instance)
{
if (ConfigSettings.showReservedItemsHolstered.Value)
{
if ((Object)(object)__instance.playerHeldBy != (Object)null && !ignoreMeshOverride && ReservedPlayerData.allPlayerData.TryGetValue(__instance.playerHeldBy, out var value) && SessionManager.TryGetUnlockedItemData(__instance, out var itemData) && value.IsItemInReservedItemSlot(__instance) && itemData.showOnPlayerWhileHolstered && (Object)(object)value.currentlySelectedItem != (Object)(object)__instance && !PlayerPatcher.ReservedItemIsBeingGrabbed(__instance))
{
enable = true;
}
ignoreMeshOverride = false;
}
}
public static void ForceEnableItemMesh(GrabbableObject grabbableObject, bool enabled)
{
ignoreMeshOverride = true;
grabbableObject.EnableItemMeshes(enabled);
}
public static bool IsLayerInLocalCameraMask(int layer)
{
if (!Object.op_Implicit((Object)(object)localPlayerController) || !Object.op_Implicit((Object)(object)localPlayerController.gameplayCamera))
{
return false;
}
int cullingMask = localPlayerController.gameplayCamera.cullingMask;
return (cullingMask & (1 << layer)) != 0;
}
}
[HarmonyPatch]
internal static class SyncAlreadyHeldObjectsPatcher
{
[HarmonyPatch(typeof(StartOfRound), "SyncAlreadyHeldObjectsClientRpc")]
[HarmonyPrefix]
private static void SyncAlreadyHeldReservedObjectsClientRpc(ref NetworkObjectReference[] gObjects, ref int[] playersHeldBy, ref int[] itemSlotNumbers, ref int[] isObjectPocketed, int syncWithClient, StartOfRound __instance)
{
if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsListening || !NetworkHelper.IsServerExecStage((NetworkBehaviour)(object)__instance) || (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsHost) || syncWithClient != (int)NetworkManager.Singleton.LocalClientId)
{
return;
}
bool flag = false;
List<NetworkObjectReference> list = new List<NetworkObjectReference>(gObjects);
List<int> list2 = new List<int>(playersHeldBy);
List<int> list3 = new List<int>(itemSlotNumbers);
List<int> list4 = new List<int>(isObjectPocketed);
for (int num = itemSlotNumbers.Length - 1; num >= 0; num--)
{
if (itemSlotNumbers[num] >= __instance.localPlayerController.ItemSlots.Length && itemSlotNumbers[num] != 50)
{
list.RemoveAt(num);
list2.RemoveAt(num);
list3.RemoveAt(num);
list4.Remove(num);
flag = true;
}
}
if (flag)
{
gObjects = list.ToArray();
playersHeldBy = list2.ToArray();
itemSlotNumbers = list3.ToArray();
isObjectPocketed = list4.ToArray();
}
}
}
[HarmonyPatch]
internal static class TerminalPatcher
{
public static Terminal terminalInstance;
public static bool initializedTerminalNodes;
public static ReservedItemSlotData purchasingItemSlot;
[HarmonyPatch(typeof(Terminal), "Awake")]
[HarmonyPrefix]
public static void InitializeTerminal(Terminal __instance)
{
terminalInstance = __instance;
initializedTerminalNodes = false;
EditExistingTerminalNodes();
}
[HarmonyPatch(typeof(Terminal), "BeginUsingTerminal")]
[HarmonyPrefix]
public static void OnBeginUsingTerminal(Terminal __instance)
{
if (!initializedTerminalNodes && SyncManager.isSynced)
{
EditExistingTerminalNodes();
}
}
public static void EditExistingTerminalNodes()
{
if (!SyncManager.isSynced)
{
return;
}
initializedTerminalNodes = true;
if (!SyncManager.enablePurchasingItemSlots)
{
return;
}
foreach (TerminalNode specialNode in terminalInstance.terminalNodes.specialNodes)
{
if (((Object)specialNode).name == "Start" && !specialNode.displayText.Contains("[ReservedItemSlots]"))
{
string text = "Type \"Help\" for a list of commands.";
int num = specialNode.displayText.IndexOf(text);
if (num != -1)
{
num += text.Length;
string value = "\n\n[ReservedItemSlots]\nType \"Reserved\" to purchase reserved item slots.";
specialNode.displayText = specialNode.displayText.Insert(num, value);
}
else
{
Plugin.LogError("Failed to add reserved item slots tip to terminal. Maybe an update broke it?");
}
}
else if (((Object)specialNode).name == "HelpCommands" && !specialNode.displayText.Contains(">RESERVED"))
{
string value2 = "[numberOfItemsOnRoute]";
int num2 = specialNode.displayText.IndexOf(value2);
if (num2 != -1)
{
string text2 = ">RESERVED\n";
text2 += "Purchase reserved item slots.\n\n";
specialNode.displayText = specialNode.displayText.Insert(num2, text2);
}
}
}
}
[HarmonyPatch(typeof(Terminal), "TextPostProcess")]
[HarmonyPrefix]
public static void TextPostProcess(ref string modifiedDisplayText, TerminalNode node)
{
if (modifiedDisplayText.Length <= 0)
{
return;
}
string text = "[[[reservedItemSlotsSelectionList]]]";
if (!modifiedDisplayText.Contains(text))
{
return;
}
int num = modifiedDisplayText.IndexOf(text);
int num2 = num + text.Length;
string oldValue = modifiedDisplayText.Substring(num, num2 - num);
string text2 = "";
if (!SyncManager.enablePurchasingItemSlots)
{
text2 += "Every reserved item slot is unlocked!\n\n";
}
else
{
text2 += "Reserved Item Slots\n------------------------------\n\n";
text2 += "To purchase a reserved item slot, type the following command.\n> RESERVED [item_slot]\n\n";
int num3 = 0;
foreach (ReservedItemSlotData value in SyncManager.unlockableReservedItemSlotsDict.Values)
{
num3 = Mathf.Max(num3, value.slotName.Length);
}
foreach (ReservedItemSlotData value2 in SyncManager.unlockableReservedItemSlotsDict.Values)
{
string arg = (SessionManager.IsItemSlotUnlocked(value2) ? "[Purchased]" : ("$" + value2.purchasePrice));
text2 += $"* {value2.slotDisplayName}{new string(' ', num3 - value2.slotDisplayName.Length)} // {arg}\n";
}
}
modifiedDisplayText = modifiedDisplayText.Replace(oldValue, text2);
}
[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
[HarmonyPrefix]
public static bool ParsePlayerSentence(ref TerminalNode __result, Terminal __instance)
{
if (__instance.screenText.text.Length <= 0)
{
return true;
}
string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).ToLower();
string[] array = text.Split(new char[1] { ' ' });
ReservedItemSlotData reservedItemSlotData = null;
if (!SyncManager.isSynced)
{
if (text.StartsWith("reserved"))
{
__result = BuildTerminalNodeHostDoesNotHaveMod();
return false;
}
return true;
}
if (purchasingItemSlot != null)
{
if ("confirm".StartsWith(text))
{
if (purchasingItemSlot.isUnlocked)
{
Plugin.LogWarning("Attempted to confirm purchase on reserved item slot that was already unlocked. Item slot: " + purchasingItemSlot.slotDisplayName);
__result = BuildTerminalNodeAlreadyUnlocked(purchasingItemSlot);
}
else if (terminalInstance.groupCredits < purchasingItemSlot.purchasePrice)
{
Plugin.LogWarning("Attempted to confirm purchase with insufficient credits. Current credits: " + terminalInstance.groupCredits + " Required credits: " + purchasingItemSlot.purchasePrice);
__result = BuildTerminalNodeInsufficientFunds(purchasingItemSlot);
}
else
{
Plugin.Log("Purchasing reserved item slot: " + purchasingItemSlot.slotDisplayName + ". Price: " + purchasingItemSlot.purchasePrice);
Terminal obj = terminalInstance;
obj.groupCredits -= purchasingItemSlot.purchasePrice;
terminalInstance.BuyItemsServerRpc(new int[0], terminalInstance.groupCredits, terminalInstance.numberOfItemsInDropship);
SyncManager.SendUnlockItemSlotUpdateToServer(purchasingItemSlot.slotId);
__result = BuildTerminalNodeOnPurchased(purchasingItemSlot, terminalInstance.groupCredits);
}
}
else
{
Plugin.Log("Canceling order.");
__result = BuildCustomTerminalNode("Canceled order.\n\n");
}
purchasingItemSlot = null;
return false;
}
purchasingItemSlot = null;
if (array.Length == 0 || array[0] != "reserved")
{
return true;
}
if (array.Length == 1)
{
__result = BuildTerminalNodeHome();
return false;
}
string text2 = text.Substring(9);
reservedItemSlotData = TryGetReservedItemSlot(text2);
if (reservedItemSlotData != null)
{
if (SessionManager.IsItemSlotUnlocked(reservedItemSlotData))
{
Plugin.LogWarning("Attempted to start purchase on reserved item slot that was already unlocked. Item slot: " + reservedItemSlotData.slotName);
__result = BuildTerminalNodeAlreadyUnlocked(reservedItemSlotData);
}
else if (terminalInstance.groupCredits < reservedItemSlotData.purchasePrice)
{
Plugin.LogWarning("Attempted to start purchase with insufficient credits. Current credits: " + terminalInstance.groupCredits + ". Item slot price: " + reservedItemSlotData.purchasePrice);
__result = BuildTerminalNodeInsufficientFunds(reservedItemSlotData);
}
else
{
Plugin.Log("Started purchasing reserved item slot: " + reservedItemSlotData.slotName);
purchasingItemSlot = reservedItemSlotData;
__result = BuildTerminalNodeConfirmDenyPurchase(reservedItemSlotData);
}
return false;
}
Plugin.LogWarning("Attempted to start purchase on invalid reserved item slot. Item slot: " + text2);
__result = BuildTerminalNodeInvalidReservedItemSlot(text2);
return false;
}
private static TerminalNode BuildTerminalNodeHome()
{
//IL_0001: Unknown result type (might be due to invalid IL or