Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ExtraInventorySlots v1.0.0
plugins\ExtraInventorySlots\ExtraInventorySlots.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ExtraInventorySlots")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+86a34959c3a3098544184b63ef4eb03edbe7dce4")] [assembly: AssemblyProduct("ExtraInventorySlots")] [assembly: AssemblyTitle("ExtraInventorySlots")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ExtraInventorySlots { [BepInPlugin("DarkSpider90.ExtraInventorySlots", "Extra Inventory Slots", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { internal const string PluginGuid = "DarkSpider90.ExtraInventorySlots"; internal const string PluginName = "Extra Inventory Slots"; internal const string PluginVersion = "1.0.0"; internal const int VanillaSlotCount = 3; private const int MaxSlotCount = 10; private Harmony _harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<int> SlotCount { get; private set; } internal static ConfigEntry<bool> HostProtection { get; private set; } internal static ConfigEntry<bool> KeepItemsInTruck { get; private set; } internal static ConfigEntry<bool> ExtraHotkeys { get; private set; } internal static ConfigEntry<bool> NumpadHotkeys { get; private set; } internal static ConfigEntry<bool> AutoSwapItems { get; private set; } internal static int EffectiveSlotCount => Mathf.Clamp(SlotCount?.Value ?? 3, 3, 10); private void Awake() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; SlotCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Number Of Slots", 5, new ConfigDescription("Total inventory slots to show and use. Vanilla is 3. Changes after a scene or round reload.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 10), Array.Empty<object>())); HostProtection = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Host Protection", true, "If true, a host with this mod blocks clients from equipping items into slots above the host's configured slot count."); KeepItemsInTruck = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Keep Items In Truck", false, "If true, extra-slot items are not restored back to players when the game rebuilds item ownership between rounds."); AutoSwapItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Auto Swap Items", true, "If true, storing a held item into an occupied inventory slot swaps it with the item already in that slot."); ExtraHotkeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "Extra Slot Hotkeys", true, "If true, number keys 4-9 and 0 control extra inventory slots."); NumpadHotkeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "Numpad Hotkeys", true, "If true, numpad keys also control matching extra inventory slots."); _harmony = new Harmony("DarkSpider90.ExtraInventorySlots"); _harmony.PatchAll(); Log.LogInfo((object)"Extra Inventory Slots v1.0.0 loaded for R.E.P.O. v0.4.0."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class AutoItemSwap { private const float EquipWaitTimeout = 0.75f; private static readonly FieldInfo GrabbedPhysGrabObjectField = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject"); private static readonly FieldInfo PlayerInputDisableTimerField = AccessTools.Field(typeof(PlayerController), "InputDisableTimer"); private static readonly FieldInfo LastEquipTimeField = AccessTools.Field(typeof(InventorySpot), "lastEquipTime"); private static readonly FieldInfo EquipCooldownField = AccessTools.Field(typeof(InventorySpot), "equipCooldown"); private static readonly FieldInfo HandleInputField = AccessTools.Field(typeof(InventorySpot), "handleInput"); internal static bool PrefixHandleInput(InventorySpot spot) { if (!Plugin.AutoSwapItems.Value || (Object)(object)spot == (Object)null) { return true; } if (ShouldLetVanillaHandle(spot)) { return true; } ItemEquippable heldItem = GetHeldItem(); if ((Object)(object)heldItem == (Object)null || !spot.IsOccupied()) { return true; } ItemEquippable currentItem = spot.CurrentItem; if ((Object)(object)currentItem == (Object)null || (Object)(object)currentItem == (Object)(object)heldItem) { return true; } int inventorySpotIndex = spot.inventorySpotIndex; int ownerViewId = (SemiFunc.IsMultiplayer() ? PhysGrabber.instance.photonView.ViewID : (-1)); SetInputCooldown(spot); currentItem.RequestUnequip(); ((MonoBehaviour)Plugin.Instance).StartCoroutine(EquipWhenSlotIsReady(heldItem, inventorySpotIndex, ownerViewId, currentItem)); return false; } private static bool ShouldLetVanillaHandle(InventorySpot spot) { if (SemiFunc.RunIsArena()) { return true; } if ((Object)(object)PlayerController.instance != (Object)null && PlayerInputDisableTimerField != null && (float)PlayerInputDisableTimerField.GetValue(PlayerController.instance) > 0f) { return true; } return IsInCooldown(spot); } private static bool IsInCooldown(InventorySpot spot) { if (LastEquipTimeField == null || EquipCooldownField == null || HandleInputField == null) { return false; } if ((bool)HandleInputField.GetValue(spot)) { return false; } float num = (float)LastEquipTimeField.GetValue(spot); float num2 = (float)EquipCooldownField.GetValue(spot); return Time.time - num < num2; } private static void SetInputCooldown(InventorySpot spot) { LastEquipTimeField?.SetValue(spot, Time.time); HandleInputField?.SetValue(spot, false); } private static ItemEquippable GetHeldItem() { PhysGrabber instance = PhysGrabber.instance; if ((Object)(object)instance == (Object)null || !instance.grabbed) { return null; } object? obj = GrabbedPhysGrabObjectField?.GetValue(instance); PhysGrabObject val = (PhysGrabObject)((obj is PhysGrabObject) ? obj : null); if (!((Object)(object)val == (Object)null)) { return ((Component)val).GetComponent<ItemEquippable>(); } return null; } private static IEnumerator EquipWhenSlotIsReady(ItemEquippable heldItem, int slotIndex, int ownerViewId, ItemEquippable previousSlotItem) { float timeoutAt = Time.time + 0.75f; while (Time.time < timeoutAt) { InventorySpot spot = GetSpot(slotIndex); if ((Object)(object)spot == (Object)null || !spot.IsOccupied() || (Object)(object)spot.CurrentItem != (Object)(object)previousSlotItem) { break; } yield return null; } if ((Object)(object)heldItem != (Object)null && !heldItem.IsEquipped()) { heldItem.RequestEquip(slotIndex, ownerViewId); } } private static InventorySpot GetSpot(int slotIndex) { if ((Object)(object)Inventory.instance == (Object)null) { return null; } InventorySlotList.EnsureSlots(Inventory.instance, slotIndex + 1); List<InventorySpot> allSpots = Inventory.instance.GetAllSpots(); if (slotIndex < 0 || slotIndex >= allSpots.Count) { return null; } return allSpots[slotIndex]; } } internal static class ExtraSlotState { private static readonly Dictionary<string, Dictionary<int, int>> ServerMonitoredInventoryItems = new Dictionary<string, Dictionary<int, int>>(); internal static void TrackInventoryUpdate(string steamId, string itemName, int spot) { if (!SemiFunc.IsMasterClientOrSingleplayer() || spot < 3 || string.IsNullOrEmpty(steamId)) { return; } if (string.IsNullOrEmpty(itemName)) { if (ServerMonitoredInventoryItems.TryGetValue(steamId, out var value)) { value.Remove(spot); if (value.Count == 0) { ServerMonitoredInventoryItems.Remove(steamId); } } } else { if (!ServerMonitoredInventoryItems.TryGetValue(steamId, out var value2)) { value2 = new Dictionary<int, int>(); ServerMonitoredInventoryItems[steamId] = value2; } value2[spot] = itemName.GetHashCode(); } } internal static bool TryFindItemOwnerAndSpot(int itemHash, out PlayerAvatar owner, out int spot) { owner = null; spot = -1; List<PlayerAvatar> list = SemiFunc.PlayerGetList(); if (list == null) { return false; } foreach (PlayerAvatar item in list) { string key = SemiFunc.PlayerGetSteamID(item); if (!ServerMonitoredInventoryItems.TryGetValue(key, out var value)) { continue; } foreach (KeyValuePair<int, int> item2 in value) { if (item2.Value == itemHash) { owner = item; spot = item2.Key; return true; } } } return false; } internal static void Clear() { ServerMonitoredInventoryItems.Clear(); } } internal static class InventorySlotList { internal static void EnsureSlots(Inventory inventory, int minimumSlotCount = -1) { if (!((Object)(object)inventory == (Object)null)) { List<InventorySpot> allSpots = inventory.GetAllSpots(); int num = Math.Max(Plugin.EffectiveSlotCount, minimumSlotCount); while (allSpots.Count < num) { allSpots.Add(null); } } } } internal static class InventoryBatteryBinding { private static readonly FieldInfo BatteryVisualLogicField = AccessTools.Field(typeof(InventorySpot), "batteryVisualLogic"); private static readonly FieldInfo BarsField = AccessTools.Field(typeof(BatteryVisualLogic), "bars"); private static readonly FieldInfo TargetScaleField = AccessTools.Field(typeof(BatteryVisualLogic), "targetScale"); private static readonly FieldInfo TargetScaleOriginalField = AccessTools.Field(typeof(BatteryVisualLogic), "targetScaleOriginal"); private static readonly FieldInfo TargetRotationField = AccessTools.Field(typeof(BatteryVisualLogic), "targetRotation"); private static readonly FieldInfo TargetRotationOriginalField = AccessTools.Field(typeof(BatteryVisualLogic), "targetRotationOriginal"); private static readonly FieldInfo TargetPositionField = AccessTools.Field(typeof(BatteryVisualLogic), "targetPosition"); private static readonly FieldInfo TargetPositionOriginalField = AccessTools.Field(typeof(BatteryVisualLogic), "targetPositionOriginal"); private static readonly FieldInfo DoOutroField = AccessTools.Field(typeof(BatteryVisualLogic), "doOutro"); private static readonly FieldInfo SpringScaleField = AccessTools.Field(typeof(BatteryVisualLogic), "springScale"); private static readonly FieldInfo SpringRotationField = AccessTools.Field(typeof(BatteryVisualLogic), "springRotation"); private static readonly FieldInfo SpringPositionField = AccessTools.Field(typeof(BatteryVisualLogic), "springPosition"); private static readonly FieldInfo SpringFloatLastPositionField = AccessTools.Field(typeof(SpringFloat), "lastPosition"); private static readonly FieldInfo SpringVectorLastPositionField = AccessTools.Field(typeof(SpringVector3), "lastPosition"); internal static BatteryVisualLogic Bind(InventorySpot spot, bool activateForVanillaStart) { if ((Object)(object)spot == (Object)null) { return null; } object? obj = BatteryVisualLogicField?.GetValue(spot); BatteryVisualLogic val = (BatteryVisualLogic)((obj is BatteryVisualLogic) ? obj : null); if ((Object)(object)val != (Object)null && ((Component)val).transform.IsChildOf(((Component)spot).transform)) { if (activateForVanillaStart && !((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } return val; } BatteryVisualLogic val2 = ((Component)spot).GetComponentsInChildren<BatteryVisualLogic>(true).FirstOrDefault(); if ((Object)(object)val2 == (Object)null) { return null; } if (activateForVanillaStart && !((Component)val2).gameObject.activeSelf) { ((Component)val2).gameObject.SetActive(true); } BatteryVisualLogicField?.SetValue(spot, val2); return val2; } internal static void PrepareFreshClone(InventorySpot spot, BatteryVisualLogic templateVisual) { BatteryVisualLogic val = Bind(spot, activateForVanillaStart: true); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)$"Inventory slot {((spot != null) ? new int?(spot.inventorySpotIndex + 1) : null)} has no BatteryVisualLogic child."); return; } BarsField?.SetValue(val, new List<GameObject>()); ResetCloneTargets(val, templateVisual); ResetSprings(val, GetTargetScale(val, templateVisual)); } internal static void Refresh(InventorySpot spot) { BatteryVisualLogic val = Bind(spot, activateForVanillaStart: false); if ((Object)(object)val == (Object)null) { return; } ItemEquippable currentItem = spot.CurrentItem; ItemBattery val2 = (((Object)(object)currentItem == (Object)null) ? null : ((Component)currentItem).GetComponent<ItemBattery>()); if (!((Object)(object)val2 == (Object)null)) { val.itemBattery = val2; if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } val.ResetOutro(); val.BatteryBarsSet(); val.BatteryBarsUpdate(-1, true); } } private static void ResetCloneTargets(BatteryVisualLogic visual, BatteryVisualLogic templateVisual) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)visual == (Object)null)) { Vector3 targetPosition = GetTargetPosition(visual, templateVisual); float targetScale = GetTargetScale(visual, templateVisual); float fieldValue = GetFieldValue(TargetRotationOriginalField, templateVisual, 0f); ((Component)visual).transform.localPosition = targetPosition; ((Component)visual).transform.localScale = new Vector3(targetScale, targetScale, targetScale); ((Component)visual).transform.localRotation = Quaternion.Euler(0f, 0f, fieldValue); TargetPositionField?.SetValue(visual, targetPosition); TargetPositionOriginalField?.SetValue(visual, targetPosition); TargetScaleField?.SetValue(visual, targetScale); TargetScaleOriginalField?.SetValue(visual, targetScale); TargetRotationField?.SetValue(visual, fieldValue); TargetRotationOriginalField?.SetValue(visual, fieldValue); DoOutroField?.SetValue(visual, false); } } private static Vector3 GetTargetPosition(BatteryVisualLogic visual, BatteryVisualLogic templateVisual) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Vector3 fieldValue = GetFieldValue<Vector3>(TargetPositionOriginalField, templateVisual, ((Component)visual).transform.localPosition); if (float.IsNaN(fieldValue.x) || float.IsInfinity(fieldValue.x)) { return ((Component)visual).transform.localPosition; } return fieldValue; } private static float GetTargetScale(BatteryVisualLogic visual, BatteryVisualLogic templateVisual) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) float fieldValue = GetFieldValue(TargetScaleOriginalField, templateVisual, 0f); if (fieldValue > 0.001f) { return fieldValue; } fieldValue = GetFieldValue(TargetScaleField, templateVisual, 0f); if (fieldValue > 0.001f) { return fieldValue; } fieldValue = Mathf.Max(((Component)visual).transform.localScale.x, ((Component)visual).transform.localScale.y); if (!(fieldValue > 0.001f)) { return 0.5f; } return fieldValue; } private static T GetFieldValue<T>(FieldInfo field, object instance, T fallback) { if (field == null || instance == null) { return fallback; } object value = field.GetValue(instance); if (value is T) { return (T)value; } return fallback; } private static void ResetSprings(BatteryVisualLogic visual, float targetScale) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_008e: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) SpringFloat val = new SpringFloat { damping = 0.4f, speed = 30f }; SpringFloatLastPositionField?.SetValue(val, targetScale); SpringScaleField?.SetValue(visual, val); SpringFloat val2 = new SpringFloat { damping = 0.3f, speed = 40f }; SpringFloatLastPositionField?.SetValue(val2, 0f); SpringRotationField?.SetValue(visual, val2); SpringVector3 val3 = new SpringVector3 { damping = 0.35f, speed = 30f }; SpringVectorLastPositionField?.SetValue(val3, ((Component)visual).transform.localPosition); SpringPositionField?.SetValue(visual, val3); } } internal static class InventoryUiBuilder { private static readonly FieldInfo AllChildrenField = AccessTools.Field(typeof(SemiUI), "allChildren"); private static readonly FieldInfo CurrentStateField = AccessTools.Field(typeof(InventorySpot), "currentState"); private static readonly FieldInfo CurrentItemBackingField = AccessTools.Field(typeof(InventorySpot), "<CurrentItem>k__BackingField"); private static readonly FieldInfo StateStartField = AccessTools.Field(typeof(InventorySpot), "stateStart"); internal static void Rebuild(InventoryUI inventoryUi) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventoryUi == (Object)null) { return; } int effectiveSlotCount = Plugin.EffectiveSlotCount; if (effectiveSlotCount <= 3) { return; } try { Transform transform = ((Component)inventoryUi).transform; List<InventorySpot> list = (from spot in ((Component)transform).GetComponentsInChildren<InventorySpot>(true) orderby spot.inventorySpotIndex, ((Object)spot).name select spot).ToList(); InventorySpot val = ((IEnumerable<InventorySpot>)list).FirstOrDefault((Func<InventorySpot, bool>)((InventorySpot spot) => spot.inventorySpotIndex == 0)) ?? list.FirstOrDefault(); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"Could not find an InventorySpot template in InventoryUI."); return; } List<GameObject> list2 = AllChildrenField?.GetValue(inventoryUi) as List<GameObject>; float num = CalculateSpacing(list); float num2 = CalculateCenterX(list, ((Component)val).transform.localPosition.x) - num * (float)(effectiveSlotCount - 1) * 0.5f; float y = ((Component)val).transform.localPosition.y; float z = ((Component)val).transform.localPosition.z; for (int i = 0; i < effectiveSlotCount; i++) { InventorySpot orCreateSpot = GetOrCreateSpot(transform, val, list, i); if (!((Object)(object)orCreateSpot == (Object)null)) { ConfigureSpot(orCreateSpot, i, num2 + num * (float)i, y, z); GameObject gameObject = ((Component)orCreateSpot).gameObject; if (list2 != null && !list2.Contains(gameObject)) { list2.Add(gameObject); } } } InventorySlotList.EnsureSlots(Inventory.instance, effectiveSlotCount); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"Failed to rebuild inventory slots: {arg}"); } } private static InventorySpot GetOrCreateSpot(Transform root, InventorySpot template, List<InventorySpot> existingSpots, int index) { InventorySpot val = ((IEnumerable<InventorySpot>)existingSpots).FirstOrDefault((Func<InventorySpot, bool>)((InventorySpot spot) => spot.inventorySpotIndex == index)); if ((Object)(object)val != (Object)null) { return val; } Transform val2 = root.Find($"Inventory Spot {index + 1}"); InventorySpot val3 = default(InventorySpot); if ((Object)(object)val2 != (Object)null && ((Component)val2).TryGetComponent<InventorySpot>(ref val3)) { if (!existingSpots.Contains(val3)) { existingSpots.Add(val3); } return val3; } Transform obj = Object.Instantiate<Transform>(((Component)template).transform, ((Component)template).transform.parent); ((Object)obj).name = $"Inventory Spot {index + 1}"; InventorySpot component = ((Component)obj).GetComponent<InventorySpot>(); BatteryVisualLogic templateVisual = ((Component)template).GetComponentsInChildren<BatteryVisualLogic>(true).FirstOrDefault(); InventoryBatteryBinding.PrepareFreshClone(component, templateVisual); ClearCopiedRuntimeState(component); existingSpots.Add(component); return component; } private static void ClearCopiedRuntimeState(InventorySpot spot) { if (!((Object)(object)spot == (Object)null)) { CurrentItemBackingField?.SetValue(spot, null); if (CurrentStateField != null) { CurrentStateField.SetValue(spot, Enum.ToObject(CurrentStateField.FieldType, 0)); } StateStartField?.SetValue(spot, true); } } private static void ConfigureSpot(InventorySpot spot, int index, float x, float y, float z) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) spot.inventorySpotIndex = index; ((Object)spot).name = $"Inventory Spot {index + 1}"; ((Component)spot).transform.localPosition = new Vector3(x, y, z); ((Component)spot).gameObject.SetActive(true); InventoryBatteryBinding.Bind(spot, activateForVanillaStart: false); string slotLabel = GetSlotLabel(index); if ((Object)(object)spot.noItem != (Object)null) { ((TMP_Text)spot.noItem).text = slotLabel; } Transform val = ((Component)spot).transform.Find("Numbers"); TextMeshProUGUI val2 = default(TextMeshProUGUI); if ((Object)(object)val != (Object)null && ((Component)val).TryGetComponent<TextMeshProUGUI>(ref val2)) { ((TMP_Text)val2).text = slotLabel; } } private static float CalculateSpacing(List<InventorySpot> spots) { List<float> list = (from spot in spots where spot.inventorySpotIndex >= 0 && spot.inventorySpotIndex < 3 orderby spot.inventorySpotIndex select ((Component)spot).transform.localPosition.x).ToList(); if (list.Count >= 2) { float num = Mathf.Abs(list[1] - list[0]); if (num > 1f) { return num; } } return 40f; } private static float CalculateCenterX(List<InventorySpot> spots, float fallback) { List<float> list = (from spot in spots where spot.inventorySpotIndex >= 0 && spot.inventorySpotIndex < 3 orderby spot.inventorySpotIndex select ((Component)spot).transform.localPosition.x).ToList(); if (list.Count >= 3) { return (list[0] + list[2]) * 0.5f; } return fallback; } private static string GetSlotLabel(int index) { if (index != 9) { return (index + 1).ToString(); } return "0"; } } internal static class ExtraSlotInput { private static readonly MethodInfo HandleInputMethod = AccessTools.Method(typeof(InventorySpot), "HandleInput", (Type[])null, (Type[])null); internal static void HandleExtraSlotHotkey(InventorySpot spot) { if (Plugin.ExtraHotkeys.Value && !((Object)(object)spot == (Object)null)) { int inventorySpotIndex = spot.inventorySpotIndex; if (inventorySpotIndex >= 3 && inventorySpotIndex < Plugin.EffectiveSlotCount && WasSlotKeyPressed(inventorySpotIndex)) { HandleInputMethod?.Invoke(spot, Array.Empty<object>()); } } } private static bool WasSlotKeyPressed(int index) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) Keyboard current = Keyboard.current; if (current == null) { return false; } if (!WasPressed(current, MainKeyForSlot(index))) { if (Plugin.NumpadHotkeys.Value) { return WasPressed(current, NumpadKeyForSlot(index)); } return false; } return true; } private static bool WasPressed(Keyboard keyboard, Key key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 0) { return false; } KeyControl val = keyboard[key]; if (val != null) { return ((ButtonControl)val).wasPressedThisFrame; } return false; } private static Key MainKeyForSlot(int index) { return (Key)(index switch { 3 => 44, 4 => 45, 5 => 46, 6 => 47, 7 => 48, 8 => 49, 9 => 50, _ => 0, }); } private static Key NumpadKeyForSlot(int index) { return (Key)(index switch { 3 => 88, 4 => 89, 5 => 90, 6 => 91, 7 => 92, 8 => 93, 9 => 84, _ => 0, }); } } [HarmonyPatch(typeof(Inventory), "Awake")] internal static class InventoryAwakePatch { private static void Postfix(Inventory __instance) { InventorySlotList.EnsureSlots(__instance); } } [HarmonyPatch(typeof(Inventory), "InventorySpotAddAtIndex")] internal static class InventorySpotAddAtIndexPatch { private static void Prefix(Inventory __instance, int index) { InventorySlotList.EnsureSlots(__instance, index + 1); } } [HarmonyPatch(typeof(InventoryUI), "Start")] internal static class InventoryUiStartPatch { private static void Postfix(InventoryUI __instance) { InventoryUiBuilder.Rebuild(__instance); } } [HarmonyPatch(typeof(InventorySpot), "Start")] internal static class InventorySpotStartPatch { private static void Prefix(InventorySpot __instance) { InventoryBatteryBinding.Bind(__instance, activateForVanillaStart: true); } private static void Postfix(InventorySpot __instance) { InventoryBatteryBinding.Refresh(__instance); } } [HarmonyPatch(typeof(InventorySpot), "Update")] internal static class InventorySpotUpdatePatch { private static void Postfix(InventorySpot __instance) { ExtraSlotInput.HandleExtraSlotHotkey(__instance); } } [HarmonyPatch(typeof(InventorySpot), "HandleInput")] internal static class InventorySpotHandleInputPatch { private static bool Prefix(InventorySpot __instance) { return AutoItemSwap.PrefixHandleInput(__instance); } } [HarmonyPatch(typeof(InventorySpot), "EquipItem")] internal static class InventorySpotEquipItemPatch { private static void Postfix(InventorySpot __instance) { InventoryBatteryBinding.Refresh(__instance); } } [HarmonyPatch(typeof(InventorySpot), "UpdateUI")] internal static class InventorySpotUpdateUiPatch { private static void Postfix(InventorySpot __instance) { InventoryBatteryBinding.Refresh(__instance); } } [HarmonyPatch(typeof(InventorySpot), "StateOccupied")] internal static class InventorySpotStateOccupiedPatch { private static void Prefix(InventorySpot __instance) { InventoryBatteryBinding.Bind(__instance, activateForVanillaStart: false); } } [HarmonyPatch(typeof(StatsManager), "PlayerInventoryUpdate")] internal static class StatsManagerPlayerInventoryUpdatePatch { private static void Postfix(string _steamID, string itemName, int spot) { ExtraSlotState.TrackInventoryUpdate(_steamID, itemName, spot); } } [HarmonyPatch(typeof(ItemEquippable), "RPC_RequestEquip")] internal static class ItemEquippableRequestEquipPatch { private static bool Prefix(int spotIndex) { if (IsRestoringFromItemNameLogic() && Plugin.KeepItemsInTruck.Value) { return false; } if (SemiFunc.IsMultiplayer() && Plugin.HostProtection.Value && spotIndex >= Plugin.EffectiveSlotCount) { return false; } return true; } private static bool IsRestoringFromItemNameLogic() { return new StackTrace().GetFrames()?.Any((StackFrame frame) => frame.GetMethod()?.Name == "SetItemNameLOGIC") ?? false; } } [HarmonyPatch(typeof(PunManager), "SetItemNameLOGIC")] internal static class PunManagerSetItemNameLogicPatch { private static void Postfix(string _name, int photonViewID, ItemAttributes _itemAttributes) { if (Plugin.KeepItemsInTruck.Value || string.IsNullOrEmpty(_name)) { return; } try { ItemEquippable val = ResolveItemEquippable(photonViewID, _itemAttributes); if ((Object)(object)val == (Object)null || val.IsEquipped() || !ExtraSlotState.TryFindItemOwnerAndSpot(_name.GetHashCode(), out var owner, out var spot) || spot < 3 || spot >= Plugin.EffectiveSlotCount) { return; } int num = -1; if (SemiFunc.IsMultiplayer()) { if ((Object)(object)owner.photonView == (Object)null) { return; } num = owner.photonView.ViewID; } val.RequestEquip(spot, num); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to restore extra-slot item '" + _name + "': " + ex.Message)); } } private static ItemEquippable ResolveItemEquippable(int photonViewID, ItemAttributes itemAttributes) { ItemAttributes val = itemAttributes; if (SemiFunc.IsMultiplayer()) { PhotonView val2 = PhotonView.Find(photonViewID); if ((Object)(object)val2 == (Object)null) { return null; } val = ((Component)val2).GetComponent<ItemAttributes>(); } if (!((Object)(object)val == (Object)null)) { return ((Component)val).GetComponent<ItemEquippable>(); } return null; } } [HarmonyPatch(typeof(MainMenuOpen), "Start")] internal static class MainMenuOpenStartPatch { private static void Postfix() { ExtraSlotState.Clear(); } } }