using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GearSlots.Configuration; using GearSlots.Core; using GearSlots.Patches; using GearSlots.Runtime; using GearSlots.UI; using HarmonyLib; using JG224.ModCore.API; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("GearSlots")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.1.0")] [assembly: AssemblyInformationalVersion("0.5.1")] [assembly: AssemblyProduct("GearSlots")] [assembly: AssemblyTitle("GearSlots")] [assembly: AssemblyVersion("0.5.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 GearSlots { public static class GearSlotsApi { public static bool IsProtected(ItemData? item) { if (item != null) { return SlotStateManager.ContainsAuxiliaryItem(item); } return false; } public static bool IsProtectedInventory(Inventory? inventory) { if (inventory != null) { return SlotStateManager.IsAuxiliaryInventory(inventory); } return false; } } [BepInPlugin("com.jg224.gearslots", "GearSlots", "0.5.1")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInProcess("valheim.exe")] public sealed class GearSlotsPlugin : BaseUnityPlugin { public const string PluginGuid = "com.jg224.gearslots"; public const string PluginName = "GearSlots"; public const string PluginVersion = "0.5.1"; public const string ModCoreGuid = "com.jg224.modcore"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("gearslots"); private static readonly IReadOnlyDictionary ConflictingPlugins = new Dictionary(StringComparer.Ordinal) { ["Azumatt.AzuExtendedPlayerInventory"] = "AzuExtendedPlayerInventory", ["randyknapp.mods.equipmentandquickslots"] = "Equipment and Quick Slots", ["aedenthorn.ExtendedPlayerInventory"] = "Extended Player Inventory", ["com.bruce.valheim.comfyquickslots"] = "Comfy Quick Slots", ["shudnal.ExtraSlots"] = "Extra Slots", ["shudnal.ExtraSlotsCustomSlots"] = "Extra Slots Custom Slots", ["moreslots"] = "More Slots", ["toombe.EquipMultipleUtilityItemsUpdate"] = "Equip Multiple Utility Items Update", ["aedenthorn.EquipMultipleUtilityItems"] = "Equip Multiple Utility Items" }; private Harmony? harmony; private readonly List registrations = new List(); private bool shutDown; internal static ManualLogSource ModLog { get; private set; } = null; internal static GearSlotsConfig Settings { get; private set; } = null; internal static ICoreServices Core { get; private set; } = null; private void Awake() { //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0086: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) ModLog = ((BaseUnityPlugin)this).Logger; try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before GearSlots."); } SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.1", ref val)) { throw new InvalidOperationException("GearSlots has an invalid plugin version."); } Core = ModCoreApi.Services; registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "com.jg224.gearslots", "GearSlots", val, 1, (ModuleSide)1, (ModuleRequirement)1, 0uL, 1, 1))); registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)3, "com.jg224.gearslots.", 1, Array.Empty())); registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)2, "com.jg224.gearslots.", 1, Array.Empty())); registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)8, "gearslots.", 1, Array.Empty())); registrations.Add(Core.Ui.Reserve(new UiReservation(ModuleId, (UiSurface)4, "dedicated-equipment-and-quick-slots", 30, false))); registrations.Add(Core.Ui.Reserve(new UiReservation(ModuleId, (UiSurface)1, "guardian-adjacent.quick-slots", 30, false))); Settings = new GearSlotsConfig(ConfigFileMigration.Open((BaseUnityPlugin)(object)this, Paths.ConfigPath, ((BaseUnityPlugin)this).Logger)); Settings.Changed += SlotStateManager.NotifyConfigurationChanged; SlotStateManager.Initialize(); NamedLoadouts.Register(); harmony = new Harmony("com.jg224.gearslots"); harmony.PatchAll(typeof(GearSlotsPlugin).Assembly); WarnAboutSlotProviders(); Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Client-local protected slots, persistence, and UI hooks ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"GearSlots 0.5.1 loaded for BepInEx 5."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} failed to initialize safely: {1}", "GearSlots", ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void Update() { SlotStateManager.Tick(); } private void OnDestroy() { Shutdown(); } private void OnGUI() { GearSlotsRecoveryScreen.Draw(); } private void Shutdown() { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (shutDown) { return; } shutDown = true; if (Settings != null) { Settings.Changed -= SlotStateManager.NotifyConfigurationChanged; } SlotStateManager.Shutdown(); GearSlotsRecoveryScreen.Close(); GearSlotsUi.Destroy(); GearSlotsUi.DestroyHud(); Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; for (int num = registrations.Count - 1; num >= 0; num--) { try { registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; } private void WarnAboutSlotProviders() { foreach (KeyValuePair conflictingPlugin in ConflictingPlugins) { if (Chainloader.PluginInfos.ContainsKey(conflictingPlugin.Key)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("GearSlots detected " + conflictingPlugin.Value + " (" + conflictingPlugin.Key + "). Both mods provide overlapping equipment or quick slots; disable one provider before playing this character.")); } } } } } namespace GearSlots.UI { internal static class GearSlotsRecoveryScreen { [CompilerGenerated] private static class <>O { public static WindowFunction <0>__DrawWindow; } private static bool open; private static Rect window = new Rect(240f, 180f, 460f, 255f); private static string result = ""; internal static void Open() { open = true; result = ""; } internal static void Close() { open = false; } internal static void Draw() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (open && InventoryGui.IsVisible()) { Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = new Color(0.25f, 0.2f, 0.14f, 1f); Rect val = window; object obj = <>O.<0>__DrawWindow; if (obj == null) { WindowFunction val2 = DrawWindow; <>O.<0>__DrawWindow = val2; obj = (object)val2; } window = GUILayout.Window(224102, val, (WindowFunction)obj, "GearSlots — Recovery", Array.Empty()); GUI.backgroundColor = backgroundColor; } } private static void DrawWindow(int id) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.label) { wordWrap = true }; GUILayout.Label(SlotStateManager.RecoveryStatus, val, Array.Empty()); GUILayout.Label("Return all moves complete stacks into empty main-inventory cells. If they will not all fit, everything stays where it is.", val, Array.Empty()); bool enabled = GUI.enabled; GUI.enabled = enabled && !SlotStateManager.RecoveryBlocked; if (GUILayout.Button("Return all to inventory", Array.Empty())) { result = NamedLoadouts.ReturnAll(); } GUI.enabled = enabled; GUI.enabled = enabled && SlotStateManager.CanRetryRecovery; if (GUILayout.Button("Retry load from preserved character data", Array.Empty())) { SlotStateManager.RetryRecovery(); } GUI.enabled = enabled; if (result.Length != 0) { GUILayout.Label(result, val, Array.Empty()); } if (GUILayout.Button("Close", Array.Empty())) { Close(); } GUI.DragWindow(); } } internal static class GearSlotsUi { private sealed class QuickHudElement { internal GameObject GameObject; internal Image Icon; internal GuiBar Durability; internal TMP_Text Amount; internal TMP_Text Binding; internal GameObject Equipped; internal GameObject Queued; internal GameObject Selection; internal UITooltip? Tooltip; } private const string GearGridName = "GearSlots_DedicatedGrid"; private const string QuickGridName = "GearSlots_QuickGrid"; private const string QuickHudName = "GearSlots_QuickHud"; private const string LabelName = "GearSlots_EmptyLabel"; private const string UtilityHeaderName = "GearSlots_UtilityHeader"; private const string GearHeaderName = "GearSlots_GearHeader"; private const float InventoryPanelMargin = 8f; private const float DedicatedHeaderHeight = 24f; private const int DedicatedColumns = 2; private const int DedicatedRows = 5; private static readonly MethodInfo SetupDragItemMethod = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3] { typeof(ItemData), typeof(Inventory), typeof(int) }, (Type[])null); private static readonly MethodInfo ShowSplitDialogMethod = AccessTools.Method(typeof(InventoryGui), "ShowSplitDialog", new Type[2] { typeof(ItemData), typeof(Inventory) }, (Type[])null); private static readonly MethodInfo OnSelectedItemMethod = AccessTools.Method(typeof(InventoryGui), "OnSelectedItem", new Type[4] { typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i), typeof(Modifier) }, (Type[])null); private static readonly MethodInfo OnRightClickItemMethod = AccessTools.Method(typeof(InventoryGui), "OnRightClickItem", new Type[3] { typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i) }, (Type[])null); private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements"); private static readonly FieldInfo SelectedPositionField = AccessTools.Field(typeof(InventoryGrid), "m_selected"); private static readonly FieldInfo DragObjectField = AccessTools.Field(typeof(InventoryGui), "m_dragGo"); private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem"); private static readonly FieldInfo DragInventoryField = AccessTools.Field(typeof(InventoryGui), "m_dragInventory"); private static readonly List PointerRaycastResults = new List(); private static InventoryGui? inventoryGui; private static GameObject? gearGridObject; private static GameObject? quickGridObject; private static InventoryGrid? gearGrid; private static InventoryGrid? quickGrid; private static Hud? hud; private static HotkeyBar? nativeHotkeyBar; private static RectTransform? quickHudRoot; private static readonly List QuickHudElements = new List(); private static readonly Vector3[] GuardianCorners = (Vector3[])(object)new Vector3[4]; private static bool dirty = true; private static bool inventoryLayoutLogged; private static bool inventoryVisualsLogged; internal static void Create(InventoryGui gui) { Destroy(); inventoryGui = gui; gearGrid = CreateGrid(gui, "GearSlots_DedicatedGrid", out gearGridObject); quickGrid = CreateGrid(gui, "GearSlots_QuickGrid", out quickGridObject); SetGridSize(gearGrid, 2, 5, 24f); SetGridSize(quickGrid, 3, 1, 0f); AppendGamepadGroups(gui, gearGrid.m_uiGroup, quickGrid.m_uiGroup); ApplyConfiguration(); BindInventories(); EnsureQuickHud(); } internal static void Destroy() { if ((Object)(object)gearGridObject != (Object)null) { Object.Destroy((Object)(object)gearGridObject); } if ((Object)(object)quickGridObject != (Object)null) { Object.Destroy((Object)(object)quickGridObject); } inventoryGui = null; gearGridObject = null; quickGridObject = null; gearGrid = null; quickGrid = null; dirty = true; inventoryLayoutLogged = false; inventoryVisualsLogged = false; } internal static void CreateHud(Hud instance) { DestroyHud(); hud = instance; EnsureQuickHud(); } internal static void DestroyHud() { if ((Object)(object)quickHudRoot != (Object)null) { Object.Destroy((Object)(object)((Component)quickHudRoot).gameObject); } hud = null; nativeHotkeyBar = null; quickHudRoot = null; QuickHudElements.Clear(); dirty = true; } internal static void BindInventories() { dirty = true; Refresh(); } internal static void UnbindInventories() { dirty = true; } internal static void MarkDirty() { dirty = true; } internal static void Tick() { EnsureQuickHud(); bool flag = (Object)(object)inventoryGui != (Object)null && InventoryGui.IsVisible(); InventoryGui? obj = inventoryGui; bool active = SlotPanelLayout.ShouldShowAuxiliaryPanels(flag, obj != null && obj.IsSkillsPanelOpen); if ((Object)(object)gearGridObject != (Object)null) { gearGridObject.SetActive(active); } if ((Object)(object)quickGridObject != (Object)null) { quickGridObject.SetActive(active); } if (flag) { PositionInventoryGrids(); } if ((Object)(object)quickHudRoot != (Object)null) { Player currentPlayer = SlotStateManager.CurrentPlayer; ((Component)quickHudRoot).gameObject.SetActive(!flag && (Object)(object)currentPlayer != (Object)null && !((Character)currentPlayer).IsDead()); PositionQuickHud(); } Refresh(force: true); } internal static void ApplyConfiguration() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gearGridObject != (Object)null && (Object)(object)quickGridObject != (Object)null) { float num = Mathf.Clamp(GearSlotsPlugin.Settings.UiScale.Value, 0.5f, 1.5f); ((Transform)gearGridObject.GetComponent()).localScale = Vector3.one * num; ((Transform)quickGridObject.GetComponent()).localScale = Vector3.one * num; PositionInventoryGrids(); } PositionQuickHud(); dirty = true; } internal static bool HandleSelected(InventoryGui gui, InventoryGrid selectedGrid, ItemData? selectedItem, Vector2i position, Modifier modifier, GameObject? dragObject, ItemData? dragItem, Inventory? dragInventory, int dragAmount) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Invalid comparison between Unknown and I4 //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Invalid comparison between Unknown and I4 //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) bool flag = SlotStateManager.IsAuxiliaryInventory(selectedGrid.GetInventory()); bool flag2 = dragInventory != null && SlotStateManager.IsAuxiliaryInventory(dragInventory); if (!flag && !flag2) { return false; } Player currentPlayer = SlotStateManager.CurrentPlayer; if ((Object)(object)currentPlayer == (Object)null || ((Character)currentPlayer).IsTeleporting()) { return true; } if ((Object)(object)dragObject != (Object)null && dragItem != null && dragInventory != null) { if (!dragInventory.GetAllItems().Contains(dragItem)) { ClearDrag(gui); return true; } if ((!flag) ? SlotTransferService.TryDropOnRegularGrid(selectedGrid, dragInventory, dragItem, dragAmount, position) : (SlotStateManager.TryGetSlot(selectedGrid.GetInventory(), position, out var slot) && SlotTransferService.TryPlaceInSlot(dragInventory, dragItem, dragAmount, slot))) { PlayMoveEffect(gui); ClearDrag(gui); } return true; } if (!flag || selectedItem == null) { return true; } if ((int)modifier == 1) { OpenSplitDialog(gui, selectedItem, selectedGrid.GetInventory()); return true; } if ((int)modifier != 2) { if ((int)modifier == 3) { if (SlotTransferService.TryDropAtPlayer(selectedItem)) { PlayMoveEffect(gui); } } else { SetupDragItemMethod.Invoke(gui, new object[3] { selectedItem, selectedGrid.GetInventory(), selectedItem.m_stack }); } } else if (SlotTransferService.TryMoveItemToMain(selectedItem)) { PlayMoveEffect(gui); } return true; } internal static bool HandleRightClick(InventoryGrid grid, ItemData? item, Vector2i position) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!SlotStateManager.IsAuxiliaryInventory(grid.GetInventory())) { return false; } if (item != null && SlotStateManager.TryGetSlot(grid.GetInventory(), position, out var slot)) { if (SlotRuleEngine.IsQuick(slot)) { SlotStateManager.UseQuickSlot((int)(slot - 6)); } else if (SlotTransferService.TryMoveItemToMain(item) && (Object)(object)inventoryGui != (Object)null) { PlayMoveEffect(inventoryGui); } } return true; } internal static bool HandleDedicatedGamepad(InventoryGrid grid) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_0140: Unknown result type (might be due to invalid IL or missing references) if (grid != gearGrid) { return false; } if ((Object)(object)grid.m_uiGroup == (Object)null || !grid.m_uiGroup.IsActive || Console.IsVisible()) { return true; } Vector2i val = (Vector2i)SelectedPositionField.GetValue(grid); int num = Mathf.Clamp(val.x, 0, SlotRuleEngine.DedicatedSlots.Count - 1); if (ZInput.GetButtonDown("JoyDPadUp") || ZInput.GetButtonDown("JoyLStickUp")) { num = DedicatedPanelLayout.GetNeighborIndex(num, PanelDirection.Up); } if (ZInput.GetButtonDown("JoyDPadDown") || ZInput.GetButtonDown("JoyLStickDown")) { num = DedicatedPanelLayout.GetNeighborIndex(num, PanelDirection.Down); } if (ZInput.GetButtonDown("JoyDPadLeft") || ZInput.GetButtonDown("JoyLStickLeft")) { num = DedicatedPanelLayout.GetNeighborIndex(num, PanelDirection.Left); } if (ZInput.GetButtonDown("JoyDPadRight") || ZInput.GetButtonDown("JoyLStickRight")) { num = DedicatedPanelLayout.GetNeighborIndex(num, PanelDirection.Right); } ((Vector2i)(ref val))..ctor(num, 0); SelectedPositionField.SetValue(grid, val); Inventory inventory = grid.GetInventory(); ItemData arg = ((inventory != null) ? inventory.GetItemAt(num, 0) : null); if (ZInput.GetButtonDown("JoyButtonA")) { Modifier arg2 = (Modifier)0; if (ZInput.GetButton("JoyLTrigger")) { arg2 = (Modifier)1; } if (ZInput.GetButton("JoyRTrigger")) { arg2 = (Modifier)3; } grid.m_onSelected?.Invoke(grid, arg, val, arg2); } if (ZInput.GetButtonDown("JoyButtonX")) { if (ZInput.GetButton("JoyLTrigger")) { grid.m_onSelected?.Invoke(grid, arg, val, (Modifier)2); } else { grid.m_onRightClick?.Invoke(grid, arg, val); } } return true; } private static InventoryGrid CreateGrid(InventoryGui gui, string name, out GameObject rootObject) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) rootObject = new GameObject(name, new Type[4] { typeof(RectTransform), typeof(CanvasGroup), typeof(UIGroupHandler), typeof(InventoryGrid) }); rootObject.transform.SetParent(gui.m_inventoryRoot, false); RectTransform component = rootObject.GetComponent(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0f, 1f); RectTransform component2 = new GameObject(name + "_Root", new Type[1] { typeof(RectTransform) }).GetComponent(); ((Transform)component2).SetParent((Transform)(object)component, false); component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(0f, 1f); component2.pivot = new Vector2(0f, 1f); component2.anchoredPosition = Vector2.zero; InventoryGrid playerGrid = gui.m_playerGrid; UIGroupHandler component3 = rootObject.GetComponent(); if ((Object)(object)playerGrid.m_uiGroup != (Object)null) { component3.m_defaultElementFallbackMode = playerGrid.m_uiGroup.m_defaultElementFallbackMode; component3.m_groupPriority = playerGrid.m_uiGroup.m_groupPriority; component3.m_setDefaultOnKBM = playerGrid.m_uiGroup.m_setDefaultOnKBM; component3.m_resetActiveElementOnStateChange = playerGrid.m_uiGroup.m_resetActiveElementOnStateChange; } component3.SetActive(false); InventoryGrid component4 = rootObject.GetComponent(); component4.m_elementPrefab = playerGrid.m_elementPrefab; component4.m_gridRoot = component2; component4.m_tooltipAnchor = playerGrid.m_tooltipAnchor; component4.m_elementSpace = playerGrid.m_elementSpace; component4.m_uiGroup = component3; component4.CanDropDragOntoItem = playerGrid.CanDropDragOntoItem; component4.m_onSelected = null; component4.m_onRightClick = null; component4.OnMoveToUpperInventoryGrid = null; component4.OnMoveToLowerInventoryGrid = null; component4.m_onSelected = (Action)Delegate.Combine(component4.m_onSelected, (Action)delegate(InventoryGrid selectedGrid, ItemData item, Vector2i position, Modifier modifier) { //IL_001b: 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) OnSelectedItemMethod.Invoke(gui, new object[4] { selectedGrid, item, position, modifier }); }); component4.m_onRightClick = (Action)Delegate.Combine(component4.m_onRightClick, (Action)delegate(InventoryGrid selectedGrid, ItemData item, Vector2i position) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) OnRightClickItemMethod.Invoke(gui, new object[3] { selectedGrid, item, position }); }); return component4; } private static void SetGridSize(InventoryGrid grid, int columns, int rows, float headerHeight) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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) RectTransform val = (RectTransform)((Component)grid).transform; val.SetSizeWithCurrentAnchors((Axis)0, (float)columns * grid.m_elementSpace); val.SetSizeWithCurrentAnchors((Axis)1, (float)rows * grid.m_elementSpace + headerHeight); grid.m_gridRoot.SetSizeWithCurrentAnchors((Axis)0, (float)columns * grid.m_elementSpace); grid.m_gridRoot.SetSizeWithCurrentAnchors((Axis)1, (float)rows * grid.m_elementSpace); grid.m_gridRoot.anchorMin = new Vector2(0f, 1f); grid.m_gridRoot.anchorMax = new Vector2(0f, 1f); grid.m_gridRoot.pivot = new Vector2(0f, 1f); grid.m_gridRoot.anchoredPosition = new Vector2(0f, 0f - headerHeight); } private static void AppendGamepadGroups(InventoryGui gui, params UIGroupHandler[] groups) { gui.m_uiGroups = gui.m_uiGroups.Concat(groups.Where((UIGroupHandler group) => (Object)(object)group != (Object)null)).ToArray(); } private static void ConfigureInventoryTransform(RectTransform transform, Vector3 localPosition, float scale) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) transform.anchorMin = new Vector2(0.5f, 0.5f); transform.anchorMax = new Vector2(0.5f, 0.5f); transform.pivot = new Vector2(0f, 1f); ((Transform)transform).localPosition = localPosition; ((Transform)transform).localScale = Vector3.one * Mathf.Clamp(scale, 0.5f, 1.5f); } private static void PositionInventoryGrids() { //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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventoryGui == (Object)null || (Object)(object)gearGridObject == (Object)null || (Object)(object)quickGridObject == (Object)null || (Object)(object)gearGrid == (Object)null || (Object)(object)quickGrid == (Object)null) { return; } Transform inventoryRoot = inventoryGui.m_inventoryRoot; RectTransform val = (RectTransform)(object)((inventoryRoot is RectTransform) ? inventoryRoot : null); if (val != null) { Transform obj = ((Transform)inventoryGui.m_player).Find("Bkg"); RectTransform val2 = (RectTransform)(((object)((obj is RectTransform) ? obj : null)) ?? ((object)inventoryGui.m_player)); Vector3[] array = (Vector3[])(object)new Vector3[4]; val2.GetWorldCorners(array); Vector3 val3 = ((Transform)val).InverseTransformPoint(array[2]); GearSlotsConfig settings = GearSlotsPlugin.Settings; float num = Mathf.Clamp(settings.UiScale.Value, 0.5f, 1.5f); float num2 = 2f * gearGrid.m_elementSpace; float num3 = 5f * gearGrid.m_elementSpace + 24f; float num4 = 3f * quickGrid.m_elementSpace; float elementSpace = quickGrid.m_elementSpace; Rect rect = val.rect; float x = val3.x + settings.UiOffsetX.Value; float y = val3.y + settings.UiOffsetY.Value; string arg = "right of " + ((Object)val2).name; SlotPanelPlacement slotPanelPlacement = SlotPanelLayout.QuickBelowDedicated(x, y, num3, num, settings.InventoryQuickOffsetX.Value, settings.InventoryQuickOffsetY.Value); float x2 = slotPanelPlacement.QuickX; float y2 = slotPanelPlacement.QuickY; if (((Rect)(ref rect)).width > 0f && ((Rect)(ref rect)).height > 0f) { ClampPanelToViewport(ref x, ref y, num2 * num, num3 * num, rect); ClampPanelToViewport(ref x2, ref y2, num4 * num, elementSpace * num, rect); } Vector3 localPosition = default(Vector3); ((Vector3)(ref localPosition))..ctor(x, y, val3.z); Vector3 localPosition2 = default(Vector3); ((Vector3)(ref localPosition2))..ctor(x2, y2, val3.z); ConfigureInventoryTransform(gearGridObject.GetComponent(), localPosition, num); ConfigureInventoryTransform(quickGridObject.GetComponent(), localPosition2, num); if (!inventoryLayoutLogged) { inventoryLayoutLogged = true; GearSlotsPlugin.ModLog.LogInfo((object)($"GearSlots inventory panels anchored {arg}: dedicated=({x:0.#}, {y:0.#}), " + $"quick=({x2:0.#}, {y2:0.#}); " + $"viewport {((Rect)(ref rect)).width:0.#}x{((Rect)(ref rect)).height:0.#}.")); } } } private static void ClampPanelToViewport(ref float x, ref float y, float width, float height, Rect viewport) { x = Mathf.Clamp(x, ((Rect)(ref viewport)).xMin + 8f, ((Rect)(ref viewport)).xMax - width - 8f); y = Mathf.Clamp(y, ((Rect)(ref viewport)).yMin + height + 8f, ((Rect)(ref viewport)).yMax - 8f); } private static void EnsureQuickHud() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) Hud instance = Hud.instance; if ((Object)(object)instance == (Object)null) { return; } if (hud != instance) { DestroyHud(); hud = instance; } if ((Object)(object)quickHudRoot != (Object)null) { return; } nativeHotkeyBar = instance.m_rootObject.GetComponentInChildren(true); if (!((Object)(object)nativeHotkeyBar == (Object)null) && !((Object)(object)nativeHotkeyBar.m_elementPrefab == (Object)null)) { quickHudRoot = new GameObject("GearSlots_QuickHud", new Type[1] { typeof(RectTransform) }).GetComponent(); ((Transform)quickHudRoot).SetParent(((Component)nativeHotkeyBar).transform.parent, false); ((Transform)quickHudRoot).SetSiblingIndex(((Component)nativeHotkeyBar).transform.GetSiblingIndex() + 1); for (int i = 0; i < 3; i++) { GameObject val = Object.Instantiate(nativeHotkeyBar.m_elementPrefab, (Transform)(object)quickHudRoot); ((Object)val).name = $"GearSlots_QuickHud_{i + 1}"; val.SetActive(true); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(0.5f, 0.5f); val2.anchorMax = new Vector2(0.5f, 0.5f); val2.pivot = new Vector2(0.5f, 0.5f); val.transform.localPosition = new Vector3(SlotPanelLayout.GetHorizontalQuickElementX(i, 3, nativeHotkeyBar.m_elementSpace), 0f, 0f); QuickHudElement quickHudElement = new QuickHudElement { GameObject = val, Icon = ((Component)val.transform.Find("icon")).GetComponent(), Durability = ((Component)val.transform.Find("durability")).GetComponent(), Amount = ((Component)val.transform.Find("amount")).GetComponent(), Binding = ((Component)val.transform.Find("binding")).GetComponent(), Equipped = ((Component)val.transform.Find("equiped")).gameObject, Queued = ((Component)val.transform.Find("queued")).gameObject, Selection = ((Component)val.transform.Find("selected")).gameObject, Tooltip = val.GetComponent() }; quickHudElement.Selection.SetActive(false); QuickHudElements.Add(quickHudElement); } PositionQuickHud(); dirty = true; } } private static void PositionQuickHud() { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)quickHudRoot == (Object)null || (Object)(object)nativeHotkeyBar == (Object)null || (Object)(object)hud?.m_gpRoot == (Object)null) { return; } Transform transform = ((Component)nativeHotkeyBar).transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val == null) { return; } Transform parent = ((Transform)quickHudRoot).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val2 == null || QuickHudElements.Count == 0) { return; } Transform transform2 = QuickHudElements[0].GameObject.transform; RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if (val3 != null && TryGetRectBounds(hud.m_gpRoot, val2, out var left, out var right, out var bottom, out var top, out var depth)) { GearSlotsConfig settings = GearSlotsPlugin.Settings; HorizontalHudPlacement horizontalHudPlacement = SlotPanelLayout.HorizontalBesideBox(left, right, bottom, top, 8f, settings.QuickHudOffsetX.Value, settings.QuickHudOffsetY.Value); Rect rect = val3.rect; float num = Mathf.Max(1f, Mathf.Abs(((Rect)(ref rect)).width)); rect = val3.rect; float num2 = Mathf.Max(1f, Mathf.Abs(((Rect)(ref rect)).height)); Vector3 localScale = default(Vector3); ((Vector3)(ref localScale))..ctor(horizontalHudPlacement.CellWidth / num, horizontalHudPlacement.CellHeight / num2, ((Transform)val).localScale.z); quickHudRoot.anchorMin = new Vector2(0.5f, 0.5f); quickHudRoot.anchorMax = new Vector2(0.5f, 0.5f); quickHudRoot.pivot = new Vector2(0.5f, 0.5f); ((Transform)quickHudRoot).localPosition = new Vector3(horizontalHudPlacement.FirstCellCenterX, horizontalHudPlacement.CellCenterY, depth); ((Transform)quickHudRoot).localRotation = ((Transform)val).localRotation; ((Transform)quickHudRoot).localScale = localScale; bool flag = settings.QuickHudOrientation.Value == QuickHudOrientation.Vertical; quickHudRoot.sizeDelta = (flag ? new Vector2(num, num2 + nativeHotkeyBar.m_elementSpace * (float)(QuickHudElements.Count - 1)) : new Vector2(num + nativeHotkeyBar.m_elementSpace * (float)(QuickHudElements.Count - 1), num2)); for (int i = 0; i < QuickHudElements.Count; i++) { QuickHudElements[i].GameObject.transform.localPosition = new Vector3(flag ? 0f : SlotPanelLayout.GetHorizontalQuickElementX(i, QuickHudElements.Count, nativeHotkeyBar.m_elementSpace), flag ? SlotPanelLayout.GetCenteredVerticalQuickElementY(i, QuickHudElements.Count, nativeHotkeyBar.m_elementSpace) : 0f, 0f); } } } private static bool TryGetRectBounds(RectTransform transform, RectTransform parent, out float left, out float right, out float bottom, out float top, out float depth) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) left = float.PositiveInfinity; right = float.NegativeInfinity; bottom = float.PositiveInfinity; top = float.NegativeInfinity; depth = 0f; transform.GetWorldCorners(GuardianCorners); for (int i = 0; i < GuardianCorners.Length; i++) { Vector3 val = ((Transform)parent).InverseTransformPoint(GuardianCorners[i]); left = Mathf.Min(left, val.x); right = Mathf.Max(right, val.x); bottom = Mathf.Min(bottom, val.y); top = Mathf.Max(top, val.y); depth = val.z; } if (right > left) { return top > bottom; } return false; } private static void Refresh(bool force = false) { if ((!dirty && !force) || (Object)(object)SlotStateManager.CurrentPlayer == (Object)null || SlotStateManager.GearInventory == null || SlotStateManager.QuickInventory == null) { return; } Player currentPlayer = SlotStateManager.CurrentPlayer; if ((Object)(object)inventoryGui != (Object)null && (Object)(object)gearGrid != (Object)null && (Object)(object)quickGrid != (Object)null && InventoryGui.IsVisible()) { gearGrid.UpdateInventory(SlotStateManager.GearInventory, currentPlayer, GetDraggedItem()); quickGrid.UpdateInventory(SlotStateManager.QuickInventory, currentPlayer, GetDraggedItem()); ApplyDedicatedVisualLayout(gearGrid); DecorateGrid(gearGrid, isGear: true); DecorateGrid(quickGrid, isGear: false); SetDefaultGamepadElement(gearGrid); SetDefaultGamepadElement(quickGrid); if (!inventoryVisualsLogged) { inventoryVisualsLogged = true; IList list = ElementsField.GetValue(gearGrid) as IList; IList list2 = ElementsField.GetValue(quickGrid) as IList; GearSlotsPlugin.ModLog.LogInfo((object)($"Dedicated slot visuals created: gear={list?.Count ?? 0}, quick={list2?.Count ?? 0}, " + $"active={((Component)gearGrid).gameObject.activeInHierarchy}/{((Component)quickGrid).gameObject.activeInHierarchy}.")); } } RefreshQuickHud(currentPlayer); dirty = false; } private static ItemData? GetDraggedItem() { if (!((Object)(object)inventoryGui == (Object)null)) { object? value = DragItemField.GetValue(inventoryGui); return (ItemData?)((value is ItemData) ? value : null); } return null; } internal static void BeginHeldDrag(InventoryGrid sourceGrid, Vector2i sourcePosition, PointerEventData eventData) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventoryGui == (Object)null || (int)eventData.button != 0 || DragObjectField.GetValue(inventoryGui) is GameObject || ZInput.GetKey((KeyCode)308, true) || ZInput.GetKey((KeyCode)307, true) || ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true) || ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true)) { return; } Inventory inventory = sourceGrid.GetInventory(); if (SlotStateManager.IsAuxiliaryInventory(inventory)) { ItemData itemAt = inventory.GetItemAt(sourcePosition.x, sourcePosition.y); if (itemAt != null) { SetupDragItemMethod.Invoke(inventoryGui, new object[3] { itemAt, inventory, itemAt.m_stack }); } } } internal static bool EnsureSplitDialog(InventoryGrid sourceGrid, Vector2i sourcePosition, PointerEventData eventData) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Invalid comparison between Unknown and I4 if ((Object)(object)inventoryGui == (Object)null || !SlotStateManager.IsAuxiliaryInventory(sourceGrid.GetInventory())) { return false; } Inventory inventory = sourceGrid.GetInventory(); ItemData itemAt = inventory.GetItemAt(sourcePosition.x, sourcePosition.y); bool shiftHeld = ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true); if (itemAt == null || !AuxiliarySplitPolicy.ShouldOpen((int)eventData.button == 0, shiftHeld, itemAt.m_stack)) { return false; } if (!inventoryGui.m_splitDialog.IsActive) { OpenSplitDialog(inventoryGui, itemAt, inventory); } else { ((Component)inventoryGui.m_splitDialog).transform.SetAsLastSibling(); } return true; } internal static void CompleteHeldDrag(InventoryGrid sourceGrid, PointerEventData eventData) { if ((Object)(object)inventoryGui == (Object)null || !SlotStateManager.IsAuxiliaryInventory(sourceGrid.GetInventory()) || !(DragObjectField.GetValue(inventoryGui) is GameObject)) { return; } object? value = DragItemField.GetValue(inventoryGui); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val != null) { object? value2 = DragInventoryField.GetValue(inventoryGui); Inventory val2 = (Inventory)((value2 is Inventory) ? value2 : null); if (val2 != null && SlotStateManager.IsAuxiliaryInventory(val2) && !TryCompleteHeldDragToPlayerGrid(eventData) && !IsPointerOverInventoryMenu(eventData) && SlotTransferService.TryDropAtPlayer(val)) { PlayMoveEffect(inventoryGui); ClearDrag(inventoryGui); } } } private static bool TryCompleteHeldDragToPlayerGrid(PointerEventData eventData) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventoryGui == (Object)null) { return false; } InventoryGrid playerGrid = inventoryGui.m_playerGrid; if (!(ElementsField.GetValue(playerGrid) is IList list)) { return false; } int width = playerGrid.GetInventory().GetWidth(); Vector2i val2 = default(Vector2i); for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj != null) { Transform transform = ((Component)(InventoryElement)obj).gameObject.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val != null && RectTransformUtility.RectangleContainsScreenPoint(val, eventData.position, eventData.enterEventCamera ?? eventData.pressEventCamera)) { ((Vector2i)(ref val2))..ctor(i % width, i / width); ItemData itemAt = playerGrid.GetInventory().GetItemAt(val2.x, val2.y); playerGrid.m_onSelected?.Invoke(playerGrid, itemAt, val2, (Modifier)0); return true; } } } return false; } private static bool IsPointerOverInventoryMenu(PointerEventData eventData) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventoryGui == (Object)null || (Object)(object)EventSystem.current == (Object)null) { return false; } PointerRaycastResults.Clear(); EventSystem.current.RaycastAll(eventData, PointerRaycastResults); object? value = DragObjectField.GetValue(inventoryGui); object? obj = ((value is GameObject) ? value : null); Transform val = ((obj != null) ? ((GameObject)obj).transform : null); foreach (RaycastResult pointerRaycastResult in PointerRaycastResults) { RaycastResult current = pointerRaycastResult; if (!((Object)(object)((RaycastResult)(ref current)).gameObject == (Object)null) && (!((Object)(object)val != (Object)null) || !((RaycastResult)(ref current)).gameObject.transform.IsChildOf(val)) && ((RaycastResult)(ref current)).gameObject.transform.IsChildOf(((Component)inventoryGui).transform)) { return true; } } return false; } private static void DecorateGrid(InventoryGrid grid, bool isGear) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) if (!(ElementsField.GetValue(grid) is IList list)) { return; } for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj != null) { Image icon = ((InventoryElement)obj).m_icon; ItemData itemAt = grid.GetInventory().GetItemAt(i, 0); SlotKind slot = (isGear ? SlotRuleEngine.GetDedicatedSlotAtPosition(i) : ((SlotKind)(6 + i))); GameObject gameObject = ((Component)(InventoryElement)obj).gameObject; UIInputHandler componentInChildren = gameObject.GetComponentInChildren(); GameObject val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : gameObject); (val.GetComponent() ?? val.AddComponent()).Initialize(grid, new Vector2i(i, 0)); Transform obj2 = gameObject.transform.Find("binding"); TMP_Text val2 = ((obj2 != null) ? ((Component)obj2).GetComponent() : null); if ((Object)(object)val2 != (Object)null) { ConfigureShortcutLabel(val2); ((Behaviour)val2).enabled = !isGear; val2.text = (isGear ? string.Empty : GetQuickBinding(i)); } TMP_Text orCreateLabel = GetOrCreateLabel(obj, "GearSlots_EmptyLabel", (TextAlignmentOptions)514, 14f); ConfigureEmptySlotLabel(orCreateLabel); orCreateLabel.text = SlotDisplayName.For(slot); bool flag = (((Behaviour)orCreateLabel).enabled = itemAt == null && !GearSlotsPlugin.Settings.HideEmptyLabels.Value); ((Component)orCreateLabel).gameObject.SetActive(flag); if (flag) { orCreateLabel.transform.SetAsLastSibling(); } if (itemAt == null) { ((Behaviour)icon).enabled = false; } if (!SlotStateManager.IsSlotEnabled(slot)) { orCreateLabel.text = SlotDisplayName.For(slot) + " (Off)"; ((Behaviour)orCreateLabel).enabled = true; ((Component)orCreateLabel).gameObject.SetActive(true); orCreateLabel.transform.SetAsLastSibling(); ((Graphic)icon).color = new Color(0.55f, 0.35f, 0.35f, 0.32f); } } } } private static void ApplyDedicatedVisualLayout(InventoryGrid grid) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (!(ElementsField.GetValue(grid) is IList list) || list.Count < SlotRuleEngine.DedicatedSlots.Count) { return; } SetGridSize(grid, 2, 5, 24f); for (int i = 0; i < SlotRuleEngine.DedicatedSlots.Count; i++) { object obj = list[i]; if (obj != null) { RectTransform val = (RectTransform)((Component)(InventoryElement)obj).gameObject.transform; SlotKind dedicatedSlotAtPosition = SlotRuleEngine.GetDedicatedSlotAtPosition(i); val.anchoredPosition = new Vector2((float)DedicatedPanelLayout.GetColumn(dedicatedSlotAtPosition) * grid.m_elementSpace, (float)(-DedicatedPanelLayout.GetRow(dedicatedSlotAtPosition)) * grid.m_elementSpace); } } GetOrCreateSectionHeader(list[4], "GearSlots_UtilityHeader", "UTILITY", 0f, grid.m_elementSpace); GetOrCreateSectionHeader(list[0], "GearSlots_GearHeader", "GEAR", grid.m_elementSpace, grid.m_elementSpace); } private static TMP_Text GetOrCreateSectionHeader(object templateElement, string name, string text, float x, float width) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) RectTransform component = gearGridObject.GetComponent(); Transform val = ((Transform)component).Find(name); TMP_Text val2; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).GetComponent(); } else { val2 = Object.Instantiate(((InventoryElement)templateElement).m_amount, (Transform)(object)component); ((Object)val2).name = name; ((Graphic)val2).raycastTarget = false; val2.alignment = (TextAlignmentOptions)514; val2.fontSize = 15f; val2.fontStyle = (FontStyles)1; val2.enableAutoSizing = false; ((Graphic)val2).color = new Color(0.9f, 0.78f, 0.48f, 1f); RectTransform rectTransform = val2.rectTransform; rectTransform.anchorMin = new Vector2(0f, 1f); rectTransform.anchorMax = new Vector2(0f, 1f); rectTransform.pivot = new Vector2(0f, 1f); rectTransform.sizeDelta = new Vector2(width, 24f); rectTransform.anchoredPosition = new Vector2(x, 0f); } val2.text = text; ((Behaviour)val2).enabled = true; ((Component)val2).gameObject.SetActive(true); return val2; } private static TMP_Text GetOrCreateLabel(object element, string name, TextAlignmentOptions alignment, float fontSize) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = ((Component)(InventoryElement)element).gameObject; TMP_Text amount = ((InventoryElement)element).m_amount; Transform val = gameObject.transform.Find(name); if ((Object)(object)val != (Object)null) { return ((Component)val).GetComponent(); } TMP_Text obj = Object.Instantiate(amount, gameObject.transform); ((Object)obj).name = name; ((Graphic)obj).raycastTarget = false; obj.alignment = alignment; obj.fontSize = fontSize; obj.enableAutoSizing = false; ((Graphic)obj).color = new Color(0.95f, 0.82f, 0.52f, 1f); RectTransform rectTransform = obj.rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(3f, 3f); rectTransform.offsetMax = new Vector2(-3f, -3f); return obj; } private static void ConfigureEmptySlotLabel(TMP_Text label) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_008a: 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) ((Graphic)label).raycastTarget = false; label.alignment = (TextAlignmentOptions)514; label.textWrappingMode = (TextWrappingModes)0; label.overflowMode = (TextOverflowModes)0; label.enableAutoSizing = true; label.fontSizeMin = 9f; label.fontSizeMax = 14f; label.fontStyle = (FontStyles)1; ((Graphic)label).color = new Color(0.95f, 0.82f, 0.52f, 1f); RectTransform rectTransform = label.rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(3f, 3f); rectTransform.offsetMax = new Vector2(-3f, -3f); } private static void RefreshQuickHud(Player player) { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)quickHudRoot == (Object)null || SlotStateManager.QuickInventory == null || QuickHudElements.Count != 3) { return; } Inventory quickInventory = SlotStateManager.QuickInventory; for (int i = 0; i < QuickHudElements.Count; i++) { QuickHudElement quickHudElement = QuickHudElements[i]; ItemData itemAt = quickInventory.GetItemAt(i, 0); ConfigureShortcutLabel(quickHudElement.Binding); quickHudElement.Binding.text = GetQuickBinding(i); ((Component)quickHudElement.Binding).gameObject.SetActive(true); quickHudElement.Selection.SetActive(false); if (itemAt == null) { ((Component)quickHudElement.Icon).gameObject.SetActive(false); ((Component)quickHudElement.Durability).gameObject.SetActive(false); ((Component)quickHudElement.Amount).gameObject.SetActive(false); quickHudElement.Equipped.SetActive(false); quickHudElement.Queued.SetActive(false); if ((Object)(object)quickHudElement.Tooltip != (Object)null) { quickHudElement.Tooltip.m_topic = SlotDisplayName.For((SlotKind)(6 + i)); quickHudElement.Tooltip.m_text = string.Empty; } continue; } ((Component)quickHudElement.Icon).gameObject.SetActive(true); quickHudElement.Icon.sprite = itemAt.GetIcon(); ((Graphic)quickHudElement.Icon).color = Color.white; bool flag = itemAt.m_shared.m_useDurability && itemAt.m_durability < itemAt.GetMaxDurability(); ((Component)quickHudElement.Durability).gameObject.SetActive(flag); if (flag) { if (itemAt.m_durability <= 0f) { quickHudElement.Durability.SetValue(1f); quickHudElement.Durability.SetColor((Color)((Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : new Color(0f, 0f, 0f, 0f))); } else { quickHudElement.Durability.SetValue(itemAt.GetDurabilityPercentage()); quickHudElement.Durability.ResetColor(); } } quickHudElement.Equipped.SetActive(itemAt.m_equipped); quickHudElement.Queued.SetActive(player.IsEquipActionQueued(itemAt)); bool flag2 = itemAt.m_shared.m_maxStackSize > 1; ((Component)quickHudElement.Amount).gameObject.SetActive(flag2); if (flag2) { quickHudElement.Amount.text = $"{itemAt.m_stack} / {itemAt.m_shared.m_maxStackSize}"; } if ((Object)(object)quickHudElement.Tooltip != (Object)null) { quickHudElement.Tooltip.Set(itemAt.m_shared.m_name, itemAt.GetTooltip(-1), quickHudRoot, default(Vector2)); } } } private unsafe static string GetQuickBinding(int index) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut quickKey = GearSlotsPlugin.Settings.GetQuickKey(index); return ShortcutLabelFormatter.Format(((object)((KeyboardShortcut)(ref quickKey)).MainKey/*cast due to .constrained prefix*/).ToString(), ((KeyboardShortcut)(ref quickKey)).Modifiers.Select((KeyCode modifier) => ((object)(*(KeyCode*)(&modifier))/*cast due to .constrained prefix*/).ToString())); } private static void ConfigureShortcutLabel(TMP_Text binding) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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) binding.alignment = (TextAlignmentOptions)258; binding.textWrappingMode = (TextWrappingModes)0; binding.overflowMode = (TextOverflowModes)0; binding.enableAutoSizing = true; binding.fontSizeMin = 10f; binding.fontSizeMax = Mathf.Max(10f, binding.fontSize); RectTransform rectTransform = binding.rectTransform; rectTransform.anchorMin = new Vector2(0f, 1f); rectTransform.anchorMax = new Vector2(1f, 1f); rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.anchoredPosition = new Vector2(0f, -2f); rectTransform.sizeDelta = new Vector2(-6f, 22f); } private static void SetDefaultGamepadElement(InventoryGrid grid) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (ElementsField.GetValue(grid) is IList { Count: >0 } list && (Object)(object)grid.m_uiGroup != (Object)null) { object obj = list[0]; if (obj != null) { grid.m_uiGroup.m_defaultElement = ((Component)(InventoryElement)obj).gameObject; } } } private static void ClearDrag(InventoryGui gui) { SetupDragItemMethod.Invoke(gui, new object[3] { null, null, 1 }); } private static void PlayMoveEffect(InventoryGui gui) { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) gui.m_moveItemEffects.Create(((Component)gui).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } private static void OpenSplitDialog(InventoryGui gui, ItemData item, Inventory inventory) { if (item.m_stack > 1) { ShowSplitDialogMethod.Invoke(gui, new object[2] { item, inventory }); ((Component)gui.m_splitDialog).transform.SetAsLastSibling(); } else { SetupDragItemMethod.Invoke(gui, new object[3] { item, inventory, item.m_stack }); } } } internal sealed class AuxiliarySlotDragHandler : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler, IPointerUpHandler { private InventoryGrid? sourceGrid; private Vector2i sourcePosition; internal void Initialize(InventoryGrid grid, Vector2i position) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) sourceGrid = grid; sourcePosition = position; } public void OnBeginDrag(PointerEventData eventData) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourceGrid != (Object)null) { GearSlotsUi.BeginHeldDrag(sourceGrid, sourcePosition, eventData); } } public void OnDrag(PointerEventData eventData) { } public void OnEndDrag(PointerEventData eventData) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourceGrid != (Object)null && (int)eventData.button == 0) { GearSlotsUi.CompleteHeldDrag(sourceGrid, eventData); } } public void OnPointerUp(PointerEventData eventData) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourceGrid != (Object)null && (int)eventData.button == 0 && !GearSlotsUi.EnsureSplitDialog(sourceGrid, sourcePosition, eventData)) { GearSlotsUi.CompleteHeldDrag(sourceGrid, eventData); } } } } namespace GearSlots.Runtime { internal static class CharacterPreviewService { private static readonly MethodInfo SetupEquipmentMethod = AccessTools.Method(typeof(Humanoid), "SetupEquipment", (Type[])null, (Type[])null); private static readonly FieldInfo HelmetItemField = AccessTools.Field(typeof(Humanoid), "m_helmetItem"); private static readonly FieldInfo ChestItemField = AccessTools.Field(typeof(Humanoid), "m_chestItem"); private static readonly FieldInfo LegItemField = AccessTools.Field(typeof(Humanoid), "m_legItem"); private static readonly FieldInfo ShoulderItemField = AccessTools.Field(typeof(Humanoid), "m_shoulderItem"); private static readonly FieldInfo UtilityItemField = AccessTools.Field(typeof(Humanoid), "m_utilityItem"); private static readonly FieldInfo TrinketItemField = AccessTools.Field(typeof(Humanoid), "m_trinketItem"); internal static void Apply(Player previewPlayer) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Invalid comparison between Unknown and I4 //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Invalid comparison between Unknown and I4 if ((Object)(object)previewPlayer == (Object)null || !TryLoadGearInventory(previewPlayer, out Inventory gearInventory)) { return; } bool flag = false; flag |= ApplyItem(previewPlayer, gearInventory, SlotKind.Head, (ItemType)6, HelmetItemField); flag |= ApplyItem(previewPlayer, gearInventory, SlotKind.Chest, (ItemType)7, ChestItemField); flag |= ApplyItem(previewPlayer, gearInventory, SlotKind.Legs, (ItemType)11, LegItemField); flag |= ApplyItem(previewPlayer, gearInventory, SlotKind.Cape, (ItemType)17, ShoulderItemField); ItemData val = null; ItemData val2 = null; foreach (SlotKind utilitySlot in SlotRuleEngine.UtilitySlots) { if (GearSlotsPlugin.Settings.IsEnabled(utilitySlot)) { int dedicatedPosition = SlotRuleEngine.GetDedicatedPosition(utilitySlot); ItemData itemAt = gearInventory.GetItemAt(dedicatedPosition, 0); if (itemAt != null && (int)itemAt.m_shared.m_itemType == 18 && val == null) { val = itemAt; } else if (itemAt != null && (int)itemAt.m_shared.m_itemType == 24 && val2 == null) { val2 = itemAt; } } } flag |= ApplyItem(previewPlayer, val, UtilityItemField); if (flag | ApplyItem(previewPlayer, val2, TrinketItemField)) { SetupEquipmentMethod.Invoke(previewPlayer, Array.Empty()); } } private static bool TryLoadGearInventory(Player previewPlayer, out Inventory gearInventory) { gearInventory = CreateGearInventory(previewPlayer); Inventory quickInventory = CreateQuickInventory(previewPlayer); if (previewPlayer.m_customData.TryGetValue("com.jg224.gearslots.save.v1", out var value) && SlotPersistence.TryLoad(value, gearInventory, quickInventory, out long sequence, out string error)) { return true; } gearInventory = CreateGearInventory(previewPlayer); quickInventory = CreateQuickInventory(previewPlayer); if (previewPlayer.m_customData.TryGetValue("com.jg224.gearslots.save.backup.v1", out var value2)) { return SlotPersistence.TryLoad(value2, gearInventory, quickInventory, out sequence, out error); } return false; } private static Inventory CreateGearInventory(Player previewPlayer) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown return new Inventory("$gearslots_preview_gear", ((Humanoid)previewPlayer).GetInventory().GetBkg(), SlotRuleEngine.DedicatedSlots.Count, 1); } private static Inventory CreateQuickInventory(Player previewPlayer) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new Inventory("$gearslots_preview_quick", ((Humanoid)previewPlayer).GetInventory().GetBkg(), 3, 1); } private static bool ApplyItem(Player previewPlayer, Inventory gearInventory, SlotKind slot, ItemType expectedType, FieldInfo equipmentField) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!GearSlotsPlugin.Settings.IsEnabled(slot)) { return false; } int dedicatedPosition = SlotRuleEngine.GetDedicatedPosition(slot); ItemData itemAt = gearInventory.GetItemAt(dedicatedPosition, 0); if (itemAt != null && itemAt.m_shared.m_itemType == expectedType) { return ApplyItem(previewPlayer, itemAt, equipmentField); } return false; } private static bool ApplyItem(Player previewPlayer, ItemData? item, FieldInfo equipmentField) { if (item == null) { return false; } item.m_equipped = true; equipmentField.SetValue(previewPlayer, item); return true; } } internal static class NamedLoadouts { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__1_0; public static Func <>9__3_0; public static Func <>9__3_1; public static Func> <>9__3_2; public static Func <>9__3_3; public static Func <>9__3_4; public static Func <>9__3_5; public static Func <>9__3_6; internal void b__1_0(ConsoleEventArgs args) { try { if (args.Args.Length > 1 && args.Args[1] == "recovery") { GearSlotsRecoveryScreen.Open(); args.Context.AddString("Open your inventory to view GearSlots recovery."); return; } if (args.Args.Length > 1 && args.Args[1] == "returnall") { args.Context.AddString(ReturnAll()); return; } if (!SlotStateManager.IsReady) { throw new InvalidOperationException(SlotStateManager.RecoveryStatus); } Player currentPlayer = SlotStateManager.CurrentPlayer; currentPlayer.m_customData.TryGetValue("com.jg224.gearslots.loadouts.v1", out var value); Dictionary> dictionary = LoadoutCodec.Decode(value); if (args.Args.Length < 3 || args.Args[2] == "list") { args.Context.AddString("Loadouts: " + string.Join(", ", dictionary.Keys)); return; } if (args.Args[1] != "loadout") { throw new InvalidOperationException("Use gearslots loadout save/load/delete or gearslots recovery."); } string text = string.Join(" ", args.Args.Skip(3)).Trim(); if (!LoadoutCodec.ValidName(text)) { throw new InvalidOperationException("Use a loadout name of 1–32 letters, numbers, spaces, underscores or dashes."); } switch (args.Args[2]) { case "load": { if (!dictionary.TryGetValue(text, out var value2)) { throw new InvalidOperationException("Loadout not found."); } args.Context.AddString(Apply(value2) ? ("Loaded " + text + ".") : "Loadout failed; original inventory restored."); return; } case "save": { Dictionary dictionary2 = new Dictionary(); foreach (SlotKind value4 in Enum.GetValues(typeof(SlotKind))) { ItemData item = SlotStateManager.GetItem(value4); if (item != null) { dictionary2.Add(value4, SlotStateManager.EnsureIdentity(item)); } } dictionary[text] = dictionary2; break; } case "delete": if (!dictionary.Remove(text)) { throw new InvalidOperationException("Loadout not found."); } break; default: throw new InvalidOperationException("Use loadout save, load, delete or list."); } string value3 = LoadoutCodec.Encode(dictionary); currentPlayer.m_customData["com.jg224.gearslots.loadouts.v1"] = value3; SlotStateManager.MarkChanged(); args.Context.AddString("Updated loadout " + text + "."); } catch (Exception ex) { args.Context.AddString("GearSlots: " + ex.Message); } } internal Inventory b__3_0(Inventory inventory) { return inventory; } internal ItemData[] b__3_1(Inventory inventory) { return inventory.GetAllItems().ToArray(); } internal IEnumerable b__3_2(ItemData[] items) { return items; } internal ItemData b__3_3(ItemData item) { return item; } internal Vector2i b__3_4(ItemData item) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return item.m_gridPos; } internal string b__3_5(ItemData item) { return SlotStateManager.EnsureIdentity(item); } internal ItemData b__3_6(ItemData item) { return item; } } private const string StorageKey = "com.jg224.gearslots.loadouts.v1"; internal static void Register() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__1_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { try { if (args.Args.Length > 1 && args.Args[1] == "recovery") { GearSlotsRecoveryScreen.Open(); args.Context.AddString("Open your inventory to view GearSlots recovery."); } else if (args.Args.Length > 1 && args.Args[1] == "returnall") { args.Context.AddString(ReturnAll()); } else { if (!SlotStateManager.IsReady) { throw new InvalidOperationException(SlotStateManager.RecoveryStatus); } Player currentPlayer = SlotStateManager.CurrentPlayer; currentPlayer.m_customData.TryGetValue("com.jg224.gearslots.loadouts.v1", out var value); Dictionary> dictionary = LoadoutCodec.Decode(value); if (args.Args.Length < 3 || args.Args[2] == "list") { args.Context.AddString("Loadouts: " + string.Join(", ", dictionary.Keys)); } else { if (args.Args[1] != "loadout") { throw new InvalidOperationException("Use gearslots loadout save/load/delete or gearslots recovery."); } string text = string.Join(" ", args.Args.Skip(3)).Trim(); if (!LoadoutCodec.ValidName(text)) { throw new InvalidOperationException("Use a loadout name of 1–32 letters, numbers, spaces, underscores or dashes."); } switch (args.Args[2]) { case "load": { if (!dictionary.TryGetValue(text, out var value2)) { throw new InvalidOperationException("Loadout not found."); } args.Context.AddString(Apply(value2) ? ("Loaded " + text + ".") : "Loadout failed; original inventory restored."); return; } case "save": { Dictionary dictionary2 = new Dictionary(); foreach (SlotKind value4 in Enum.GetValues(typeof(SlotKind))) { ItemData item = SlotStateManager.GetItem(value4); if (item != null) { dictionary2.Add(value4, SlotStateManager.EnsureIdentity(item)); } } dictionary[text] = dictionary2; break; } case "delete": if (!dictionary.Remove(text)) { throw new InvalidOperationException("Loadout not found."); } break; default: throw new InvalidOperationException("Use loadout save, load, delete or list."); } string value3 = LoadoutCodec.Encode(dictionary); currentPlayer.m_customData["com.jg224.gearslots.loadouts.v1"] = value3; SlotStateManager.MarkChanged(); args.Context.AddString("Updated loadout " + text + "."); } } } catch (Exception ex) { args.Context.AddString("GearSlots: " + ex.Message); } }; <>c.<>9__1_0 = val; obj = (object)val; } new ConsoleCommand("gearslots", "loadout save/load/delete , loadout list, recovery, returnall", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } internal static string ReturnAll() { try { return Apply(new Dictionary()) ? "Returned every slot item to the main inventory." : "Return failed; original inventory restored."; } catch (Exception ex) { return ex.Message; } } private static bool Apply(IReadOnlyDictionary desired) { if (!SlotStateManager.IsReady || SlotStateManager.LoadoutMutation) { throw new InvalidOperationException(SlotStateManager.RecoveryStatus); } Player player = SlotStateManager.CurrentPlayer; if (((Character)player).IsDead() || ((Character)player).IsTeleporting()) { throw new InvalidOperationException("Wait until you are alive and teleportation has finished."); } Inventory[] inventories = (Inventory[])(object)new Inventory[3] { ((Humanoid)player).GetInventory(), SlotStateManager.GearInventory, SlotStateManager.QuickInventory }; Dictionary original = inventories.ToDictionary((Inventory inventory) => inventory, (Inventory inventory) => inventory.GetAllItems().ToArray()); ItemData[] all = original.Values.SelectMany((ItemData[] result2) => result2).ToArray(); Dictionary positions = all.ToDictionary((ItemData item) => item, (ItemData item) => item.m_gridPos); ItemData[] equipped = ((IEnumerable)all).Where((Func)((Humanoid)player).IsItemEquiped).ToArray(); Dictionary identities = all.ToDictionary((ItemData item) => SlotStateManager.EnsureIdentity(item), (ItemData item) => item, StringComparer.Ordinal); foreach (KeyValuePair item in desired) { if (!identities.TryGetValue(item.Value, out var value) || !SlotStateManager.IsSlotEnabled(item.Key) || !SlotRuleAdapter.Accepts(item.Key, value)) { throw new InvalidOperationException("A saved item is missing, its slot is disabled, or it no longer fits."); } if (value.m_shared.m_questItem && !SlotRuleAdapter.IsUtilityKey(value)) { throw new InvalidOperationException("Quest items cannot be assigned to loadout slots."); } } int width = inventories[0].GetWidth(); LoadoutItem[] items = identities.Select((KeyValuePair pair) => new LoadoutItem(pair.Key, inventories[0].ContainsItem(pair.Value) ? (pair.Value.m_gridPos.y * width + pair.Value.m_gridPos.x) : (-1))).ToArray(); LoadoutPlan plan = LoadoutPlanner.Plan(items, desired, width * inventories[0].GetHeight()); MethodInfo changed = AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); if (changed == null) { throw new InvalidOperationException("Inventory notification API is unavailable."); } SlotStateManager.BeginMutation(); SlotStateManager.LoadoutMutation = true; try { bool result = LoadoutTransaction.Execute(delegate { //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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) ItemData[] array = all; foreach (ItemData val in array) { ((Humanoid)player).RemoveEquipAction(val); if (((Humanoid)player).IsItemEquiped(val)) { ((Humanoid)player).UnequipItem(val, false); } } Inventory[] array2 = inventories; for (int i = 0; i < array2.Length; i++) { array2[i].GetAllItems().Clear(); } foreach (KeyValuePair mainCell in plan.MainCells) { ItemData val2 = identities[mainCell.Key]; val2.m_gridPos = new Vector2i(mainCell.Value % width, mainCell.Value / width); inventories[0].GetAllItems().Add(val2); } foreach (KeyValuePair slot in plan.Slots) { ItemData val3 = identities[slot.Key]; val3.m_gridPos = SlotStateManager.GetPosition(slot.Value); SlotStateManager.GetInventory(slot.Value).GetAllItems().Add(val3); } array2 = inventories; foreach (Inventory obj in array2) { changed.Invoke(obj, new object[2] { false, false }); } foreach (ItemData item2 in equipped.Where((ItemData item) => inventories[0].ContainsItem(item))) { ((Humanoid)player).EquipItem(item2, false); } SlotStateManager.SynchronizeEquipment(); }, delegate { //IL_0099: 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) ItemData[] array = all; foreach (ItemData val in array) { ((Humanoid)player).RemoveEquipAction(val); if (((Humanoid)player).IsItemEquiped(val)) { ((Humanoid)player).UnequipItem(val, false); } } Inventory[] array2 = inventories; foreach (Inventory val2 in array2) { val2.GetAllItems().Clear(); val2.GetAllItems().AddRange(original[val2]); } array = all; foreach (ItemData val3 in array) { val3.m_gridPos = positions[val3]; } array2 = inventories; foreach (Inventory obj in array2) { changed.Invoke(obj, new object[2] { false, false }); } array = equipped; foreach (ItemData val4 in array) { ((Humanoid)player).EquipItem(val4, false); } SlotStateManager.SynchronizeEquipment(); }); SlotStateManager.MarkChanged(); return result; } catch (AggregateException ex) { SlotStateManager.BlockForRecovery("Loadout rollback could not finish: " + ex.Message + ". Existing character payloads are preserved."); throw; } finally { SlotStateManager.LoadoutMutation = false; SlotStateManager.EndMutation(); } } } internal static class ProtectedUpgradeService { internal static void EnsureOriginalRecovered(ProtectedUpgradeState state) { //IL_0012: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = SlotStateManager.GetInventory(state.Slot); Vector2i position = SlotStateManager.GetPosition(state.Slot); if (inventory != null && inventory.GetItemAt(position.x, position.y) == null) { RestoreOriginal(inventory, state.OriginalItem, position); } } internal static ItemData? CreateUpgradedItem(ProtectedUpgradeState state, int stack, int quality, int variant, long crafterId, string crafterName, bool cheated, bool pickedUp) { //IL_0012: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = SlotStateManager.GetInventory(state.Slot); Vector2i position = SlotStateManager.GetPosition(state.Slot); ItemData originalItem = state.OriginalItem; if (inventory == null) { return null; } SlotStateManager.BeginMutation(); try { ItemData itemAt = inventory.GetItemAt(position.x, position.y); if (itemAt != null && itemAt != originalItem) { RestoreOriginal(inventory, originalItem, position); return null; } if (itemAt == originalItem) { inventory.RemoveItem(originalItem); } ItemData val = originalItem.Clone(); val.m_stack = stack; val.m_quality = quality; val.m_variant = variant; val.m_crafterID = crafterId; val.m_crafterName = crafterName; val.m_worldLevel = Game.m_worldLevel; val.m_pickedUp = pickedUp; val.m_cheated = cheated; val.m_equipped = false; val.m_durability = val.GetMaxDurability(); val.m_gridPos = position; if (!inventory.AddItem(val, position)) { RestoreOriginal(inventory, originalItem, position); return null; } SlotStateManager.EnsureIdentity(val); SlotStateManager.SynchronizeEquipment(); return val; } catch (Exception ex) { GearSlotsPlugin.ModLog.LogError((object)("Could not return upgraded gear to its protected slot: " + ex)); RestoreOriginal(inventory, originalItem, position); return null; } finally { SlotStateManager.EndMutation(); } } private static void RestoreOriginal(Inventory destination, ItemData original, Vector2i position) { //IL_000a: 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_001f: Unknown result type (might be due to invalid IL or missing references) if (!destination.ContainsItem(original) && destination.GetItemAt(position.x, position.y) == null) { destination.AddItem(original, position); } SlotStateManager.SynchronizeEquipment(); } } internal static class SlotPersistence { internal const string CurrentKey = "com.jg224.gearslots.save.v1"; internal const string BackupKey = "com.jg224.gearslots.save.backup.v1"; internal static string Serialize(long sequence, Inventory gearInventory, Inventory quickInventory) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown ZPackage val = new ZPackage(); gearInventory.Save(val); ZPackage val2 = new ZPackage(); quickInventory.Save(val2); return SlotPayloadCodec.Encode(new SlotSaveEnvelope(sequence, Guid.NewGuid(), val.GetArray(), val2.GetArray())); } internal static bool TryLoad(string payload, Inventory gearInventory, Inventory quickInventory, out long sequence, out string error) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown sequence = 0L; if (!SlotPayloadCodec.TryDecode(payload, out SlotSaveEnvelope envelope, out error) || envelope == null) { return false; } try { Inventory val = new Inventory("GearSlots validation", gearInventory.GetBkg(), gearInventory.GetWidth(), gearInventory.GetHeight()); Inventory val2 = new Inventory("GearSlots validation", quickInventory.GetBkg(), quickInventory.GetWidth(), quickInventory.GetHeight()); val.Load(new ZPackage(envelope.GearInventory)); val2.Load(new ZPackage(envelope.QuickInventory)); gearInventory.GetAllItems().Clear(); quickInventory.GetAllItems().Clear(); gearInventory.GetAllItems().AddRange(val.GetAllItems()); quickInventory.GetAllItems().AddRange(val2.GetAllItems()); AccessTools.Method(typeof(Inventory), "UpdateTotalWeight", (Type[])null, (Type[])null).Invoke(gearInventory, Array.Empty()); AccessTools.Method(typeof(Inventory), "UpdateTotalWeight", (Type[])null, (Type[])null).Invoke(quickInventory, Array.Empty()); sequence = envelope.Sequence; return true; } catch (Exception ex) { error = "Valheim could not restore the saved slot inventories: " + ex.Message; return false; } } } internal static class SlotRuleAdapter { internal static bool Accepts(SlotKind slot, ItemData item) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return SlotRuleEngine.Accepts(slot, ToCategory(item.m_shared.m_itemType), !string.IsNullOrEmpty(item.m_shared.m_ammoType), item.IsEquipable(), IsUtilityKey(item)); } internal static bool TryGetDedicatedSlot(ItemData item, out SlotKind slot) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_0015: 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_0035: Expected I4, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 ItemType itemType = item.m_shared.m_itemType; if ((int)itemType <= 17) { if ((int)itemType != 2) { switch (itemType - 6) { default: if ((int)itemType != 17) { goto IL_0082; } slot = SlotKind.Cape; return true; case 0: slot = SlotKind.Head; return true; case 1: slot = SlotKind.Chest; return true; case 5: slot = SlotKind.Legs; return true; case 3: break; case 2: case 4: goto IL_0082; } goto IL_0066; } if (!string.IsNullOrEmpty(item.m_shared.m_ammoType)) { slot = SlotKind.Ammo; return true; } goto IL_0082; } if ((int)itemType != 18) { if ((int)itemType == 23) { goto IL_0066; } if ((int)itemType != 24) { goto IL_0082; } } slot = SlotKind.Utility; return true; IL_0066: slot = SlotKind.Ammo; return true; IL_0082: slot = SlotKind.Head; return false; } internal static bool IsUtilityKey(ItemData item) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)item.m_shared.m_itemType == 16) { if (!(item.m_shared.m_name == "$item_cryptkey")) { if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name == "CryptKey"; } return false; } return true; } return false; } internal static ItemCategory ToCategory(ItemType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected I4, but got Unknown switch (type - 1) { case 0: return ItemCategory.Material; case 1: return ItemCategory.Consumable; case 2: case 3: case 13: case 19: case 21: return ItemCategory.Weapon; case 4: return ItemCategory.Shield; case 5: return ItemCategory.Helmet; case 6: return ItemCategory.Chest; case 8: return ItemCategory.Ammo; case 9: return ItemCategory.Customization; case 10: return ItemCategory.Legs; case 12: return ItemCategory.Trophy; case 14: return ItemCategory.Torch; case 15: return ItemCategory.Misc; case 16: return ItemCategory.Shoulder; case 17: return ItemCategory.Utility; case 18: return ItemCategory.Tool; case 20: return ItemCategory.Fish; case 22: return ItemCategory.AmmoNonEquipable; case 23: return ItemCategory.Trinket; default: return ItemCategory.None; } } } internal static class SlotStateManager { private sealed class MainInventoryRecoveryItem { internal ItemData Item { get; } internal string EncodedOrigin { get; } internal MainInventoryOrigin Origin { get; } internal MainInventoryRecoveryItem(ItemData item, string encodedOrigin, MainInventoryOrigin origin) { Item = item; EncodedOrigin = encodedOrigin; Origin = origin; } } private sealed class AutoStackTarget { internal Inventory Inventory { get; } internal ItemData Item { get; } internal AutoStackTarget(Inventory inventory, ItemData item) { Inventory = inventory; Item = item; } } internal const string ItemIdentityKey = "com.jg224.gearslots.item-id"; internal const string TombstoneOriginKey = "com.jg224.gearslots.tombstone-origin"; internal const string MainInventoryOriginKey = "com.jg224.gearslots.main-inventory-origin"; private static readonly TransferGate TransferGate = new TransferGate(); private static readonly MethodInfo SetupEquipmentMethod = AccessTools.Method(typeof(Humanoid), "SetupEquipment", (Type[])null, (Type[])null); private static readonly MethodInfo QueueEquipActionMethod = AccessTools.Method(typeof(Player), "QueueEquipAction", new Type[1] { typeof(ItemData) }, (Type[])null); private static readonly MethodInfo QueueUnequipActionMethod = AccessTools.Method(typeof(Player), "QueueUnequipAction", new Type[1] { typeof(ItemData) }, (Type[])null); private static readonly FieldInfo HelmetItemField = AccessTools.Field(typeof(Humanoid), "m_helmetItem"); private static readonly FieldInfo ChestItemField = AccessTools.Field(typeof(Humanoid), "m_chestItem"); private static readonly FieldInfo LegItemField = AccessTools.Field(typeof(Humanoid), "m_legItem"); private static readonly FieldInfo ShoulderItemField = AccessTools.Field(typeof(Humanoid), "m_shoulderItem"); private static readonly FieldInfo UtilityItemField = AccessTools.Field(typeof(Humanoid), "m_utilityItem"); private static readonly FieldInfo TrinketItemField = AccessTools.Field(typeof(Humanoid), "m_trinketItem"); private static readonly List AdditionalEquippedUtilities = new List(); private static readonly List DesiredAdditionalUtilities = new List(); private static readonly HashSet PendingAnimatedEquipment = new HashSet(); private static Player? player; private static Inventory? gearInventory; private static Inventory? quickInventory; private static long saveSequence; private static bool suppressChanges; private static bool configurationDirty = true; private static bool stateDirty; private static int mutationDepth; private static bool recoveryBlocked; private static bool payloadRecoveryOnly; private static float nextEvacuationRetry; internal static bool LoadoutMutation { get; set; } internal static string RecoveryStatus { get; private set; } = "Slot payload is healthy."; internal static bool RecoveryBlocked => recoveryBlocked; internal static bool CanRetryRecovery { get { if (recoveryBlocked) { return payloadRecoveryOnly; } return false; } } internal static Player? CurrentPlayer => player; internal static Inventory? GearInventory => gearInventory; internal static Inventory? QuickInventory => quickInventory; internal static bool IsReady { get { if ((Object)(object)player != (Object)null && gearInventory != null && quickInventory != null) { return !recoveryBlocked; } return false; } } internal static void Initialize() { configurationDirty = true; } internal static void Shutdown() { Persist(); Detach(); } internal static void Tick() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } if (player != localPlayer) { Attach(localPlayer); } if (IsReady) { if (configurationDirty && Time.unscaledTime >= nextEvacuationRetry) { configurationDirty = false; EvacuateDisabledSlots(); nextEvacuationRetry = Time.unscaledTime + 2f; GearSlotsUi.ApplyConfiguration(); } RecoverTaggedItemsFromMainInventory(); SynchronizeEquipment(); HandleQuickSlotInput(); GearSlotsUi.Tick(); } } internal static void NotifyConfigurationChanged() { configurationDirty = true; } internal static void ReloadAfterPlayerLoad(Player loadedPlayer) { if (!((Object)(object)loadedPlayer != (Object)(object)Player.m_localPlayer)) { Attach(loadedPlayer, forceReload: true); } } internal static void PersistBeforePlayerSave(Player savingPlayer) { if ((Object)(object)savingPlayer == (Object)(object)Player.m_localPlayer) { if (player != savingPlayer) { Attach(savingPlayer); } Persist(); } } internal static bool IsMainInventory(Inventory inventory) { if ((Object)(object)player != (Object)null) { return ((Humanoid)player).GetInventory() == inventory; } return false; } internal static bool IsAuxiliaryInventory(Inventory inventory) { if (inventory != gearInventory) { return inventory == quickInventory; } return true; } internal static bool ContainsAuxiliaryItem(ItemData item) { Inventory? obj = gearInventory; if (obj == null || !obj.ContainsItem(item)) { Inventory? obj2 = quickInventory; if (obj2 == null) { return false; } return obj2.ContainsItem(item); } return true; } internal static IReadOnlyList GetAdditionalEquippedUtilities() { return AdditionalEquippedUtilities; } internal static bool IsAdditionalUtilityItem(ItemData item) { if (TryGetSlot(item, out var slot) && IsAdditionalUtilitySlot(slot)) { return item.m_equipped; } return false; } internal static Inventory? FindAuxiliaryInventory(ItemData item) { Inventory? obj = gearInventory; if (obj != null && obj.ContainsItem(item)) { return gearInventory; } Inventory? obj2 = quickInventory; if (obj2 == null || !obj2.ContainsItem(item)) { return null; } return quickInventory; } internal static bool TryGetSlot(Inventory inventory, Vector2i position, out SlotKind slot) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (inventory == gearInventory && position.y == 0 && position.x >= 0 && position.x < SlotRuleEngine.DedicatedSlots.Count) { slot = SlotRuleEngine.GetDedicatedSlotAtPosition(position.x); return true; } if (inventory == quickInventory && position.y == 0 && position.x >= 0 && position.x <= 2) { slot = (SlotKind)(6 + position.x); return true; } slot = SlotKind.Head; return false; } internal static bool TryGetSlot(ItemData item, out SlotKind slot) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) slot = SlotKind.Head; Inventory val = FindAuxiliaryInventory(item); if (val != null) { return TryGetSlot(val, item.m_gridPos, out slot); } return false; } internal static Inventory? GetInventory(SlotKind slot) { if (!SlotRuleEngine.IsDedicated(slot)) { return quickInventory; } return gearInventory; } internal static Vector2i GetPosition(SlotKind slot) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!SlotRuleEngine.IsDedicated(slot)) { return new Vector2i((int)(slot - 6), 0); } return new Vector2i(SlotRuleEngine.GetDedicatedPosition(slot), 0); } internal static ItemData? GetItem(SlotKind slot) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Inventory? inventory = GetInventory(slot); if (inventory == null) { return null; } return inventory.GetItemAt(GetPosition(slot).x, 0); } internal static bool IsSlotEnabled(SlotKind slot) { return GearSlotsPlugin.Settings.IsEnabled(slot); } internal static string EnsureIdentity(ItemData item) { if (!item.m_customData.TryGetValue("com.jg224.gearslots.item-id", out var value) || string.IsNullOrWhiteSpace(value)) { value = Guid.NewGuid().ToString("N"); item.m_customData["com.jg224.gearslots.item-id"] = value; } return value; } internal static bool TryEnterTransfer(ItemData item, out string identity) { identity = EnsureIdentity(item); if (recoveryBlocked || LoadoutMutation) { return false; } return TransferGate.TryEnter(identity); } internal static void ExitTransfer(string identity) { TransferGate.Exit(identity); } internal static void BeginMutation() { mutationDepth++; } internal static void EndMutation() { if (mutationDepth > 0) { mutationDepth--; } if (mutationDepth == 0 && stateDirty) { Persist(); } } internal static void MarkChanged() { stateDirty = true; GearSlotsUi.MarkDirty(); if (mutationDepth == 0) { Persist(); } } internal static bool TryRebindCompletedEquipment(SlotKind slot, ItemData originalItem, ItemData protectedItem) { if ((Object)(object)player == (Object)null || originalItem == protectedItem) { return false; } FieldInfo fieldInfo = slot switch { SlotKind.Head => HelmetItemField, SlotKind.Chest => ChestItemField, SlotKind.Legs => LegItemField, SlotKind.Cape => ShoulderItemField, _ => null, }; if (fieldInfo == null || fieldInfo.GetValue(player) != originalItem) { return false; } fieldInfo.SetValue(player, protectedItem); originalItem.m_equipped = false; protectedItem.m_equipped = true; PendingAnimatedEquipment.Remove(originalItem); PendingAnimatedEquipment.Remove(protectedItem); return true; } internal static void QueueEquipmentAfterTransfer(SlotKind slot, ItemData item, bool completedEquipWasPreserved = false) { if (!((Object)(object)player == (Object)null) && item.IsEquipable() && EquipmentActionPolicy.ShouldQueueEquipAfterTransfer(SlotRuleEngine.UsesStandardEquipQueue(slot), completedEquipWasPreserved, ((Humanoid)player).IsItemEquiped(item))) { PendingAnimatedEquipment.Add(item); if (!player.IsEquipActionQueued(item)) { QueueEquipActionMethod.Invoke(player, new object[1] { item }); } } } internal static void QueueUnequipAfterTransfer(ItemData item) { if (!((Object)(object)player == (Object)null) && ((Humanoid)player).IsItemEquiped(item) && !player.IsEquipActionQueued(item)) { QueueUnequipActionMethod.Invoke(player, new object[1] { item }); } } internal static ItemData? GetPreferredAmmo(string ammoType, string? prefabName) { ItemData item = GetItem(SlotKind.Ammo); if (item == null || !IsSlotEnabled(SlotKind.Ammo) || item.m_shared.m_ammoType != ammoType) { return null; } if (prefabName != null && ((Object)item.m_dropPrefab).name != prefabName) { return null; } return item; } internal static int CountQuickItems(string? name, int quality, bool matchWorldLevel) { if (quickInventory == null) { return 0; } int num = 0; foreach (ItemData allItem in quickInventory.GetAllItems()) { if ((name == null || allItem.m_shared.m_name == name) && (quality < 0 || allItem.m_quality == quality) && (!matchWorldLevel || allItem.m_worldLevel >= Game.m_worldLevel)) { num += allItem.m_stack; } } return num; } internal static bool HasDedicatedUtilityKey(string name, bool matchWorldLevel) { if (gearInventory == null) { return false; } foreach (ItemData allItem in gearInventory.GetAllItems()) { if (allItem.m_shared.m_name == name && SlotRuleAdapter.IsUtilityKey(allItem) && (!matchWorldLevel || allItem.m_worldLevel >= Game.m_worldLevel) && TryGetSlot(allItem, out var slot) && IsSlotEnabled(slot)) { return true; } } return false; } internal static int RemoveQuickItems(string name, int amount, int quality, bool matchWorldLevel) { if (quickInventory == null || amount <= 0) { return 0; } int num = 0; BeginMutation(); try { foreach (ItemData item in quickInventory.GetAllItems().ToList()) { if (!(item.m_shared.m_name != name) && (quality < 0 || item.m_quality == quality) && (!matchWorldLevel || item.m_worldLevel >= Game.m_worldLevel)) { int num2 = Math.Min(item.m_stack, amount - num); if (num2 > 0 && quickInventory.RemoveItem(item, num2)) { num += num2; } if (num >= amount) { break; } } } } finally { EndMutation(); } return num; } internal static void AddRepairCandidates(List candidates) { if (gearInventory == null) { return; } foreach (ItemData allItem in gearInventory.GetAllItems()) { if (RepairRuleEngine.IsCandidate(allItem.m_shared.m_useDurability, allItem.m_durability, allItem.GetMaxDurability()) && !candidates.Contains(allItem)) { candidates.Add(allItem); } } } internal static void AddUpgradeCandidates(string name, List candidates) { if (gearInventory == null) { return; } foreach (ItemData allItem in gearInventory.GetAllItems()) { if (allItem.m_shared.m_name == name && allItem.m_worldLevel >= Game.m_worldLevel && TryGetSlot(allItem, out var slot) && IsSlotEnabled(slot) && !candidates.Contains(allItem)) { candidates.Add(allItem); } } } internal static bool AuxiliaryInventoriesAreTeleportable(bool allowAllItems) { Inventory? obj = gearInventory; if (obj == null || obj.IsTeleportable(allowAllItems)) { Inventory? obj2 = quickInventory; if (obj2 == null) { return true; } return obj2.IsTeleportable(allowAllItems); } return false; } internal static int GetExistingQuickStackCapacity(ItemData incoming, int? incomingWorldLevel = null) { if (incoming.m_stack <= 0 || incoming.m_shared.m_maxStackSize <= 1) { return 0; } return GetAutoStackTargets(incoming, incomingWorldLevel).Sum((AutoStackTarget target) => Math.Max(0, target.Item.m_shared.m_maxStackSize - target.Item.m_stack)); } internal static int GetRegularInventoryCapacity(Inventory inventory, ItemData incoming, int? incomingWorldLevel = null) { int num = (from item in inventory.GetAllItems() where CanStackIncoming(item, incoming, incomingWorldLevel) select item).Sum((ItemData item) => Math.Max(0, item.m_shared.m_maxStackSize - item.m_stack)); int num2 = Math.Max(0, inventory.GetWidth() * inventory.GetHeight() - inventory.GetAllItems().Count); return num + num2 * incoming.m_shared.m_maxStackSize; } internal static int StackIncomingIntoExistingQuickSlots(ItemData incoming) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) List list = GetAutoStackTargets(incoming).ToList(); if (ExistingStackPlanner.GetTransferAmount(incoming.m_stack, list.Select((AutoStackTarget target) => target.Item.m_shared.m_maxStackSize - target.Item.m_stack)) <= 0 || list.Count == 0) { return 0; } int num = 0; BeginMutation(); try { foreach (AutoStackTarget item in list) { int val = item.Item.m_shared.m_maxStackSize - item.Item.m_stack; int num2 = Math.Min(incoming.m_stack, Math.Max(0, val)); if (num2 > 0) { int stack = item.Item.m_stack; ItemData val2 = incoming.Clone(); val2.m_stack = num2; item.Inventory.AddItem(val2, item.Item.m_gridPos); int num3 = item.Item.m_stack - stack; incoming.m_stack = Math.Max(0, incoming.m_stack - num3); num += num3; if (incoming.m_stack <= 0) { break; } } } return num; } finally { EndMutation(); } } private static IEnumerable GetAutoStackTargets(ItemData incoming, int? incomingWorldLevel = null) { ItemData item = GetItem(SlotKind.Ammo); if (gearInventory != null && item != null && IsSlotEnabled(SlotKind.Ammo) && SlotRuleAdapter.Accepts(SlotKind.Ammo, incoming) && CanStackIncoming(item, incoming, incomingWorldLevel)) { yield return new AutoStackTarget(gearInventory, item); } if (quickInventory == null) { yield break; } foreach (ItemData item2 in from val in quickInventory.GetAllItems() where CanStackIncoming(val, incoming, incomingWorldLevel) orderby val.m_gridPos.x select val) { yield return new AutoStackTarget(quickInventory, item2); } } private static bool CanStackIncoming(ItemData existing, ItemData incoming, int? incomingWorldLevel = null) { if (existing.m_shared.m_name == incoming.m_shared.m_name && existing.m_quality == incoming.m_quality && existing.m_worldLevel == (incomingWorldLevel ?? incoming.m_worldLevel)) { return existing.m_stack < existing.m_shared.m_maxStackSize; } return false; } internal static int RecoverFromInventory(Inventory source) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00d7: Unknown result type (might be due to invalid IL or missing references) if (!IsReady || source == gearInventory || source == quickInventory) { return 0; } int num = 0; BeginMutation(); try { foreach (ItemData item in source.GetAllItems().ToList()) { if (!item.m_customData.TryGetValue("com.jg224.gearslots.tombstone-origin", out var value) || !Enum.TryParse(value, out var result)) { continue; } Inventory inventory = GetInventory(result); Vector2i position = GetPosition(result); if (inventory == null || !IsSlotEnabled(result) || inventory.GetItemAt(position.x, position.y) != null || !SlotRuleAdapter.Accepts(result, item)) { item.m_customData.Remove("com.jg224.gearslots.tombstone-origin"); continue; } item.m_customData.Remove("com.jg224.gearslots.tombstone-origin"); if (inventory.MoveItemToThis(source, item, item.m_stack, position.x, position.y)) { EnsureIdentity(item); num++; } else { item.m_customData["com.jg224.gearslots.tombstone-origin"] = value; } } if (!IsMainInventory(source)) { num += RecoverMainInventoryPositions(source); } } finally { EndMutation(); } if (num > 0) { SynchronizeEquipment(); } return num; } private static int RecoverMainInventoryPositions(Inventory source) { if ((Object)(object)player == (Object)null) { return 0; } Inventory inventory = ((Humanoid)player).GetInventory(); string value; MainInventoryOrigin origin; List list = (from item in source.GetAllItems() select (!item.m_customData.TryGetValue("com.jg224.gearslots.main-inventory-origin", out value) || !MainInventoryOriginCodec.TryDecode(value, out origin)) ? null : new MainInventoryRecoveryItem(item, value, origin) into candidate where candidate != null select candidate).Cast().ToList(); if (list.Count == 0) { return 0; } int width = inventory.GetWidth(); int height = inventory.GetHeight(); List occupiedCells = (from item in inventory.GetAllItems() select item.m_gridPos.y * width + item.m_gridPos.x).ToList(); IReadOnlyList readOnlyList = MainInventoryRecoveryPlanner.Plan(list.Select((MainInventoryRecoveryItem candidate) => candidate.Origin).ToList(), width, height, occupiedCells); int num = 0; foreach (MainInventoryRecoveryStep item in readOnlyList) { MainInventoryRecoveryItem mainInventoryRecoveryItem = list[item.CandidateIndex]; if (source.ContainsItem(mainInventoryRecoveryItem.Item)) { MainInventoryRecoveryMode mainInventoryRecoveryMode = item.Mode; if (mainInventoryRecoveryMode == MainInventoryRecoveryMode.ExactSlot && inventory.GetItemAt(mainInventoryRecoveryItem.Origin.X, mainInventoryRecoveryItem.Origin.Y) != null) { mainInventoryRecoveryMode = MainInventoryRecoveryMode.FirstAvailable; } num += MoveRecoveredMainItem(source, inventory, mainInventoryRecoveryItem, mainInventoryRecoveryMode); } } return num; } private static int MoveRecoveredMainItem(Inventory source, Inventory main, MainInventoryRecoveryItem candidate, MainInventoryRecoveryMode mode) { ItemData item = candidate.Item; int stack = item.m_stack; if (mode == MainInventoryRecoveryMode.FirstAvailable && GetRegularInventoryCapacity(main, item) < stack) { return 0; } item.m_customData.Remove("com.jg224.gearslots.main-inventory-origin"); if (mode == MainInventoryRecoveryMode.ExactSlot) { main.MoveItemToThis(source, item, stack, candidate.Origin.X, candidate.Origin.Y); } else { main.MoveItemToThis(source, item); } int num = (source.ContainsItem(item) ? item.m_stack : 0); if (num > 0) { item.m_customData["com.jg224.gearslots.main-inventory-origin"] = candidate.EncodedOrigin; } return (stack - num > 0) ? 1 : 0; } internal static void RouteEquippedItem(ItemData item) { if (!IsReady || (Object)(object)player == (Object)null || !((Humanoid)player).GetInventory().GetAllItems().Contains(item) || !SlotRuleAdapter.TryGetDedicatedSlot(item, out var destination)) { return; } if (destination == SlotKind.Utility) { if (!TryFindUtilityDestination(out destination)) { return; } } else if (!IsSlotEnabled(destination)) { return; } SlotTransferService.TryPlaceInSlot(((Humanoid)player).GetInventory(), item, item.m_stack, destination, showMessage: false); } internal static void Persist() { if (!IsReady || (Object)(object)player == (Object)null || gearInventory == null || quickInventory == null || suppressChanges) { return; } try { ValidateDuplicateIdentities(); string value = SlotPersistence.Serialize(++saveSequence, gearInventory, quickInventory); if (player.m_customData.TryGetValue("com.jg224.gearslots.save.v1", out var value2) && SlotPayloadCodec.TryDecode(value2, out SlotSaveEnvelope _, out string _)) { player.m_customData["com.jg224.gearslots.save.backup.v1"] = value2; } player.m_customData["com.jg224.gearslots.save.v1"] = value; stateDirty = false; } catch (Exception ex) { GearSlotsPlugin.ModLog.LogError((object)("Could not update the in-memory GearSlots character payload: " + ex)); } } private static void Attach(Player localPlayer, bool forceReload = false) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown if (player == localPlayer && !forceReload) { return; } if (player != localPlayer) { Detach(); player = localPlayer; } suppressChanges = true; try { gearInventory = new Inventory("$gearslots_gear", ((Humanoid)localPlayer).GetInventory().GetBkg(), SlotRuleEngine.DedicatedSlots.Count, 1); quickInventory = new Inventory("$gearslots_quick", ((Humanoid)localPlayer).GetInventory().GetBkg(), 3, 1); Inventory? obj = gearInventory; obj.m_onChanged = (Action)Delegate.Combine(obj.m_onChanged, new Action(OnAuxiliaryInventoryChanged)); Inventory? obj2 = quickInventory; obj2.m_onChanged = (Action)Delegate.Combine(obj2.m_onChanged, new Action(OnAuxiliaryInventoryChanged)); saveSequence = 0L; recoveryBlocked = false; payloadRecoveryOnly = false; LoadFromCharacterData(localPlayer); if (!recoveryBlocked) { NormalizeLoadedItems(); } } finally { suppressChanges = false; } stateDirty = true; configurationDirty = true; GearSlotsUi.BindInventories(); Persist(); } private static void Detach() { PendingAnimatedEquipment.Clear(); GearSlotsUi.UnbindInventories(); if (gearInventory != null) { Inventory? obj = gearInventory; obj.m_onChanged = (Action)Delegate.Remove(obj.m_onChanged, new Action(OnAuxiliaryInventoryChanged)); } if (quickInventory != null) { Inventory? obj2 = quickInventory; obj2.m_onChanged = (Action)Delegate.Remove(obj2.m_onChanged, new Action(OnAuxiliaryInventoryChanged)); } player = null; gearInventory = null; quickInventory = null; AdditionalEquippedUtilities.Clear(); DesiredAdditionalUtilities.Clear(); saveSequence = 0L; stateDirty = false; mutationDepth = 0; recoveryBlocked = false; LoadoutMutation = false; nextEvacuationRetry = 0f; } private static void LoadFromCharacterData(Player localPlayer) { if (gearInventory == null || quickInventory == null) { return; } string error = string.Empty; if (localPlayer.m_customData.TryGetValue("com.jg224.gearslots.save.v1", out var value) && SlotPersistence.TryLoad(value, gearInventory, quickInventory, out saveSequence, out error)) { RecoveryStatus = "Current slot payload loaded successfully."; return; } if (!string.IsNullOrEmpty(error)) { GearSlotsPlugin.ModLog.LogWarning((object)("The current GearSlots payload was not usable: " + error)); } string error2 = string.Empty; if (localPlayer.m_customData.TryGetValue("com.jg224.gearslots.save.backup.v1", out var value2) && SlotPersistence.TryLoad(value2, gearInventory, quickInventory, out saveSequence, out error2)) { if (!string.IsNullOrEmpty(value)) { localPlayer.m_customData["com.jg224.gearslots.save.corrupt.v1"] = value; } localPlayer.m_customData["com.jg224.gearslots.save.v1"] = value2; RecoveryStatus = "Recovered the previous valid slot payload; original retained in character recovery data."; GearSlotsPlugin.ModLog.LogWarning((object)"Recovered GearSlots items from the previous valid character payload."); return; } if (!string.IsNullOrEmpty(error2)) { GearSlotsPlugin.ModLog.LogError((object)("The GearSlots backup payload was also unusable: " + error2)); } recoveryBlocked = localPlayer.m_customData.ContainsKey("com.jg224.gearslots.save.v1") || localPlayer.m_customData.ContainsKey("com.jg224.gearslots.save.backup.v1"); payloadRecoveryOnly = recoveryBlocked; RecoveryStatus = (recoveryBlocked ? "Slot payload could not be loaded. Writes and slot transfers are paused; both saved payloads are preserved. Restore a compatible backup, then Retry load." : "New character slot storage."); if (recoveryBlocked) { GearSlotsRecoveryScreen.Open(); } } internal static void RetryRecovery() { if ((Object)(object)player != (Object)null && CanRetryRecovery) { Attach(player, forceReload: true); } } internal static void BlockForRecovery(string reason) { recoveryBlocked = true; payloadRecoveryOnly = false; RecoveryStatus = reason; GearSlotsRecoveryScreen.Open(); } private static void NormalizeLoadedItems() { if (gearInventory != null && quickInventory != null) { NormalizeInventory(gearInventory); NormalizeInventory(quickInventory); ValidateDuplicateIdentities(); } } private static void NormalizeInventory(Inventory inventory) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); foreach (ItemData item2 in inventory.GetAllItems().ToList()) { Vector2i gridPos = item2.m_gridPos; int item = gridPos.y * inventory.GetWidth() + gridPos.x; if (!TryGetSlot(inventory, gridPos, out var slot) || !hashSet.Add(item) || !SlotRuleAdapter.Accepts(slot, item2)) { EvacuateItem(inventory, item2, "an invalid saved slot"); } else { EnsureIdentity(item2); } } } private static void ValidateDuplicateIdentities() { if (!IsReady || (Object)(object)player == (Object)null || gearInventory == null || quickInventory == null) { return; } foreach (ItemData item in gearInventory.GetAllItems().Concat(quickInventory.GetAllItems())) { EnsureIdentity(item); } List list = (from item in ((Humanoid)player).GetInventory().GetAllItems().Concat(gearInventory.GetAllItems()) .Concat(quickInventory.GetAllItems()) where item.m_customData.ContainsKey("com.jg224.gearslots.item-id") select item).ToList(); string value; foreach (int item2 in DuplicateGuard.FindDuplicateIndices(list.Select((ItemData item) => (!item.m_customData.TryGetValue("com.jg224.gearslots.item-id", out value)) ? null : value).ToList())) { list[item2].m_customData["com.jg224.gearslots.item-id"] = Guid.NewGuid().ToString("N"); GearSlotsPlugin.ModLog.LogWarning((object)"Re-keyed a duplicate GearSlots item identity without removing the item."); } } private static void EvacuateDisabledSlots() { if (gearInventory == null) { return; } foreach (SlotKind dedicatedSlot in SlotRuleEngine.DedicatedSlots) { if (!IsSlotEnabled(dedicatedSlot)) { ItemData item = GetItem(dedicatedSlot); if (item != null && !EvacuateItem(gearInventory, item, "a disabled " + dedicatedSlot.ToString() + " slot")) { configurationDirty = true; } } } } private static bool EvacuateItem(Inventory source, ItemData item, string reason) { if ((Object)(object)player == (Object)null) { return false; } bool flag = ((Humanoid)player).IsItemEquiped(item); ((Humanoid)player).UnequipItem(item, false); Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory.CanAddItem(item, item.m_stack)) { inventory.MoveItemToThis(source, item); if (!source.ContainsItem(item)) { GearSlotsPlugin.ModLog.LogInfo((object)("Returned " + item.m_shared.m_name + " from " + reason + " to the player inventory.")); return true; } } if (!((Character)player).IsDead() && ((Humanoid)player).DropItem(source, item, item.m_stack)) { GearSlotsPlugin.ModLog.LogWarning((object)("Player inventory was full; safely dropped " + item.m_shared.m_name + " from " + reason + " at the player's feet.")); return true; } if (flag) { ((Humanoid)player).EquipItem(item, false); } return false; } private static void RecoverTaggedItemsFromMainInventory() { if ((Object)(object)player != (Object)null) { RecoverFromInventory(((Humanoid)player).GetInventory()); } } internal static void SynchronizeEquipment() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 if ((Object)(object)player == (Object)null || gearInventory == null || ((Character)player).IsDead()) { return; } PendingAnimatedEquipment.RemoveWhere((ItemData val) => !gearInventory.ContainsItem(val) || ((Humanoid)player).IsItemEquiped(val)); foreach (SlotKind dedicatedSlot in SlotRuleEngine.DedicatedSlots) { if (!IsSlotEnabled(dedicatedSlot)) { continue; } ItemData item = GetItem(dedicatedSlot); if (item == null || !item.IsEquipable() || ((Humanoid)player).IsItemEquiped(item) || (int)item.m_shared.m_itemType == 2) { continue; } if (PendingAnimatedEquipment.Contains(item)) { if (EquipmentActionPolicy.ResolvePendingEquip(player.IsEquipActionQueued(item)) == PendingEquipmentActionResolution.WaitForQueuedAction) { continue; } PendingAnimatedEquipment.Remove(item); } if (!player.IsEquipActionQueued(item) && !IsAdditionalUtilitySlot(dedicatedSlot)) { ((Humanoid)player).EquipItem(item, false); } } DesiredAdditionalUtilities.Clear(); foreach (SlotKind utilitySlot in SlotRuleEngine.UtilitySlots) { if (IsAdditionalUtilitySlot(utilitySlot)) { ItemData item2 = GetItem(utilitySlot); if (item2 != null && item2.IsEquipable() && IsSlotEnabled(utilitySlot) && !IsVanillaUtilityOrTrinket(item2)) { DesiredAdditionalUtilities.Add(item2); } } } bool flag = AdditionalEquippedUtilities.Count != DesiredAdditionalUtilities.Count || !AdditionalEquippedUtilities.SequenceEqual(DesiredAdditionalUtilities); foreach (ItemData additionalEquippedUtility in AdditionalEquippedUtilities) { if (!DesiredAdditionalUtilities.Contains(additionalEquippedUtility)) { additionalEquippedUtility.m_equipped = false; } } AdditionalEquippedUtilities.Clear(); AdditionalEquippedUtilities.AddRange(DesiredAdditionalUtilities); foreach (ItemData additionalEquippedUtility2 in AdditionalEquippedUtilities) { if (!additionalEquippedUtility2.m_equipped) { additionalEquippedUtility2.m_equipped = true; flag = true; } } if (flag) { RefreshEquipmentEffects(); } } internal static void UnequipAdditionalUtilities() { bool flag = false; foreach (ItemData additionalEquippedUtility in AdditionalEquippedUtilities) { if (additionalEquippedUtility.m_equipped) { additionalEquippedUtility.m_equipped = false; flag = true; } } AdditionalEquippedUtilities.Clear(); DesiredAdditionalUtilities.Clear(); if (flag) { RefreshEquipmentEffects(); } } private static bool IsAdditionalUtilitySlot(SlotKind slot) { if (slot != SlotKind.Utility2 && slot != SlotKind.Utility3 && slot != SlotKind.Utility4) { return slot == SlotKind.Utility5; } return true; } private static bool IsVanillaUtilityOrTrinket(ItemData item) { if ((Object)(object)player != (Object)null) { if (UtilityItemField.GetValue(player) != item) { return TrinketItemField.GetValue(player) == item; } return true; } return false; } private static bool TryFindUtilityDestination(out SlotKind destination) { foreach (SlotKind utilitySlot in SlotRuleEngine.UtilitySlots) { if (IsSlotEnabled(utilitySlot) && GetItem(utilitySlot) == null) { destination = utilitySlot; return true; } } foreach (SlotKind utilitySlot2 in SlotRuleEngine.UtilitySlots) { if (IsSlotEnabled(utilitySlot2)) { destination = utilitySlot2; return true; } } destination = SlotKind.Head; return false; } private static void RefreshEquipmentEffects() { if ((Object)(object)player == (Object)null) { return; } try { SetupEquipmentMethod.Invoke(player, Array.Empty()); } catch (Exception ex) { GearSlotsPlugin.ModLog.LogError((object)("Could not refresh additional utility equipment effects: " + ex)); } } private static void HandleQuickSlotInput() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || quickInventory == null || !CanUseQuickSlots()) { return; } for (int i = 0; i < 3; i++) { KeyboardShortcut quickKey = GearSlotsPlugin.Settings.GetQuickKey(i); if (((KeyboardShortcut)(ref quickKey)).IsDown()) { UseQuickSlot(i); } } } internal static void UseQuickSlot(int index) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 if ((Object)(object)player == (Object)null || quickInventory == null || index < 0 || index > 2) { return; } ItemData itemAt = quickInventory.GetItemAt(index, 0); if (itemAt == null) { return; } BeginMutation(); try { Inventory val = (Inventory)(((int)itemAt.m_shared.m_itemType == 2) ? ((object)quickInventory) : ((object)((Humanoid)player).GetInventory())); ((Humanoid)player).UseItem(val, itemAt, false); } finally { EndMutation(); } } private static bool CanUseQuickSlots() { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || InventoryGui.IsVisible() || TextInput.IsVisible() || Console.IsVisible() || Menu.IsVisible() || StoreGui.IsVisible() || Minimap.InTextInput()) { return false; } if (!((Object)(object)Chat.instance == (Object)null)) { return !Chat.instance.HasFocus(); } return true; } private static void OnAuxiliaryInventoryChanged() { if (!suppressChanges) { MarkChanged(); } } } internal static class SlotTransferService { internal static bool TryPlaceInSlot(Inventory source, ItemData item, int amount, SlotKind slot, bool showMessage = true) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) Player currentPlayer = SlotStateManager.CurrentPlayer; Inventory inventory = SlotStateManager.GetInventory(slot); if ((Object)(object)currentPlayer == (Object)null || inventory == null || !source.GetAllItems().Contains(item)) { return false; } if (!SlotStateManager.IsSlotEnabled(slot)) { return Fail(currentPlayer, slot.ToString() + " is disabled.", showMessage); } if (!SlotRuleAdapter.Accepts(slot, item)) { return Fail(currentPlayer, item.m_shared.m_name + " cannot be placed in " + slot.ToString() + ".", showMessage); } if (item.m_shared.m_questItem && !SlotRuleAdapter.IsUtilityKey(item) && source != inventory) { return Fail(currentPlayer, "Quest items cannot be moved into GearSlots.", showMessage); } if (!SlotStateManager.TryEnterTransfer(item, out string identity)) { return false; } SlotStateManager.BeginMutation(); try { Vector2i position = SlotStateManager.GetPosition(slot); ItemData itemAt = inventory.GetItemAt(position.x, position.y); if (itemAt == item) { return true; } bool flag = ((Humanoid)currentPlayer).IsItemEquiped(item); ((Humanoid)currentPlayer).RemoveEquipAction(item); if (itemAt != null) { ((Humanoid)currentPlayer).RemoveEquipAction(itemAt); } if (source == SlotStateManager.GearInventory && ((Humanoid)currentPlayer).IsItemEquiped(item)) { ((Humanoid)currentPlayer).UnequipItem(item, false); } if (!((itemAt != null && !CanStack(itemAt, item)) ? ReplaceAndReturnExistingToMain(currentPlayer, source, inventory, item, itemAt, amount, position) : inventory.MoveItemToThis(source, item, amount, position.x, position.y))) { return Fail(currentPlayer, "There is no safe place for the replaced item.", showMessage); } ItemData itemAt2 = inventory.GetItemAt(position.x, position.y); if (itemAt2 != null) { SlotStateManager.EnsureIdentity(itemAt2); bool completedEquipWasPreserved = flag && SlotStateManager.TryRebindCompletedEquipment(slot, item, itemAt2); SlotStateManager.QueueEquipmentAfterTransfer(slot, itemAt2, completedEquipWasPreserved); } SlotStateManager.SynchronizeEquipment(); return true; } finally { SlotStateManager.EndMutation(); SlotStateManager.ExitTransfer(identity); } } internal static bool TryDropOnRegularGrid(InventoryGrid targetGrid, Inventory source, ItemData item, int amount, Vector2i position) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) Player currentPlayer = SlotStateManager.CurrentPlayer; if ((Object)(object)currentPlayer == (Object)null || !SlotStateManager.TryGetSlot(source, item.m_gridPos, out var slot) || !SlotStateManager.TryEnterTransfer(item, out string identity)) { return false; } SlotStateManager.BeginMutation(); try { ItemData itemAt = targetGrid.GetInventory().GetItemAt(position.x, position.y); if (itemAt != null && !CanStack(itemAt, item) && item.m_stack == amount && !SlotRuleAdapter.Accepts(slot, itemAt)) { ((Character)currentPlayer).Message((MessageType)2, itemAt.m_shared.m_name + " cannot replace the " + slot.ToString() + " slot item.", 0, (Sprite)null, false); return false; } bool flag = ((Humanoid)currentPlayer).IsItemEquiped(item); bool flag2 = SlotRuleEngine.UsesStandardEquipQueue(slot); ((Humanoid)currentPlayer).RemoveEquipAction(item); if (flag && !flag2) { ((Humanoid)currentPlayer).UnequipItem(item, false); } bool num = targetGrid.DropItem(source, item, amount, position); if (!num && flag && !flag2) { ((Humanoid)currentPlayer).EquipItem(item, false); } if (num) { ItemData item2 = SlotStateManager.GetItem(slot); if (item2 != null) { SlotStateManager.EnsureIdentity(item2); SlotStateManager.QueueEquipmentAfterTransfer(slot, item2); } if (EquipmentActionPolicy.ShouldQueueUnequipAfterTransfer(flag2, flag, transferSucceeded: true, item2 != null)) { SlotStateManager.QueueUnequipAfterTransfer(item); } SlotStateManager.SynchronizeEquipment(); } return num; } finally { SlotStateManager.EndMutation(); SlotStateManager.ExitTransfer(identity); } } internal static bool TryMoveItemToMain(ItemData item) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) Player currentPlayer = SlotStateManager.CurrentPlayer; Inventory val = SlotStateManager.FindAuxiliaryInventory(item); if ((Object)(object)currentPlayer == (Object)null || val == null || !SlotStateManager.TryEnterTransfer(item, out string identity)) { return false; } SlotStateManager.BeginMutation(); try { Inventory inventory = ((Humanoid)currentPlayer).GetInventory(); if (!inventory.CanAddItem(item, item.m_stack)) { ((Character)currentPlayer).Message((MessageType)2, "$msg_inventoryfull", 0, (Sprite)null, false); return false; } bool flag = ((Humanoid)currentPlayer).IsItemEquiped(item); SlotKind slot; bool flag2 = SlotStateManager.TryGetSlot(val, item.m_gridPos, out slot) && SlotRuleEngine.UsesStandardEquipQueue(slot); ((Humanoid)currentPlayer).RemoveEquipAction(item); if (flag && !flag2) { ((Humanoid)currentPlayer).UnequipItem(item, false); } inventory.MoveItemToThis(val, item); bool flag3 = !val.ContainsItem(item); if (!flag3 && flag && !flag2) { ((Humanoid)currentPlayer).EquipItem(item, false); } if (EquipmentActionPolicy.ShouldQueueUnequipAfterTransfer(flag2, flag, flag3, replacementWillEquip: false)) { SlotStateManager.QueueUnequipAfterTransfer(item); } SlotStateManager.SynchronizeEquipment(); return flag3; } finally { SlotStateManager.EndMutation(); SlotStateManager.ExitTransfer(identity); } } internal static bool TryDropAtPlayer(ItemData item) { Player currentPlayer = SlotStateManager.CurrentPlayer; Inventory val = SlotStateManager.FindAuxiliaryInventory(item); if ((Object)(object)currentPlayer == (Object)null || val == null || !SlotStateManager.TryEnterTransfer(item, out string identity)) { return false; } SlotStateManager.BeginMutation(); try { bool flag = ((Humanoid)currentPlayer).IsItemEquiped(item); ((Humanoid)currentPlayer).RemoveEquipAction(item); if (flag) { ((Humanoid)currentPlayer).UnequipItem(item, false); } bool num = ((Humanoid)currentPlayer).DropItem(val, item, item.m_stack); if (!num && flag) { ((Humanoid)currentPlayer).EquipItem(item, false); } return num; } finally { SlotStateManager.EndMutation(); SlotStateManager.ExitTransfer(identity); } } private static bool ReplaceAndReturnExistingToMain(Player player, Inventory source, Inventory destination, ItemData incoming, ItemData existing, int amount, Vector2i destinationPosition) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (amount != incoming.m_stack) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); Vector2i gridPos = incoming.m_gridPos; bool flag = source == inventory; if (!flag && !inventory.CanAddItem(existing, existing.m_stack)) { return false; } bool flag2 = ((Humanoid)player).IsItemEquiped(existing); if (flag2) { ((Humanoid)player).UnequipItem(existing, false); } if (!destination.RemoveItem(existing)) { return false; } if (flag) { if (!source.RemoveItem(incoming)) { destination.AddItem(existing, destinationPosition); return false; } if (!inventory.AddItem(existing, gridPos) || !destination.AddItem(incoming, destinationPosition)) { RollBackMainReplacement(inventory, destination, incoming, existing, gridPos, destinationPosition); if (flag2) { ((Humanoid)player).EquipItem(existing, false); } return false; } return true; } if (!inventory.AddItem(existing)) { destination.AddItem(existing, destinationPosition); if (flag2) { ((Humanoid)player).EquipItem(existing, false); } return false; } if (destination.MoveItemToThis(source, incoming, amount, destinationPosition.x, destinationPosition.y)) { return true; } inventory.RemoveItem(existing); destination.AddItem(existing, destinationPosition); if (flag2) { ((Humanoid)player).EquipItem(existing, false); } return false; } private static void RollBackMainReplacement(Inventory main, Inventory destination, ItemData incoming, ItemData existing, Vector2i sourcePosition, Vector2i destinationPosition) { //IL_002d: 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) if (main.ContainsItem(existing)) { main.RemoveItem(existing); } if (destination.ContainsItem(incoming)) { destination.RemoveItem(incoming); } if (!main.ContainsItem(incoming)) { main.AddItem(incoming, sourcePosition); } if (!destination.ContainsItem(existing)) { destination.AddItem(existing, destinationPosition); } } private static bool CanStack(ItemData existing, ItemData incoming) { if (existing.m_shared.m_name == incoming.m_shared.m_name && existing.m_quality == incoming.m_quality) { return existing.m_shared.m_maxStackSize > 1; } return false; } private static bool Fail(Player player, string message, bool showMessage) { if (showMessage) { ((Character)player).Message((MessageType)2, message, 0, (Sprite)null, false); } return false; } } internal static class TombstoneRecovery { internal static bool IsTombstone(Container container) { return (Object)(object)((Component)container).GetComponent() != (Object)null; } internal static bool Recover(Container container, bool takeAll) { Player player = Player.m_localPlayer; if (!container.IsOwner() || !SlotStateManager.IsReady || (Object)(object)player == (Object)null || ((Character)player).IsDead() || SlotStateManager.CurrentPlayer != player) { return false; } Inventory source = container.GetInventory(); Inventory[] inventories = ((IEnumerable)(object)new Inventory[4] { source, ((Humanoid)player).GetInventory(), SlotStateManager.GearInventory, SlotStateManager.QuickInventory }).Distinct().ToArray(); Dictionary originals = inventories.ToDictionary((Inventory inventory) => inventory, (Inventory inventory) => inventory.GetAllItems().ToArray()); ItemData[] items = originals.Values.SelectMany((ItemData[] value) => value).Distinct().ToArray(); Dictionary positions = items.ToDictionary((ItemData item) => item, (ItemData item) => item.m_gridPos); Dictionary stacks = items.ToDictionary((ItemData item) => item, (ItemData item) => item.m_stack); Dictionary> metadata = items.ToDictionary((ItemData item) => item, (ItemData item) => new Dictionary(item.m_customData)); ItemData[] equipped = items.Where((ItemData item) => ((Humanoid)player).IsItemEquiped(item)).ToArray(); MethodInfo changed = typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int recovered = 0; SlotStateManager.BeginMutation(); bool flag; try { flag = TombstoneRecoveryFlow.Execute(container.IsOwner(), SlotStateManager.IsReady, !((Character)player).IsDead(), delegate { recovered = SlotStateManager.RecoverFromInventory(source); if (takeAll) { ((Humanoid)player).GetInventory().MoveAll(source); } SlotStateManager.MarkChanged(); }, delegate { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) ItemData[] array = inventories.SelectMany((Inventory inventory) => inventory.GetAllItems()).Distinct().ToArray(); foreach (ItemData val in array) { ((Humanoid)player).RemoveEquipAction(val); if (((Humanoid)player).IsItemEquiped(val)) { ((Humanoid)player).UnequipItem(val, false); } } Inventory[] array2 = inventories; foreach (Inventory val2 in array2) { val2.GetAllItems().Clear(); val2.GetAllItems().AddRange(originals[val2]); } array = items; foreach (ItemData val3 in array) { val3.m_gridPos = positions[val3]; val3.m_stack = stacks[val3]; val3.m_customData.Clear(); foreach (KeyValuePair item in metadata[val3]) { val3.m_customData.Add(item.Key, item.Value); } } array2 = inventories; foreach (Inventory obj in array2) { changed.Invoke(obj, new object[2] { false, false }); } array = equipped; foreach (ItemData val4 in array) { ((Humanoid)player).EquipItem(val4, false); } SlotStateManager.SynchronizeEquipment(); SlotStateManager.MarkChanged(); }, delegate { SlotStateManager.BlockForRecovery("Tombstone rollback could not finish. Existing character payloads are preserved."); }, delegate { }); } finally { SlotStateManager.EndMutation(); } if (flag && !takeAll && recovered > 0 && source.NrOfItems() == 0) { container.m_onTakeAllSuccess?.Invoke(); } return flag; } } } namespace GearSlots.Patches { [HarmonyPatch(typeof(FejdStartup), "SetupCharacterPreview")] internal static class FejdStartupSetupCharacterPreviewPatch { private static void Postfix(FejdStartup __instance) { Player previewPlayer = __instance.GetPreviewPlayer(); if ((Object)(object)previewPlayer != (Object)null) { try { CharacterPreviewService.Apply(previewPlayer); } catch (Exception ex) { GearSlotsPlugin.ModLog.LogError((object)("Could not apply protected equipment to the character preview: " + ex)); } } } } [HarmonyPatch(typeof(Player), "CreateTombStone")] internal static class PlayerCreateTombStonePatch { private sealed class StagedItem { internal Inventory Source { get; } internal ItemData Item { get; } internal Vector2i OriginalPosition { get; } internal StagedItem(Inventory source, ItemData item, Vector2i originalPosition) { //IL_0015: 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) Source = source; Item = item; OriginalPosition = originalPosition; } } private static readonly FieldInfo InventoryHeightField = AccessTools.Field(typeof(Inventory), "m_height"); private static bool Prefix(Player __instance) { //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !SlotStateManager.IsReady || SlotStateManager.GearInventory == null || SlotStateManager.QuickInventory == null) { return true; } if (ZoneSystem.instance.GetGlobalKey((GlobalKeys)23)) { return false; } Inventory inventory = ((Humanoid)__instance).GetInventory(); int height = inventory.GetHeight(); List list = new List(); Inventory val = null; SlotStateManager.BeginMutation(); try { ApplyVanillaDeathInventoryRules(__instance, inventory); TagMainInventoryOrigins(inventory); bool keepEquipped = ZoneSystem.instance.GetGlobalKey((GlobalKeys)19); List list2 = (from item in SlotStateManager.GearInventory.GetAllItems().Concat(SlotStateManager.QuickInventory.GetAllItems()) where !keepEquipped || !item.m_equipped select item).ToList(); if (inventory.NrOfItems() == 0 && list2.Count == 0) { return false; } int width = inventory.GetWidth(); int num = (list2.Count + width - 1) / width; InventoryHeightField.SetValue(inventory, height + num); Vector2i val4 = default(Vector2i); for (int num2 = 0; num2 < list2.Count; num2++) { ItemData val2 = list2[num2]; Inventory val3 = SlotStateManager.FindAuxiliaryInventory(val2); if (val3 == null || !SlotStateManager.TryGetSlot(val2, out var slot)) { continue; } Vector2i gridPos = val2.m_gridPos; val2.m_customData["com.jg224.gearslots.tombstone-origin"] = slot.ToString(); ((Humanoid)__instance).UnequipItem(val2, false); if (!val3.RemoveItem(val2)) { val2.m_customData.Remove("com.jg224.gearslots.tombstone-origin"); continue; } ((Vector2i)(ref val4))..ctor(num2 % width, height + num2 / width); if (!inventory.AddItem(val2, val4)) { val2.m_customData.Remove("com.jg224.gearslots.tombstone-origin"); val3.AddItem(val2, gridPos); } else { list.Add(new StagedItem(val3, val2, gridPos)); } } GameObject obj = Object.Instantiate(__instance.m_tombstone, ((Character)__instance).GetCenterPoint(), ((Component)__instance).transform.rotation); val = obj.GetComponent().GetInventory(); val.MoveInventoryToGrave(inventory); TombStone component = obj.GetComponent(); PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); component.Setup(playerProfile.GetName(), playerProfile.GetPlayerID()); SlotStateManager.Persist(); return false; } catch (Exception ex) { GearSlotsPlugin.ModLog.LogError((object)("GearSlots death transfer failed; preserving staged items through recovery logic: " + ex)); if (val != null) { try { val.MoveInventoryToGrave(inventory); } catch (Exception ex2) { GearSlotsPlugin.ModLog.LogError((object)("Could not finish the tombstone recovery move: " + ex2)); } return false; } RollBackStagedItems(inventory, list); ClearMainInventoryOrigins(inventory); return true; } finally { InventoryHeightField.SetValue(inventory, height); SlotStateManager.EndMutation(); } } private static void TagMainInventoryOrigins(Inventory main) { foreach (ItemData allItem in main.GetAllItems()) { if (!allItem.m_shared.m_questItem && !allItem.m_equipped) { allItem.m_customData["com.jg224.gearslots.main-inventory-origin"] = MainInventoryOriginCodec.Encode(allItem.m_gridPos.x, allItem.m_gridPos.y); } } } private static void ClearMainInventoryOrigins(Inventory main) { foreach (ItemData allItem in main.GetAllItems()) { allItem.m_customData.Remove("com.jg224.gearslots.main-inventory-origin"); } } private static void ApplyVanillaDeathInventoryRules(Player player, Inventory main) { bool globalKey = ZoneSystem.instance.GetGlobalKey((GlobalKeys)19); bool globalKey2 = ZoneSystem.instance.GetGlobalKey((GlobalKeys)20); bool globalKey3 = ZoneSystem.instance.GetGlobalKey((GlobalKeys)21); if (!globalKey && !globalKey3) { ((Humanoid)player).UnequipAllItems(); } if (globalKey2 || globalKey3) { main.RemoveUnequipped(); Inventory? gearInventory = SlotStateManager.GearInventory; if (gearInventory != null) { gearInventory.RemoveUnequipped(); } Inventory? quickInventory = SlotStateManager.QuickInventory; if (quickInventory != null) { quickInventory.RemoveUnequipped(); } } if (globalKey3 && !globalKey) { ((Humanoid)player).UnequipAllItems(); } } private static void RollBackStagedItems(Inventory main, IEnumerable staged) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) foreach (StagedItem item in staged) { if (main.GetAllItems().Contains(item.Item)) { main.RemoveItem(item.Item); item.Item.m_customData.Remove("com.jg224.gearslots.tombstone-origin"); if (!item.Source.AddItem(item.Item, item.OriginalPosition)) { main.AddItem(item.Item); } } } } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] internal static class HumanoidEquipItemPatch { private static void Postfix(Humanoid __instance, ItemData item, bool __result) { if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { SlotStateManager.RouteEquippedItem(item); } } } [HarmonyPatch(typeof(Humanoid), "IsItemEquiped")] internal static class HumanoidIsItemEquipedPatch { private static void Postfix(Humanoid __instance, ItemData item, ref bool __result) { if (!__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { __result = SlotStateManager.IsAdditionalUtilityItem(item); } } } [HarmonyPatch(typeof(Humanoid), "UnequipAllItems")] internal static class HumanoidUnequipAllItemsPatch { private static void Postfix(Humanoid __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { SlotStateManager.UnequipAdditionalUtilities(); } } } [HarmonyPatch(typeof(Humanoid), "UpdateEquipmentStatusEffects")] internal static class HumanoidUpdateEquipmentStatusEffectsPatch { private static readonly FieldInfo EquipmentStatusEffectsField = AccessTools.Field(typeof(Humanoid), "m_equipmentStatusEffects"); private static void Prefix(Humanoid __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !(EquipmentStatusEffectsField.GetValue(__instance) is HashSet hashSet)) { return; } foreach (ItemData additionalEquippedUtility in SlotStateManager.GetAdditionalEquippedUtilities()) { StatusEffect equipStatusEffect = additionalEquippedUtility.m_shared.m_equipStatusEffect; if (additionalEquippedUtility.m_equipped && (Object)(object)equipStatusEffect != (Object)null) { hashSet.Remove(equipStatusEffect); } } } private static void Postfix(Humanoid __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !(EquipmentStatusEffectsField.GetValue(__instance) is HashSet hashSet)) { return; } foreach (ItemData additionalEquippedUtility in SlotStateManager.GetAdditionalEquippedUtilities()) { StatusEffect equipStatusEffect = additionalEquippedUtility.m_shared.m_equipStatusEffect; if (additionalEquippedUtility.m_equipped && (Object)(object)equipStatusEffect != (Object)null && hashSet.Add(equipStatusEffect)) { SEMan sEMan = ((Character)__instance).GetSEMan(); if ((Object)(object)sEMan.GetStatusEffect(equipStatusEffect.NameHash()) == (Object)null) { sEMan.AddStatusEffect(equipStatusEffect, false, 0, 0f, (short)(-1)); } } } } } [HarmonyPatch(typeof(Player), "UpdateModifiers")] internal static class PlayerUpdateModifiersPatch { private static readonly FieldInfo ModifierSourceFieldsField = AccessTools.Field(typeof(Player), "s_equipmentModifierSourceFields"); private static readonly FieldInfo ModifierValuesField = AccessTools.Field(typeof(Player), "m_equipmentModifierValues"); private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !(ModifierSourceFieldsField.GetValue(null) is FieldInfo[] array) || !(ModifierValuesField.GetValue(__instance) is float[] array2)) { return; } foreach (ItemData additionalEquippedUtility in SlotStateManager.GetAdditionalEquippedUtilities()) { if (additionalEquippedUtility.m_equipped) { for (int i = 0; i < array2.Length && i < array.Length; i++) { array2[i] += (float)array[i].GetValue(additionalEquippedUtility.m_shared); } } } } } [HarmonyPatch(typeof(Player), "GetEquipmentEitrRegenModifier")] internal static class PlayerGetEquipmentEitrRegenModifierPatch { private static void Postfix(Player __instance, ref float __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } foreach (ItemData additionalEquippedUtility in SlotStateManager.GetAdditionalEquippedUtilities()) { if (additionalEquippedUtility.m_equipped) { __result += additionalEquippedUtility.m_shared.m_eitrRegenModifier; } } } } [HarmonyPatch(typeof(Humanoid), "GetEquipmentWeight")] internal static class HumanoidGetEquipmentWeightPatch { private static void Postfix(Humanoid __instance, ref float __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } foreach (ItemData additionalEquippedUtility in SlotStateManager.GetAdditionalEquippedUtilities()) { if (additionalEquippedUtility.m_equipped) { __result += additionalEquippedUtility.m_shared.m_weight; } } } } [HarmonyPatch(typeof(Hud), "Awake")] internal static class HudAwakePatch { private static void Postfix(Hud __instance) { GearSlotsUi.CreateHud(__instance); } } [HarmonyPatch(typeof(Hud), "OnDestroy")] internal static class HudOnDestroyPatch { private static void Prefix() { GearSlotsUi.DestroyHud(); } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGamepad")] internal static class InventoryGridUpdateGamepadPatch { private static bool Prefix(InventoryGrid __instance) { return !GearSlotsUi.HandleDedicatedGamepad(__instance); } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer", new Type[] { typeof(Player) })] internal static class InventoryGuiAuxiliaryDragPatch { private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Expected O, but got Unknown List list = instructions.ToList(); FieldInfo fieldInfo = typeof(InventoryGui).GetField("m_dragInventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(InventoryGui).FullName, "m_dragInventory"); FieldInfo fieldInfo2 = typeof(Player).GetField("m_localPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(Player).FullName, "m_localPlayer"); MethodInfo methodInfo = typeof(Humanoid).GetMethod("GetInventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) ?? throw new MissingMethodException(typeof(Humanoid).FullName, "GetInventory"); MethodInfo methodInfo2 = typeof(InventoryGui).GetMethod("SetupDragItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(ItemData), typeof(Inventory), typeof(int) }, null) ?? throw new MissingMethodException(typeof(InventoryGui).FullName, "SetupDragItem"); List list2 = new List(); for (int i = 0; i + 12 < list.Count; i++) { if (list[i].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.LoadsField(list[i + 1], fieldInfo, false) && (list[i + 2].opcode == OpCodes.Brfalse || list[i + 2].opcode == OpCodes.Brfalse_S) && list[i + 3].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.LoadsField(list[i + 4], fieldInfo, false) && CodeInstructionExtensions.LoadsField(list[i + 5], fieldInfo2, false) && CodeInstructionExtensions.Calls(list[i + 6], methodInfo) && (list[i + 7].opcode == OpCodes.Beq || list[i + 7].opcode == OpCodes.Beq_S) && BranchesShareTarget(list, list[i + 2], list[i + 7]) && list[i + 8].opcode == OpCodes.Ldarg_0 && list[i + 9].opcode == OpCodes.Ldnull && list[i + 10].opcode == OpCodes.Ldnull && list[i + 11].opcode == OpCodes.Ldc_I4_1 && CodeInstructionExtensions.Calls(list[i + 12], methodInfo2)) { list2.Add(i + 7); } } if (list2.Count != 1) { throw new InvalidOperationException("Unsupported InventoryGui.UpdateContainer drag cleanup: expected one native player-inventory comparison, found " + list2.Count + ". GearSlots cannot safely patch this game version."); } int num = list2[0]; CodeInstruction obj = list[num]; object operand = obj.operand; obj.opcode = OpCodes.Call; obj.operand = typeof(InventoryGuiAuxiliaryDragPatch).GetMethod("IsPlayerOwnedDragInventory", BindingFlags.Static | BindingFlags.NonPublic); list.Insert(num + 1, new CodeInstruction(OpCodes.Brtrue, operand)); return list; } private static bool BranchesShareTarget(List body, CodeInstruction first, CodeInstruction second) { if (!(first.operand is Label item) || !(second.operand is Label item2)) { return false; } CodeInstruction val = null; CodeInstruction val2 = null; foreach (CodeInstruction item3 in body) { if (item3.labels.Contains(item)) { if (val != null) { return false; } val = item3; } if (item3.labels.Contains(item2)) { if (val2 != null) { return false; } val2 = item3; } } if (val != null) { return val == val2; } return false; } private static bool IsPlayerOwnedDragInventory(Inventory? dragInventory, Inventory? nativePlayerInventory) { if (dragInventory == nativePlayerInventory) { return true; } if (dragInventory == null || !SlotStateManager.IsReady) { return false; } Player currentPlayer = SlotStateManager.CurrentPlayer; if ((Object)(object)currentPlayer != (Object)null && currentPlayer == Player.m_localPlayer && ((Humanoid)currentPlayer).GetInventory() == nativePlayerInventory) { return SlotStateManager.IsAuxiliaryInventory(dragInventory); } return false; } } [HarmonyPatch(typeof(InventoryGui), "Awake")] internal static class InventoryGuiAwakePatch { private static void Postfix(InventoryGui __instance) { GearSlotsUi.Create(__instance); } } [HarmonyPatch(typeof(InventoryGui), "OnDestroy")] internal static class InventoryGuiOnDestroyPatch { private static void Prefix() { GearSlotsUi.Destroy(); } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem", new Type[] { typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i), typeof(Modifier) })] internal static class InventoryGuiOnSelectedItemPatch { private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData? item, Vector2i pos, Modifier mod, GameObject? ___m_dragGo, ItemData? ___m_dragItem, Inventory? ___m_dragInventory, int ___m_dragAmount) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return !GearSlotsUi.HandleSelected(__instance, grid, item, pos, mod, ___m_dragGo, ___m_dragItem, ___m_dragInventory, ___m_dragAmount); } } [HarmonyPatch(typeof(InventoryGui), "OnRightClickItem", new Type[] { typeof(InventoryGrid), typeof(ItemData), typeof(Vector2i) })] internal static class InventoryGuiOnRightClickItemPatch { private static bool Prefix(InventoryGrid grid, ItemData? item, Vector2i pos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return !GearSlotsUi.HandleRightClick(grid, item, pos); } } [HarmonyPatch(typeof(Inventory), "ContainsItem", new Type[] { typeof(ItemData) })] internal static class InventoryContainsItemPatch { private static void Postfix(Inventory __instance, ItemData item, ref bool __result) { if (!__result && SlotStateManager.IsMainInventory(__instance)) { __result = SlotStateManager.ContainsAuxiliaryItem(item); } } } [HarmonyPatch(typeof(Inventory), "GetTotalWeight")] internal static class InventoryGetTotalWeightPatch { private static void Postfix(Inventory __instance, ref float __result) { if (SlotStateManager.IsMainInventory(__instance)) { float num = __result; Inventory? gearInventory = SlotStateManager.GearInventory; __result = num + ((gearInventory != null) ? gearInventory.GetTotalWeight() : 0f); float num2 = __result; Inventory? quickInventory = SlotStateManager.QuickInventory; __result = num2 + ((quickInventory != null) ? quickInventory.GetTotalWeight() : 0f); } } } [HarmonyPatch(typeof(Inventory), "IsTeleportable", new Type[] { typeof(bool) })] internal static class InventoryIsTeleportablePatch { private static void Postfix(Inventory __instance, bool allowAllItems, ref bool __result) { if (__result && SlotStateManager.IsMainInventory(__instance)) { __result = SlotStateManager.AuxiliaryInventoriesAreTeleportable(allowAllItems); } } } [HarmonyPatch(typeof(Inventory), "GetAmmoItem", new Type[] { typeof(string), typeof(string) })] internal static class InventoryGetAmmoItemPatch { private static void Postfix(Inventory __instance, string ammoName, string? matchPrefabName, ref ItemData? __result) { if (SlotStateManager.IsMainInventory(__instance)) { ItemData preferredAmmo = SlotStateManager.GetPreferredAmmo(ammoName, matchPrefabName); if (preferredAmmo != null) { __result = preferredAmmo; } } } } [HarmonyPatch(typeof(Inventory), "RemoveOneItem", new Type[] { typeof(ItemData) })] internal static class InventoryRemoveOneItemPatch { private static bool Prefix(Inventory __instance, ItemData item, ref bool __result) { if (!SlotStateManager.IsMainInventory(__instance) || __instance.GetAllItems().Contains(item)) { return true; } Inventory val = SlotStateManager.FindAuxiliaryInventory(item); if (val == null) { return true; } SlotStateManager.BeginMutation(); try { __result = val.RemoveOneItem(item); return false; } finally { SlotStateManager.EndMutation(); } } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData) })] internal static class InventoryRemoveItemObjectPatch { private static bool Prefix(Inventory __instance, ItemData item, ref bool __result) { if (!SlotStateManager.IsMainInventory(__instance) || __instance.GetAllItems().Contains(item)) { return true; } Inventory val = SlotStateManager.FindAuxiliaryInventory(item); if (val == null) { return true; } SlotStateManager.BeginMutation(); try { __result = val.RemoveItem(item); return false; } finally { SlotStateManager.EndMutation(); } } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData), typeof(int) })] internal static class InventoryRemoveItemAmountPatch { private static bool Prefix(Inventory __instance, ItemData item, int amount, ref bool __result) { if (!SlotStateManager.IsMainInventory(__instance) || __instance.GetAllItems().Contains(item)) { return true; } Inventory val = SlotStateManager.FindAuxiliaryInventory(item); if (val == null) { return true; } SlotStateManager.BeginMutation(); try { __result = val.RemoveItem(item, amount); return false; } finally { SlotStateManager.EndMutation(); } } } [HarmonyPatch(typeof(Inventory), "GetWornItems")] internal static class InventoryGetWornItemsPatch { private static void Postfix(Inventory __instance, List worn) { if (SlotStateManager.IsMainInventory(__instance)) { SlotStateManager.AddRepairCandidates(worn); } } } [HarmonyPatch(typeof(Inventory), "CountItems", new Type[] { typeof(string), typeof(int), typeof(bool) })] internal static class InventoryCountItemsPatch { private static void Postfix(Inventory __instance, string? name, int quality, bool matchWorldLevel, ref int __result) { if (ResourceOperationContext.IsActive && SlotStateManager.IsMainInventory(__instance)) { __result += SlotStateManager.CountQuickItems(name, quality, matchWorldLevel); } } } [HarmonyPatch(typeof(Inventory), "HaveItem", new Type[] { typeof(string), typeof(bool) })] internal static class InventoryHaveItemPatch { private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result) { if (!__result && SlotStateManager.IsMainInventory(__instance)) { if (SlotStateManager.HasDedicatedUtilityKey(name, matchWorldLevel)) { __result = true; } else if (ResourceOperationContext.IsActive) { __result = SlotStateManager.CountQuickItems(name, -1, matchWorldLevel) > 0; } } } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(bool) })] internal static class InventoryRemoveResourcesPatch { private sealed class RemovalState { internal int Requested { get; set; } internal int MainBefore { get; set; } } private static void Prefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased, out RemovalState? __state) { __state = null; if (ResourceOperationContext.IsActive && SlotStateManager.IsMainInventory(__instance)) { __state = new RemovalState { Requested = amount, MainBefore = CountDirect(__instance, name, itemQuality, worldLevelBased) }; } } private static void Postfix(Inventory __instance, string name, int itemQuality, bool worldLevelBased, RemovalState? __state) { if (__state != null) { int num = CountDirect(__instance, name, itemQuality, worldLevelBased); int num2 = __state.MainBefore - num; int num3 = __state.Requested - num2; if (num3 > 0) { SlotStateManager.RemoveQuickItems(name, num3, itemQuality, worldLevelBased); } } } private static int CountDirect(Inventory inventory, string name, int quality, bool matchWorldLevel) { return (from item in inventory.GetAllItems() where item.m_shared.m_name == name && (quality < 0 || item.m_quality == quality) && (!matchWorldLevel || item.m_worldLevel >= Game.m_worldLevel) select item).Sum((ItemData item) => item.m_stack); } } [HarmonyPatch(typeof(Player), "AutoPickup", new Type[] { typeof(float) })] internal static class PlayerAutoPickupWeightPatch { private static IEnumerable Transpiler(IEnumerable instructions) { List list = instructions.ToList(); MethodInfo getter = typeof(Inventory).GetMethod("GetTotalWeight", Type.EmptyTypes) ?? throw new MissingMethodException(typeof(Inventory).FullName, "GetTotalWeight"); List list2 = list.Where((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, getter)).ToList(); if (list2.Count != 1) { throw new InvalidOperationException("Unsupported Player.AutoPickup weight check: expected one inventory weight read, found " + list2.Count + "."); } list2[0].opcode = OpCodes.Call; list2[0].operand = typeof(PlayerAutoPickupWeightPatch).GetMethod("GetPickupWeight", BindingFlags.Static | BindingFlags.NonPublic); return list; } private static float GetPickupWeight(Inventory inventory) { float num = SumWeight(inventory); Player currentPlayer = SlotStateManager.CurrentPlayer; if ((Object)(object)currentPlayer != (Object)null && currentPlayer == Player.m_localPlayer && ((Humanoid)currentPlayer).GetInventory() == inventory) { num += SumWeight(SlotStateManager.GearInventory); num += SumWeight(SlotStateManager.QuickInventory); } return num; } private static float SumWeight(Inventory? inventory) { float num = 0f; if (inventory != null) { foreach (ItemData allItem in inventory.GetAllItems()) { num += allItem.GetWeight(-1); } } return num; } } [HarmonyPatch(typeof(Player), "Save")] internal static class PlayerSavePatch { private static void Prefix(Player __instance) { SlotStateManager.PersistBeforePlayerSave(__instance); } } [HarmonyPatch(typeof(Player), "Load")] internal static class PlayerLoadPatch { private static void Postfix(Player __instance) { SlotStateManager.ReloadAfterPlayerLoad(__instance); } } internal static class QuickAutoStackContext { [ThreadStatic] private static int pickupDepth; [ThreadStatic] private static int craftingDepth; internal static bool IsActive { get { if (pickupDepth <= 0) { return craftingDepth > 0; } return true; } } internal static bool IsCrafting => craftingDepth > 0; internal static void EnterPickup() { pickupDepth++; } internal static void ExitPickup() { if (pickupDepth > 0) { pickupDepth--; } } internal static void EnterCrafting() { craftingDepth++; } internal static void ExitCrafting() { if (craftingDepth > 0) { craftingDepth--; } } } [HarmonyPatch(typeof(Humanoid), "Pickup", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] internal static class HumanoidPickupQuickAutoStackPatch { private static void Prefix() { QuickAutoStackContext.EnterPickup(); } private static Exception? Finalizer(Exception? __exception) { QuickAutoStackContext.ExitPickup(); return __exception; } } [HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[] { typeof(ItemData), typeof(int) })] internal static class InventoryCanAddItemQuickAutoStackPatch { private static void Postfix(Inventory __instance, ItemData item, int stack, ref bool __result) { if (QuickAutoStackContext.IsActive && SlotStateManager.IsMainInventory(__instance)) { int incomingAmount = ((stack <= 0) ? item.m_stack : stack); int? incomingWorldLevel = (QuickAutoStackContext.IsCrafting ? new int?(Game.m_worldLevel) : ((int?)null)); __result = ExistingStackPlanner.CanFit(incomingAmount, SlotStateManager.GetRegularInventoryCapacity(__instance, item, incomingWorldLevel), SlotStateManager.GetExistingQuickStackCapacity(item, incomingWorldLevel)); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] internal static class InventoryAddItemQuickAutoStackPatch { private static bool Prefix(Inventory __instance, ItemData item, ref bool __result) { if (!QuickAutoStackContext.IsActive || !SlotStateManager.IsMainInventory(__instance)) { return true; } SlotStateManager.StackIncomingIntoExistingQuickSlots(item); if (item.m_stack > 0) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(InventoryGui), "RepairOneItem")] internal static class InventoryGuiRepairOneItemPatch { private static void Prefix(out Dictionary? __state) { Inventory gearInventory = SlotStateManager.GearInventory; if (gearInventory == null) { __state = null; return; } __state = new Dictionary(); foreach (ItemData allItem in gearInventory.GetAllItems()) { __state[allItem] = allItem.m_durability; } } private static void Postfix(Dictionary? __state) { if (__state == null) { return; } foreach (KeyValuePair item in __state) { if (item.Key.m_durability > item.Value) { SlotStateManager.MarkChanged(); break; } } } } internal static class ResourceOperationContext { [ThreadStatic] private static int depth; internal static bool IsActive => depth > 0; internal static void Enter() { depth++; } internal static void Exit() { if (depth > 0) { depth--; } } } internal static class ResourcePatchHooks { internal static void Prefix() { ResourceOperationContext.Enter(); } internal static Exception? Finalizer(Exception? exception) { ResourceOperationContext.Exit(); return exception; } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class PlayerHaveCraftingRequirementsPatch { private static void Prefix() { ResourcePatchHooks.Prefix(); } private static Exception? Finalizer(Exception? __exception) { return ResourcePatchHooks.Finalizer(__exception); } } [HarmonyPatch(typeof(Player), "HaveRequirementItems", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class PlayerHaveRequirementItemsPatch { private static void Prefix() { ResourcePatchHooks.Prefix(); } private static Exception? Finalizer(Exception? __exception) { return ResourcePatchHooks.Finalizer(__exception); } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class PlayerHaveBuildingRequirementsPatch { private static void Prefix() { ResourcePatchHooks.Prefix(); } private static Exception? Finalizer(Exception? __exception) { return ResourcePatchHooks.Finalizer(__exception); } } [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] internal static class PlayerConsumeResourcesPatch { private static void Prefix() { ResourcePatchHooks.Prefix(); } private static Exception? Finalizer(Exception? __exception) { return ResourcePatchHooks.Finalizer(__exception); } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] internal static class InventoryGuiSetupRequirementPatch { private static void Prefix() { ResourcePatchHooks.Prefix(); } private static Exception? Finalizer(Exception? __exception) { return ResourcePatchHooks.Finalizer(__exception); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting", new Type[] { typeof(Player) })] internal static class InventoryGuiDoCraftingPatch { private static void Prefix() { ResourcePatchHooks.Prefix(); QuickAutoStackContext.EnterCrafting(); } private static Exception? Finalizer(Exception? __exception) { QuickAutoStackContext.ExitCrafting(); return ResourcePatchHooks.Finalizer(__exception); } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] internal static class TombstoneOpenedRecoveryPatch { private static void Prefix(bool ___m_firstContainerUpdate, out bool __state) { __state = ___m_firstContainerUpdate; } private static void Postfix(Container? ___m_currentContainer, bool ___m_firstContainerUpdate, bool __state) { if (!__state || ___m_firstContainerUpdate || (Object)(object)___m_currentContainer == (Object)null || !TombstoneRecovery.IsTombstone(___m_currentContainer)) { return; } try { TombstoneRecovery.Recover(___m_currentContainer, takeAll: false); } catch (Exception ex) { GearSlotsPlugin.ModLog.LogError((object)("Tombstone recovery did not complete: " + ex)); } } } [HarmonyPatch(typeof(Container), "RPC_TakeAllResponse")] internal static class TombstoneTakeAllRecoveryPatch { private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown List list = instructions.ToList(); MethodInfo moveAll = typeof(Inventory).GetMethod("MoveAll", new Type[1] { typeof(Inventory) }); CodeInstruction[] array = list.Where((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, moveAll)).ToArray(); if (array.Length != 1) { throw new InvalidOperationException("Expected one native Take All inventory move."); } CodeInstruction val = array[0]; int index = list.IndexOf(val); CodeInstruction val2 = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val2.labels.AddRange(val.labels); val2.blocks.AddRange(val.blocks); val.labels.Clear(); val.blocks.Clear(); val.opcode = OpCodes.Call; val.operand = typeof(TombstoneTakeAllRecoveryPatch).GetMethod("MoveAllAfterOwnership", BindingFlags.Static | BindingFlags.NonPublic); list.Insert(index, val2); return list; } private static void MoveAllAfterOwnership(Inventory destination, Inventory source, Container container) { if (!TombstoneRecovery.IsTombstone(container)) { destination.MoveAll(source); } else if (!TombstoneRecovery.Recover(container, takeAll: true)) { throw new InvalidOperationException("Tombstone recovery deferred; leave the grave intact and retry when the player and ownership are ready."); } } } internal static class UpgradeListContext { [ThreadStatic] private static int depth; internal static bool IsActive => depth > 0; internal static void Enter() { depth++; } internal static void Exit() { if (depth > 0) { depth--; } } } internal static class ProtectedUpgradeContext { [ThreadStatic] private static ProtectedUpgradeState? current; internal static ProtectedUpgradeState? Current => current; internal static ProtectedUpgradeState? Enter(ItemData? item) { if (item == null || !SlotStateManager.TryGetSlot(item, out var slot) || !SlotRuleEngine.IsDedicated(slot)) { return null; } current = new ProtectedUpgradeState(item, slot); return current; } internal static void Exit(ProtectedUpgradeState? state) { if (current == state) { current = null; } } } internal sealed class ProtectedUpgradeState { internal ItemData OriginalItem { get; } internal SlotKind Slot { get; } internal ProtectedUpgradeState(ItemData originalItem, SlotKind slot) { OriginalItem = originalItem; Slot = slot; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList", new Type[] { typeof(List) })] internal static class InventoryGuiUpdateRecipeListUpgradePatch { private static void Prefix() { UpgradeListContext.Enter(); } private static Exception? Finalizer(Exception? __exception) { UpgradeListContext.Exit(); return __exception; } } [HarmonyPatch(typeof(Inventory), "GetAllItems", new Type[] { typeof(string), typeof(List) })] internal static class InventoryGetAllItemsUpgradePatch { private static void Postfix(Inventory __instance, string name, List items) { if (UpgradeListContext.IsActive && SlotStateManager.IsMainInventory(__instance)) { SlotStateManager.AddUpgradeCandidates(name, items); } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting", new Type[] { typeof(Player) })] internal static class InventoryGuiProtectedUpgradePatch { private static readonly FieldInfo CraftUpgradeItemField = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem"); private static void Prefix(InventoryGui __instance, out ProtectedUpgradeState? __state) { object? value = CraftUpgradeItemField.GetValue(__instance); __state = ProtectedUpgradeContext.Enter((ItemData?)((value is ItemData) ? value : null)); if (__state != null) { SlotStateManager.BeginMutation(); } } private static Exception? Finalizer(ProtectedUpgradeState? __state, Exception? __exception) { if (__state != null) { ProtectedUpgradeService.EnsureOriginalRecovered(__state); } ProtectedUpgradeContext.Exit(__state); if (__state != null) { SlotStateManager.EndMutation(); } return __exception; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(long), typeof(string), typeof(Vector2i), typeof(bool), typeof(bool), typeof(bool) })] internal static class InventoryAddProtectedUpgradePatch { private static bool Prefix(Inventory __instance, int stack, int quality, int variant, long crafterID, string crafterName, bool cheated, bool pickedUp, ref ItemData? __result) { ProtectedUpgradeState current = ProtectedUpgradeContext.Current; if (current == null || !SlotStateManager.IsMainInventory(__instance)) { return true; } __result = ProtectedUpgradeService.CreateUpgradedItem(current, stack, quality, variant, crafterID, crafterName, cheated, pickedUp); return false; } } } namespace GearSlots.Core { internal static class AuxiliarySplitPolicy { internal static bool ShouldOpen(bool isLeftButton, bool shiftHeld, int stackSize) { if (isLeftButton && shiftHeld) { return stackSize > 1; } return false; } } public enum PanelDirection { Up, Down, Left, Right } public static class DedicatedPanelLayout { public static int GetColumn(SlotKind slot) { EnsureDedicated(slot); if (slot != SlotKind.Utility && slot != SlotKind.Utility2 && slot != SlotKind.Utility3 && slot != SlotKind.Utility4 && slot != SlotKind.Utility5) { return 1; } return 0; } public static int GetRow(SlotKind slot) { switch (slot) { case SlotKind.Head: case SlotKind.Utility: return 0; case SlotKind.Chest: case SlotKind.Utility2: return 1; case SlotKind.Legs: case SlotKind.Utility3: return 2; case SlotKind.Cape: case SlotKind.Utility4: return 3; case SlotKind.Ammo: case SlotKind.Utility5: return 4; default: throw new ArgumentOutOfRangeException("slot"); } } public static int GetNeighborIndex(int index, PanelDirection direction) { if (index < 0 || index >= SlotRuleEngine.DedicatedSlots.Count) { throw new ArgumentOutOfRangeException("index"); } return direction switch { PanelDirection.Up => (new int[10] { 0, 0, 1, 2, 4, 3, 4, 6, 7, 8 })[index], PanelDirection.Down => (new int[10] { 1, 2, 3, 5, 6, 5, 7, 8, 9, 9 })[index], PanelDirection.Left => (new int[10] { 4, 6, 7, 8, 4, 9, 6, 7, 8, 9 })[index], PanelDirection.Right => (new int[10] { 0, 1, 2, 3, 0, 5, 1, 2, 3, 5 })[index], _ => throw new ArgumentOutOfRangeException("direction"), }; } private static void EnsureDedicated(SlotKind slot) { if (!SlotRuleEngine.IsDedicated(slot)) { throw new ArgumentOutOfRangeException("slot"); } } } public static class DuplicateGuard { public static IReadOnlyList FindDuplicateIndices(IReadOnlyList identities) { HashSet hashSet = new HashSet(StringComparer.Ordinal); List list = new List(); for (int i = 0; i < identities.Count; i++) { string text = identities[i]; if (text != null && text.Length > 0 && !hashSet.Add(text)) { list.Add(i); } } return list; } } public enum PendingEquipmentActionResolution { WaitForQueuedAction, SynchronizeWithoutReplay } public static class EquipmentActionPolicy { public static bool ShouldQueueEquipAfterTransfer(bool usesStandardEquipQueue, bool completedEquipWasPreserved, bool isEquippedAfterTransfer) { if (usesStandardEquipQueue && !completedEquipWasPreserved) { return !isEquippedAfterTransfer; } return false; } public static PendingEquipmentActionResolution ResolvePendingEquip(bool actionIsQueued) { if (!actionIsQueued) { return PendingEquipmentActionResolution.SynchronizeWithoutReplay; } return PendingEquipmentActionResolution.WaitForQueuedAction; } public static bool ShouldQueueUnequipAfterTransfer(bool usesStandardEquipQueue, bool wasEquipped, bool transferSucceeded, bool replacementWillEquip) { if (usesStandardEquipQueue && wasEquipped && transferSucceeded) { return !replacementWillEquip; } return false; } } public static class ExistingStackPlanner { public static int GetTransferAmount(int incomingAmount, IEnumerable freeCapacities) { if (freeCapacities == null) { throw new ArgumentNullException("freeCapacities"); } if (incomingAmount <= 0) { return 0; } int num = incomingAmount; foreach (int freeCapacity in freeCapacities) { num -= Math.Min(num, Math.Max(0, freeCapacity)); if (num == 0) { break; } } return incomingAmount - num; } public static bool CanFit(int incomingAmount, int regularCapacity, int existingQuickStackCapacity) { if (incomingAmount > 0) { return (long)Math.Max(0, regularCapacity) + (long)Math.Max(0, existingQuickStackCapacity) >= incomingAmount; } return true; } } public enum ItemCategory { None, Material, Consumable, Weapon, Shield, Helmet, Chest, Ammo, Customization, Legs, Trophy, Torch, Misc, Shoulder, Utility, Tool, Fish, AmmoNonEquipable, Trinket } public static class LoadoutCodec { public static bool ValidName(string name) { if (!string.IsNullOrWhiteSpace(name) && name.Length <= 32) { return name.All((char character) => char.IsLetterOrDigit(character) || character == ' ' || character == '_' || character == '-'); } return false; } public static string Encode(IReadOnlyDictionary> profiles) { if (profiles.Count > 32) { throw new InvalidOperationException("At most 32 named loadouts can be saved."); } using MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true)) { binaryWriter.Write(1); binaryWriter.Write(profiles.Count); foreach (KeyValuePair> item in profiles.OrderBy>, string>((KeyValuePair> pair) => pair.Key, StringComparer.Ordinal)) { if (!ValidName(item.Key) || item.Value.Count > 13) { throw new InvalidDataException("Invalid loadout."); } binaryWriter.Write(item.Key); binaryWriter.Write(item.Value.Count); HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (KeyValuePair item2 in item.Value.OrderBy((KeyValuePair pair) => pair.Key)) { if (!Enum.IsDefined(typeof(SlotKind), item2.Key) || !Guid.TryParseExact(item2.Value, "N", out var _) || !hashSet.Add(item2.Value)) { throw new InvalidDataException("Invalid loadout item."); } binaryWriter.Write((int)item2.Key); binaryWriter.Write(item2.Value); } } } byte[] array = memoryStream.ToArray(); using SHA256 sHA = SHA256.Create(); return Convert.ToBase64String(array.Concat(sHA.ComputeHash(array)).ToArray()); } public static Dictionary> Decode(string? payload) { Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); if (payload == null) { return dictionary; } if (payload.Length > 65536) { throw new InvalidDataException("Loadout payload is too large."); } byte[] array = Convert.FromBase64String(payload); if (array.Length < 40) { throw new InvalidDataException("Loadout payload is truncated."); } byte[] array2 = array.Take(array.Length - 32).ToArray(); using SHA256 sHA = SHA256.Create(); if (!sHA.ComputeHash(array2).SequenceEqual(array.Skip(array2.Length))) { throw new InvalidDataException("Loadout checksum failed."); } using MemoryStream memoryStream = new MemoryStream(array2); using BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8); if (binaryReader.ReadInt32() != 1) { throw new InvalidDataException("Unsupported loadout format."); } int num = binaryReader.ReadInt32(); if (num < 0 || num > 32) { throw new InvalidDataException("Invalid loadout count."); } for (int i = 0; i < num; i++) { string text = binaryReader.ReadString(); int num2 = binaryReader.ReadInt32(); if (!ValidName(text) || dictionary.ContainsKey(text) || num2 < 0 || num2 > 13) { throw new InvalidDataException("Invalid loadout record."); } Dictionary dictionary2 = new Dictionary(); HashSet hashSet = new HashSet(StringComparer.Ordinal); for (int j = 0; j < num2; j++) { SlotKind slotKind = (SlotKind)binaryReader.ReadInt32(); string text2 = binaryReader.ReadString(); if (!Enum.IsDefined(typeof(SlotKind), slotKind) || dictionary2.ContainsKey(slotKind) || !Guid.TryParseExact(text2, "N", out var _) || !hashSet.Add(text2)) { throw new InvalidDataException("Invalid loadout assignment."); } dictionary2.Add(slotKind, text2); } dictionary.Add(text, dictionary2); } if (memoryStream.Position != memoryStream.Length) { throw new InvalidDataException("Unexpected loadout data."); } return dictionary; } } public sealed class LoadoutItem { public string Identity { get; } public int MainCell { get; } public LoadoutItem(string identity, int mainCell) { Identity = identity; MainCell = mainCell; } } public sealed class LoadoutPlan { public IReadOnlyDictionary MainCells { get; } public IReadOnlyDictionary Slots { get; } internal LoadoutPlan(Dictionary main, Dictionary slots) { MainCells = main; Slots = slots; } } public static class LoadoutPlanner { public static LoadoutPlan Plan(IReadOnlyList items, IReadOnlyDictionary desired, int capacity) { if (items == null || desired == null || capacity <= 0) { throw new ArgumentException("Invalid loadout input."); } HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (LoadoutItem item in items) { if (string.IsNullOrWhiteSpace(item.Identity) || !hashSet.Add(item.Identity) || item.MainCell < -1 || item.MainCell >= capacity) { throw new InvalidOperationException("Inventory contains ambiguous identities or invalid positions."); } } Dictionary slots = new Dictionary(StringComparer.Ordinal); foreach (KeyValuePair item2 in desired) { if (!Enum.IsDefined(typeof(SlotKind), item2.Key) || !hashSet.Contains(item2.Value) || slots.ContainsKey(item2.Value)) { throw new InvalidOperationException("A loadout item is missing, duplicated, or in an invalid slot."); } slots.Add(item2.Value, item2.Key); } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); HashSet hashSet2 = new HashSet(); foreach (LoadoutItem item3 in items.Where((LoadoutItem item) => item.MainCell >= 0 && !slots.ContainsKey(item.Identity))) { if (!hashSet2.Add(item3.MainCell)) { throw new InvalidOperationException("Main inventory contains overlapping items."); } dictionary.Add(item3.Identity, item3.MainCell); } foreach (LoadoutItem item4 in items.Where((LoadoutItem item) => item.MainCell < 0 && !slots.ContainsKey(item.Identity))) { int num; for (num = 0; num < capacity && hashSet2.Contains(num); num++) { } if (num == capacity) { throw new InvalidOperationException("Make room in the main inventory before switching or returning all items."); } hashSet2.Add(num); dictionary.Add(item4.Identity, num); } return new LoadoutPlan(dictionary, slots); } } public static class LoadoutTransaction { public static bool Execute(Action apply, Action restore) { try { apply(); return true; } catch (Exception ex) { try { restore(); } catch (Exception ex2) { throw new AggregateException("Loadout recovery failed; writes must remain blocked.", ex, ex2); } return false; } } } public readonly struct MainInventoryOrigin { public int X { get; } public int Y { get; } public MainInventoryOrigin(int x, int y) { X = x; Y = y; } } public static class MainInventoryOriginCodec { public const int CurrentVersion = 1; public static string Encode(int x, int y) { if (x < 0) { throw new ArgumentOutOfRangeException("x"); } if (y < 0) { throw new ArgumentOutOfRangeException("y"); } return string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", 1, x, y); } public static bool TryDecode(string? value, out MainInventoryOrigin origin) { origin = default(MainInventoryOrigin); if (string.IsNullOrWhiteSpace(value)) { return false; } string[] array = value.Split(new char[1] { ':' }); if (array.Length != 3 || !int.TryParse(array[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result != 1 || !int.TryParse(array[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(array[2], NumberStyles.None, CultureInfo.InvariantCulture, out var result3) || result2 < 0 || result3 < 0) { return false; } origin = new MainInventoryOrigin(result2, result3); return true; } } public enum MainInventoryRecoveryMode { ExactSlot, FirstAvailable } public readonly struct MainInventoryRecoveryStep { public int CandidateIndex { get; } public MainInventoryRecoveryMode Mode { get; } public MainInventoryRecoveryStep(int candidateIndex, MainInventoryRecoveryMode mode) { CandidateIndex = candidateIndex; Mode = mode; } } public static class MainInventoryRecoveryPlanner { public static IReadOnlyList Plan(IReadOnlyList candidates, int width, int height, IEnumerable occupiedCells) { if (width <= 0) { throw new ArgumentOutOfRangeException("width"); } if (height <= 0) { throw new ArgumentOutOfRangeException("height"); } HashSet hashSet = new HashSet(occupiedCells); List list = new List(); List list2 = new List(); for (int i = 0; i < candidates.Count; i++) { MainInventoryOrigin mainInventoryOrigin = candidates[i]; if (mainInventoryOrigin.X < width && mainInventoryOrigin.Y < height) { int item = mainInventoryOrigin.Y * width + mainInventoryOrigin.X; if (hashSet.Add(item)) { list.Add(new MainInventoryRecoveryStep(i, MainInventoryRecoveryMode.ExactSlot)); continue; } } list2.Add(new MainInventoryRecoveryStep(i, MainInventoryRecoveryMode.FirstAvailable)); } list.Sort(delegate(MainInventoryRecoveryStep left, MainInventoryRecoveryStep right) { MainInventoryOrigin mainInventoryOrigin2 = candidates[left.CandidateIndex]; MainInventoryOrigin mainInventoryOrigin3 = candidates[right.CandidateIndex]; int num = (mainInventoryOrigin2.Y * width + mainInventoryOrigin2.X).CompareTo(mainInventoryOrigin3.Y * width + mainInventoryOrigin3.X); return (num == 0) ? left.CandidateIndex.CompareTo(right.CandidateIndex) : num; }); list.AddRange(list2); return list; } } public enum QuickHudOrientation { Horizontal, Vertical } public enum RecoveryDestination { KeepInSlot, MainInventory, DropAtPlayer } public sealed class RecoveryCandidate { public SlotKind Slot { get; } public bool SlotEnabled { get; } public RecoveryCandidate(SlotKind slot, bool slotEnabled) { Slot = slot; SlotEnabled = slotEnabled; } } public static class RecoveryPlanner { public static IReadOnlyList Plan(IReadOnlyList candidates, int availableMainInventorySlots) { RecoveryDestination[] array = new RecoveryDestination[candidates.Count]; int num = availableMainInventorySlots; for (int i = 0; i < candidates.Count; i++) { if (candidates[i].SlotEnabled) { array[i] = RecoveryDestination.KeepInSlot; } else if (num > 0) { array[i] = RecoveryDestination.MainInventory; num--; } else { array[i] = RecoveryDestination.DropAtPlayer; } } return array; } } public static class RepairRuleEngine { public static bool IsCandidate(bool usesDurability, float durability, float maximumDurability) { if (usesDurability) { return durability < maximumDurability; } return false; } } public static class ShortcutLabelFormatter { public static string Format(string mainKey, IEnumerable modifiers) { if (mainKey == null) { throw new ArgumentNullException("mainKey"); } if (modifiers == null) { throw new ArgumentNullException("modifiers"); } List list = (from value in modifiers.Select(FormatKey) where value.Length > 0 select value).Distinct(StringComparer.Ordinal).ToList(); list.Add(FormatKey(mainKey)); return string.Join("+", list); } private static string FormatKey(string key) { if (key.StartsWith("Alpha", StringComparison.Ordinal) && key.Length == 6 && char.IsDigit(key[5])) { return key.Substring(5, 1); } if (key.StartsWith("Keypad", StringComparison.Ordinal) && key.Length == 7 && char.IsDigit(key[6])) { return "Num" + key.Substring(6, 1); } switch (key) { case "LeftAlt": case "RightAlt": case "AltGr": return "Alt"; case "LeftControl": case "RightControl": return "Ctrl"; case "LeftShift": case "RightShift": return "Shift"; case "LeftCommand": case "RightCommand": return "Cmd"; case "LeftWindows": case "RightWindows": return "Win"; case "Return": return "Enter"; case "Escape": return "Esc"; default: return key; } } } internal static class SlotDisplayName { internal static string For(SlotKind slot) { return slot switch { SlotKind.Head => "Head", SlotKind.Chest => "Chest", SlotKind.Legs => "Legs", SlotKind.Cape => "Cape", SlotKind.Utility => "Utility 1", SlotKind.Utility2 => "Utility 2", SlotKind.Utility3 => "Utility 3", SlotKind.Utility4 => "Utility 4", SlotKind.Utility5 => "Utility 5", SlotKind.Ammo => "Ammo", SlotKind.Quick1 => "Quick 1", SlotKind.Quick2 => "Quick 2", SlotKind.Quick3 => "Quick 3", _ => slot.ToString(), }; } } public enum SlotKind { Head, Chest, Legs, Cape, Utility, Ammo, Quick1, Quick2, Quick3, Utility2, Utility3, Utility4, Utility5 } public readonly struct SlotPanelPlacement { public float GearX { get; } public float GearY { get; } public float QuickX { get; } public float QuickY { get; } public SlotPanelPlacement(float gearX, float gearY, float quickX, float quickY) { GearX = gearX; GearY = gearY; QuickX = quickX; QuickY = quickY; } } public readonly struct HorizontalHudPlacement { public float FirstCellCenterX { get; } public float CellCenterY { get; } public float CellWidth { get; } public float CellHeight { get; } public HorizontalHudPlacement(float firstCellCenterX, float cellCenterY, float cellWidth, float cellHeight) { FirstCellCenterX = firstCellCenterX; CellCenterY = cellCenterY; CellWidth = cellWidth; CellHeight = cellHeight; } } public static class SlotPanelLayout { public static bool ShouldShowAuxiliaryPanels(bool inventoryVisible, bool skillsPanelOpen) { if (inventoryVisible) { return !skillsPanelOpen; } return false; } public static HorizontalHudPlacement HorizontalBesideBox(float boxLeft, float boxRight, float boxBottom, float boxTop, float gap, float horizontalAdjustment, float verticalAdjustment) { float num = boxRight - boxLeft; float num2 = boxTop - boxBottom; if (num <= 0f) { throw new ArgumentOutOfRangeException("boxRight"); } if (num2 <= 0f) { throw new ArgumentOutOfRangeException("boxTop"); } return new HorizontalHudPlacement(boxRight + gap + num * 0.5f + horizontalAdjustment, (boxBottom + boxTop) * 0.5f + verticalAdjustment, num, num2); } public static float GetHorizontalQuickElementX(int index, int count, float spacing) { if (index < 0 || index >= count) { throw new ArgumentOutOfRangeException("index"); } return (float)index * spacing; } public static float GetCenteredVerticalQuickElementY(int index, int count, float spacing) { if (index < 0 || index >= count) { throw new ArgumentOutOfRangeException("index"); } return ((float)(count - 1) * 0.5f - (float)index) * spacing; } public static SlotPanelPlacement QuickBelowDedicated(float gearX, float gearY, float gearHeight, float scale, float horizontalAdjustment, float verticalAdjustment) { return new SlotPanelPlacement(gearX, gearY, gearX + horizontalAdjustment, gearY - gearHeight * scale + verticalAdjustment); } public static SlotPanelPlacement BelowInventory(float panelLeft, float panelBottom, float gearWidth, float scale, float horizontalAdjustment, float verticalAdjustment, float gap) { float num = panelLeft + horizontalAdjustment; float num2 = panelBottom + verticalAdjustment; return new SlotPanelPlacement(num, num2, num + gearWidth * scale + gap, num2); } public static SlotPanelPlacement ClampToViewport(SlotPanelPlacement placement, float totalWidth, float rowHeight, float viewportLeft, float viewportBottom, float viewportRight, float viewportTop, float padding) { float minimum = viewportLeft + padding; float maximum = viewportRight - totalWidth - padding; float minimum2 = viewportBottom + rowHeight + padding; float maximum2 = viewportTop - padding; float num = Clamp(placement.GearX, minimum, maximum); float num2 = Clamp(placement.GearY, minimum2, maximum2); return new SlotPanelPlacement(num, num2, num + (placement.QuickX - placement.GearX), num2); } private static float Clamp(float value, float minimum, float maximum) { if (maximum < minimum) { return minimum; } if (value < minimum) { return minimum; } if (!(value > maximum)) { return value; } return maximum; } } public static class SlotPayloadCodec { public const int CurrentVersion = 1; private const int Magic = 1414288199; private const int HashLength = 32; private const int MaximumInventoryBytes = 4194304; public static string Encode(SlotSaveEnvelope envelope) { if (envelope == null) { throw new ArgumentNullException("envelope"); } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(1414288199); binaryWriter.Write(1); binaryWriter.Write(envelope.Sequence); binaryWriter.Write(envelope.TransactionId.ToByteArray()); WriteBytes(binaryWriter, envelope.GearInventory); WriteBytes(binaryWriter, envelope.QuickInventory); binaryWriter.Flush(); array = memoryStream.ToArray(); } byte[] array2; using (SHA256 sHA = SHA256.Create()) { array2 = sHA.ComputeHash(array); } byte[] array3 = new byte[array.Length + array2.Length]; Buffer.BlockCopy(array, 0, array3, 0, array.Length); Buffer.BlockCopy(array2, 0, array3, array.Length, array2.Length); return Convert.ToBase64String(array3); } public static bool TryDecode(string encoded, out SlotSaveEnvelope? envelope, out string error) { envelope = null; error = string.Empty; if (string.IsNullOrWhiteSpace(encoded)) { error = "The slot payload is empty."; return false; } byte[] array; try { array = Convert.FromBase64String(encoded); } catch (FormatException) { error = "The slot payload is not valid Base64."; return false; } if (array.Length <= 32) { error = "The slot payload is truncated."; return false; } int num = array.Length - 32; byte[] array2 = new byte[num]; byte[] array3 = new byte[32]; Buffer.BlockCopy(array, 0, array2, 0, num); Buffer.BlockCopy(array, num, array3, 0, 32); byte[] right; using (SHA256 sHA = SHA256.Create()) { right = sHA.ComputeHash(array2); } if (!FixedTimeEquals(array3, right)) { error = "The slot payload checksum does not match."; return false; } try { using MemoryStream memoryStream = new MemoryStream(array2, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream); if (binaryReader.ReadInt32() != 1414288199) { error = "The slot payload has an unknown header."; return false; } int num2 = binaryReader.ReadInt32(); if (num2 != 1) { error = $"Slot payload version {num2} is not supported by this release."; return false; } long sequence = binaryReader.ReadInt64(); Guid transactionId = new Guid(binaryReader.ReadBytes(16)); byte[] gearInventory = ReadBytes(binaryReader); byte[] quickInventory = ReadBytes(binaryReader); if (memoryStream.Position != memoryStream.Length) { error = "The slot payload contains unexpected trailing data."; return false; } envelope = new SlotSaveEnvelope(sequence, transactionId, gearInventory, quickInventory); return true; } catch (EndOfStreamException) { error = "The slot payload ended unexpectedly."; return false; } catch (IOException ex3) { error = "The slot payload could not be read: " + ex3.Message; return false; } catch (ArgumentException ex4) { error = "The slot payload contains an invalid value: " + ex4.Message; return false; } } private static void WriteBytes(BinaryWriter writer, byte[] value) { if (value.Length > 4194304) { throw new InvalidDataException("An inventory payload is larger than the safety limit."); } writer.Write(value.Length); writer.Write(value); } private static byte[] ReadBytes(BinaryReader reader) { int num = reader.ReadInt32(); if (num < 0 || num > 4194304) { throw new InvalidDataException("An inventory payload length is outside the safety limit."); } byte[] array = reader.ReadBytes(num); if (array.Length != num) { throw new EndOfStreamException(); } return array; } private static bool FixedTimeEquals(byte[] left, byte[] right) { if (left.Length != right.Length) { return false; } int num = 0; for (int i = 0; i < left.Length; i++) { num |= left[i] ^ right[i]; } return num == 0; } } public static class SlotRuleEngine { private static readonly SlotKind[] DedicatedSlotValues = new SlotKind[10] { SlotKind.Head, SlotKind.Chest, SlotKind.Legs, SlotKind.Cape, SlotKind.Utility, SlotKind.Ammo, SlotKind.Utility2, SlotKind.Utility3, SlotKind.Utility4, SlotKind.Utility5 }; private static readonly SlotKind[] UtilitySlotValues = new SlotKind[5] { SlotKind.Utility, SlotKind.Utility2, SlotKind.Utility3, SlotKind.Utility4, SlotKind.Utility5 }; public static IReadOnlyList DedicatedSlots => DedicatedSlotValues; public static IReadOnlyList UtilitySlots => UtilitySlotValues; public static bool IsDedicated(SlotKind slot) { if (slot < SlotKind.Head || slot > SlotKind.Ammo) { if (slot >= SlotKind.Utility2) { return slot <= SlotKind.Utility5; } return false; } return true; } public static bool IsQuick(SlotKind slot) { if (slot >= SlotKind.Quick1) { return slot <= SlotKind.Quick3; } return false; } public static bool UsesStandardEquipQueue(SlotKind slot) { if (slot >= SlotKind.Head) { return slot <= SlotKind.Cape; } return false; } public static int GetDedicatedPosition(SlotKind slot) { switch (slot) { case SlotKind.Head: case SlotKind.Chest: case SlotKind.Legs: case SlotKind.Cape: case SlotKind.Utility: case SlotKind.Ammo: return (int)slot; case SlotKind.Utility2: return 6; case SlotKind.Utility3: return 7; case SlotKind.Utility4: return 8; case SlotKind.Utility5: return 9; default: throw new ArgumentOutOfRangeException("slot"); } } public static SlotKind GetDedicatedSlotAtPosition(int position) { switch (position) { case 0: case 1: case 2: case 3: case 4: case 5: return (SlotKind)position; case 6: return SlotKind.Utility2; case 7: return SlotKind.Utility3; case 8: return SlotKind.Utility4; case 9: return SlotKind.Utility5; default: throw new ArgumentOutOfRangeException("position"); } } public static bool Accepts(SlotKind slot, ItemCategory category, bool hasAmmoType, bool isEquipable, bool isUtilityKey = false) { switch (slot) { case SlotKind.Head: return category == ItemCategory.Helmet; case SlotKind.Chest: return category == ItemCategory.Chest; case SlotKind.Legs: return category == ItemCategory.Legs; case SlotKind.Cape: return category == ItemCategory.Shoulder; case SlotKind.Utility: case SlotKind.Utility2: case SlotKind.Utility3: case SlotKind.Utility4: case SlotKind.Utility5: return category == ItemCategory.Utility || category == ItemCategory.Trinket || isUtilityKey; case SlotKind.Ammo: if (category != ItemCategory.Ammo && category != ItemCategory.AmmoNonEquipable) { return category == ItemCategory.Consumable && hasAmmoType; } return true; case SlotKind.Quick1: case SlotKind.Quick2: case SlotKind.Quick3: return IsNormallyUsable(category, isEquipable); default: return false; } } private static bool IsNormallyUsable(ItemCategory category, bool isEquipable) { if (isEquipable) { return true; } switch (category) { case ItemCategory.Consumable: case ItemCategory.Torch: case ItemCategory.Misc: case ItemCategory.Utility: case ItemCategory.Tool: case ItemCategory.Fish: case ItemCategory.Trinket: return true; default: return false; } } } public sealed class SlotSaveEnvelope { public long Sequence { get; } public Guid TransactionId { get; } public byte[] GearInventory { get; } public byte[] QuickInventory { get; } public SlotSaveEnvelope(long sequence, Guid transactionId, byte[] gearInventory, byte[] quickInventory) { Sequence = sequence; TransactionId = transactionId; GearInventory = gearInventory ?? throw new ArgumentNullException("gearInventory"); QuickInventory = quickInventory ?? throw new ArgumentNullException("quickInventory"); } } internal static class TombstoneRecoveryFlow { internal static bool Execute(bool ownsContainer, bool playerReady, bool playerAlive, Action transfer, Action restore, Action block, Action complete) { if (!ownsContainer || !playerReady || !playerAlive) { return false; } try { transfer(); } catch (Exception ex) { try { restore(); } catch (Exception ex2) { block(); throw new AggregateException("Tombstone recovery rollback failed; preserve the character and grave.", ex, ex2); } return false; } complete(); return true; } } public sealed class TransferGate { private readonly HashSet activeIdentities = new HashSet(StringComparer.Ordinal); public bool TryEnter(string identity) { if (string.IsNullOrWhiteSpace(identity)) { throw new ArgumentException("An item identity is required.", "identity"); } return activeIdentities.Add(identity); } public void Exit(string identity) { activeIdentities.Remove(identity); } } } namespace GearSlots.Configuration { internal static class ConfigFileMigration { internal const string CurrentFileName = "jg224.gearslots.cfg"; internal const string LegacyFileName = "com.jg224.gearslots.cfg"; internal static ConfigFile Open(BaseUnityPlugin plugin, string configDirectory, ManualLogSource log) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (MoveLegacy(configDirectory) && log != null) { log.LogInfo((object)"Renamed legacy config com.jg224.gearslots.cfg to jg224.gearslots.cfg."); } return PluginConfigFiles.Attach(plugin, new ConfigFile(Path.Combine(configDirectory, "jg224.gearslots.cfg"), true, plugin.Info.Metadata)); } internal static bool MoveLegacy(string configDirectory) { Directory.CreateDirectory(configDirectory); if (ExactPath(configDirectory, "jg224.gearslots.cfg") != null) { return false; } string text = ExactPath(configDirectory, "com.jg224.gearslots.cfg"); if (text == null) { return false; } File.Move(text, Path.Combine(configDirectory, "jg224.gearslots.cfg")); return true; } private static string? ExactPath(string directory, string fileName) { return Directory.EnumerateFiles(directory, "*.cfg", SearchOption.TopDirectoryOnly).FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } internal sealed class GearSlotsConfig { internal ConfigEntry HeadEnabled { get; } internal ConfigEntry ChestEnabled { get; } internal ConfigEntry LegsEnabled { get; } internal ConfigEntry CapeEnabled { get; } internal ConfigEntry UtilityEnabled { get; } internal ConfigEntry Utility2Enabled { get; } internal ConfigEntry Utility3Enabled { get; } internal ConfigEntry Utility4Enabled { get; } internal ConfigEntry Utility5Enabled { get; } internal ConfigEntry AmmoEnabled { get; } internal ConfigEntry Quick1Key { get; } internal ConfigEntry Quick2Key { get; } internal ConfigEntry Quick3Key { get; } internal ConfigEntry LayoutVersion { get; } internal ConfigEntry UiOffsetX { get; } internal ConfigEntry UiOffsetY { get; } internal ConfigEntry InventoryQuickOffsetX { get; } internal ConfigEntry InventoryQuickOffsetY { get; } internal ConfigEntry QuickHudOrientation { get; } internal ConfigEntry QuickHudOffsetX { get; } internal ConfigEntry QuickHudOffsetY { get; } internal ConfigEntry UiScale { get; } internal ConfigEntry HideEmptyLabels { get; } internal event Action? Changed; internal GearSlotsConfig(ConfigFile file) { //IL_00ce: 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_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown LayoutVersion = file.Bind("Interface", "Layout version", 0, "Internal layout migration marker. GearSlots updates this automatically."); HeadEnabled = BindSlot(file, SlotKind.Head, defaultValue: true); ChestEnabled = BindSlot(file, SlotKind.Chest, defaultValue: true); LegsEnabled = BindSlot(file, SlotKind.Legs, defaultValue: true); CapeEnabled = BindSlot(file, SlotKind.Cape, defaultValue: true); UtilityEnabled = BindSlot(file, SlotKind.Utility, defaultValue: true); Utility2Enabled = BindSlot(file, SlotKind.Utility2, defaultValue: true); Utility3Enabled = BindSlot(file, SlotKind.Utility3, defaultValue: true); Utility4Enabled = BindSlot(file, SlotKind.Utility4, defaultValue: true); Utility5Enabled = BindSlot(file, SlotKind.Utility5, defaultValue: true); AmmoEnabled = BindSlot(file, SlotKind.Ammo, defaultValue: true); Quick1Key = file.Bind("Quick slots", "Quick slot 1 key", new KeyboardShortcut((KeyCode)49, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Uses the first quick-slot item through Valheim's normal item-use path."); Quick2Key = file.Bind("Quick slots", "Quick slot 2 key", new KeyboardShortcut((KeyCode)50, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Uses the second quick-slot item through Valheim's normal item-use path."); Quick3Key = file.Bind("Quick slots", "Quick slot 3 key", new KeyboardShortcut((KeyCode)51, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Uses the third quick-slot item through Valheim's normal item-use path."); UiOffsetX = file.Bind("Interface", "Horizontal offset", 180f, "Horizontal adjustment in Valheim UI canvas units from the upper-right edge of the visible player inventory background."); UiOffsetY = file.Bind("Interface", "Vertical offset", 0f, "Vertical adjustment in Valheim UI canvas units from the upper-right edge of the visible player inventory background."); InventoryQuickOffsetX = file.Bind("Interface", "Inventory quick-slot horizontal offset", 0f, "Horizontal adjustment for the drag-enabled quick slots beneath the dedicated GearSlots panel."); InventoryQuickOffsetY = file.Bind("Interface", "Inventory quick-slot vertical offset", -12f, "Vertical adjustment for the drag-enabled quick slots beneath the dedicated GearSlots panel."); QuickHudOrientation = file.Bind("Interface", "Quick HUD orientation", GearSlots.Core.QuickHudOrientation.Horizontal, "Horizontal places Quick 1-3 left-to-right beside the boss-power box. Vertical places them top-to-bottom."); QuickHudOffsetX = file.Bind("Interface", "Quick HUD horizontal offset", 0f, "Editable X coordinate offset in Valheim UI canvas units from the right side of the guardian-power box."); QuickHudOffsetY = file.Bind("Interface", "Quick HUD vertical offset", 0f, "Editable Y coordinate offset in Valheim UI canvas units from the vertical center of the guardian-power box."); UiScale = file.Bind("Interface", "Scale", 0.9f, new ConfigDescription("Scale applied to the dedicated slots and inventory quick slots. The gameplay quick HUD matches the live guardian-power box.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1.5f), Array.Empty())); HideEmptyLabels = file.Bind("Interface", "Hide empty slot labels", false, "Hides empty text labels. GearSlots does not use placeholder icons for empty dedicated cells."); if (LayoutVersion.Value < 2) { UiOffsetX.Value = 0f; UiOffsetY.Value = -12f; QuickHudOffsetX.Value = 0f; QuickHudOffsetY.Value = -72f; LayoutVersion.Value = 2; } if (LayoutVersion.Value < 3) { LayoutVersion.Value = 3; } if (LayoutVersion.Value < 4) { UiOffsetX.Value = 12f; UiOffsetY.Value = 0f; InventoryQuickOffsetX.Value = 0f; InventoryQuickOffsetY.Value = -12f; LayoutVersion.Value = 4; } if (LayoutVersion.Value < 5) { UiOffsetX.Value = 180f; UiOffsetY.Value = 0f; LayoutVersion.Value = 5; } if (LayoutVersion.Value < 6) { InventoryQuickOffsetX.Value = 0f; InventoryQuickOffsetY.Value = -12f; LayoutVersion.Value = 6; } if (LayoutVersion.Value < 7) { QuickHudOffsetX.Value = 0f; QuickHudOffsetY.Value = 0f; LayoutVersion.Value = 7; } if (LayoutVersion.Value < 8) { QuickHudOffsetX.Value = 0f; QuickHudOffsetY.Value = 0f; LayoutVersion.Value = 8; } if (LayoutVersion.Value < 9) { QuickHudOrientation.Value = GearSlots.Core.QuickHudOrientation.Horizontal; QuickHudOffsetX.Value = 0f; QuickHudOffsetY.Value = 0f; LayoutVersion.Value = 9; } file.SettingChanged += OnSettingChanged; } internal bool IsEnabled(SlotKind slot) { return slot switch { SlotKind.Head => HeadEnabled.Value, SlotKind.Chest => ChestEnabled.Value, SlotKind.Legs => LegsEnabled.Value, SlotKind.Cape => CapeEnabled.Value, SlotKind.Utility => UtilityEnabled.Value, SlotKind.Utility2 => Utility2Enabled.Value, SlotKind.Utility3 => Utility3Enabled.Value, SlotKind.Utility4 => Utility4Enabled.Value, SlotKind.Utility5 => Utility5Enabled.Value, SlotKind.Ammo => AmmoEnabled.Value, _ => true, }; } internal KeyboardShortcut GetQuickKey(int index) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) return (KeyboardShortcut)(index switch { 0 => Quick1Key.Value, 1 => Quick2Key.Value, 2 => Quick3Key.Value, _ => throw new ArgumentOutOfRangeException("index"), }); } private static ConfigEntry BindSlot(ConfigFile file, SlotKind slot, bool defaultValue) { string text = slot switch { SlotKind.Utility5 => "Utility 5", SlotKind.Utility4 => "Utility 4", SlotKind.Utility3 => "Utility 3", SlotKind.Utility2 => "Utility 2", _ => slot.ToString(), }; return file.Bind("Dedicated slots", text + " enabled", defaultValue, "Enables the " + text + " dedicated slot. Disabling it safely returns its item to inventory or drops it at the player when full."); } private void OnSettingChanged(object sender, EventArgs eventArgs) { this.Changed?.Invoke(); } } }