From 9dfa0ec7aaeb19c55bcbcc3fdd1d3604cf640ae5 Mon Sep 17 00:00:00 2001 From: Zeffuro Date: Wed, 24 Dec 2025 19:03:15 +0100 Subject: [PATCH] Working inventory but with debug stuff --- .../Extensions/InventoryItemExtensions.cs | 8 +++++ .../Extensions/InventoryTypeExtensions.cs | 35 ++++++++++++++++++- .../ItemOrderModuleSorterExtensions.cs | 26 ++++++++++++++ AetherBags/Inventory/ItemInfo.cs | 1 + AetherBags/Nodes/InventoryCategoryNode.cs | 14 ++++++-- AetherBags/Plugin.cs | 34 ++++++++++++++++-- AetherBags/Services.cs | 3 ++ 7 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 AetherBags/Extensions/ItemOrderModuleSorterExtensions.cs diff --git a/AetherBags/Extensions/InventoryItemExtensions.cs b/AetherBags/Extensions/InventoryItemExtensions.cs index 634fc69..7189894 100644 --- a/AetherBags/Extensions/InventoryItemExtensions.cs +++ b/AetherBags/Extensions/InventoryItemExtensions.cs @@ -2,6 +2,7 @@ using System.Text.RegularExpressions; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using FFXIVClientStructs.FFXIV.Client.UI.Misc; using Lumina.Excel.Sheets; using Lumina.Text.ReadOnly; @@ -62,6 +63,13 @@ public static unsafe class InventoryItemExtensions { return null; } + public ItemOrderModuleSorterItemEntry* GetItemOrderData() + { + InventoryType type = item.GetInventoryType(); + int slot = item.GetSlot(); + return type.GetInventorySorter->Items[slot + type.GetInventoryStartIndex]; + } + public bool IsRegexMatch(string searchString) { // Skip any data access if string is empty if (searchString.IsNullOrEmpty()) return true; diff --git a/AetherBags/Extensions/InventoryTypeExtensions.cs b/AetherBags/Extensions/InventoryTypeExtensions.cs index ea189f0..a703d96 100644 --- a/AetherBags/Extensions/InventoryTypeExtensions.cs +++ b/AetherBags/Extensions/InventoryTypeExtensions.cs @@ -1,8 +1,10 @@ +using System; using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.UI.Misc; namespace AetherBags.Extensions; -public static class InventoryTypeExtensions +public static unsafe class InventoryTypeExtensions { extension(InventoryType inventoryType) { @@ -61,5 +63,36 @@ public static class InventoryTypeExtensions 72 => InventoryType.PremiumSaddleBag2, _ => (InventoryType)0 }; + + public ItemOrderModuleSorter* GetInventorySorter => inventoryType switch { + InventoryType.Inventory1 => ItemOrderModule.Instance()->InventorySorter, + InventoryType.Inventory2 => ItemOrderModule.Instance()->InventorySorter, + InventoryType.Inventory3 => ItemOrderModule.Instance()->InventorySorter, + InventoryType.Inventory4 => ItemOrderModule.Instance()->InventorySorter, + InventoryType.ArmoryMainHand => ItemOrderModule.Instance()->ArmouryMainHandSorter, + InventoryType.ArmoryOffHand => ItemOrderModule.Instance()->ArmouryOffHandSorter, + InventoryType.ArmoryHead => ItemOrderModule.Instance()->ArmouryHeadSorter, + InventoryType.ArmoryBody => ItemOrderModule.Instance()->ArmouryBodySorter, + InventoryType.ArmoryHands => ItemOrderModule.Instance()->ArmouryHandsSorter, + InventoryType.ArmoryLegs => ItemOrderModule.Instance()->ArmouryLegsSorter, + InventoryType.ArmoryFeets => ItemOrderModule.Instance()->ArmouryFeetSorter, + InventoryType.ArmoryEar => ItemOrderModule.Instance()->ArmouryEarsSorter, + InventoryType.ArmoryNeck => ItemOrderModule.Instance()->ArmouryNeckSorter, + InventoryType.ArmoryWrist => ItemOrderModule.Instance()->ArmouryWristsSorter, + InventoryType.ArmoryRings => ItemOrderModule.Instance()->ArmouryRingsSorter, + InventoryType.ArmorySoulCrystal => ItemOrderModule.Instance()->ArmourySoulCrystalSorter, + InventoryType.SaddleBag1 => ItemOrderModule.Instance()->SaddleBagSorter, + InventoryType.SaddleBag2 => ItemOrderModule.Instance()->SaddleBagSorter, + InventoryType.PremiumSaddleBag1 => ItemOrderModule.Instance()->PremiumSaddleBagSorter, + InventoryType.PremiumSaddleBag2 => ItemOrderModule.Instance()->PremiumSaddleBagSorter, + _ => throw new Exception($"Type Not Implemented: {inventoryType}"), + }; + + public int GetInventoryStartIndex => inventoryType switch { + InventoryType.Inventory2 => inventoryType.GetInventorySorter->ItemsPerPage, + InventoryType.Inventory3 => inventoryType.GetInventorySorter->ItemsPerPage * 2, + InventoryType.Inventory4 => inventoryType.GetInventorySorter->ItemsPerPage * 3, + _ => 0, + }; } } \ No newline at end of file diff --git a/AetherBags/Extensions/ItemOrderModuleSorterExtensions.cs b/AetherBags/Extensions/ItemOrderModuleSorterExtensions.cs new file mode 100644 index 0000000..11fbe06 --- /dev/null +++ b/AetherBags/Extensions/ItemOrderModuleSorterExtensions.cs @@ -0,0 +1,26 @@ +using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.UI.Misc; + +namespace AetherBags.Extensions; + +public static unsafe class ItemOrderModuleSorterExtensions { + extension(ref ItemOrderModuleSorter sorter) { + public long GetSlotIndex(ItemOrderModuleSorterItemEntry* entry) + => entry->Slot + sorter.ItemsPerPage * entry->Page; + + public InventoryItem* GetInventoryItem(ItemOrderModuleSorterItemEntry* entry) + => sorter.GetInventoryItem(sorter.GetSlotIndex(entry)); + + public InventoryItem* GetInventoryItem(long slotIndex) { + if (sorter.Items.LongCount <= slotIndex) return null; + + var item = sorter.Items[slotIndex].Value; + if (item == null) return null; + + var container = InventoryManager.Instance()->GetInventoryContainer(sorter.InventoryType + item->Page); + if (container == null) return null; + + return container->GetInventorySlot(item->Slot); + } + } +} diff --git a/AetherBags/Inventory/ItemInfo.cs b/AetherBags/Inventory/ItemInfo.cs index 83fca5f..0047377 100644 --- a/AetherBags/Inventory/ItemInfo.cs +++ b/AetherBags/Inventory/ItemInfo.cs @@ -5,6 +5,7 @@ using Lumina.Excel.Sheets; using System; using System.Numerics; using System.Text.RegularExpressions; +using FFXIVClientStructs.FFXIV.Client.UI.Misc; namespace AetherBags.Inventory; diff --git a/AetherBags/Nodes/InventoryCategoryNode.cs b/AetherBags/Nodes/InventoryCategoryNode.cs index 5e3eb7a..f1a0fdf 100644 --- a/AetherBags/Nodes/InventoryCategoryNode.cs +++ b/AetherBags/Nodes/InventoryCategoryNode.cs @@ -8,6 +8,7 @@ using KamiToolKit.Nodes; using System; using System.Numerics; using FFXIVClientStructs.FFXIV.Client.UI; +using FFXIVClientStructs.FFXIV.Client.UI.Misc; // TODO: Switch back to CS version when Dalamud Updated using DragDropFixedNode = AetherBags.Nodes.DragDropNode; @@ -288,13 +289,20 @@ public class InventoryCategoryNode : SimpleComponentNode private unsafe void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo itemInfo) { if (payload.Type != DragDropType.Item) return; - Services.Logger.Debug($"Inventory DragDropNode Payload Accepted: {payload.Type} Int1: {payload.Int1} Int2: {payload.Int2}"); + InventoryItem item = itemInfo.Item; + Services.Logger.Debug($"Inventory DragDropNode Payload Accepted: {payload.Type} Int1: {payload.Int1} Int2: {payload.Int2} ReferenceIndex: {payload.ReferenceIndex}"); InventoryType inventoryType = InventoryType.GetInventoryTypeFromContainerId(payload.Int1); ushort sourceSlot = (ushort)payload.Int2; - System.AddonInventoryWindow.ManualInventoryRefresh(); + ItemOrderModuleSorterItemEntry* itemEntry = item.GetItemOrderData(); + Services.Logger.Debug($"{item.Slot} vs {item.GetSlot()}: entry: {itemEntry->Slot}"); + Services.Logger.Info($"[OnPayload] Moving {inventoryType}@{sourceSlot} -> {item.Container}@{item.Slot} -> {item.Name.ExtractText()}"); + InventoryManager.Instance()->MoveItemSlot(inventoryType, sourceSlot, item.Container, item.GetSlot(), true); + + + // System.AddonInventoryWindow.ManualInventoryRefresh(); + // Should work for swapping item but need a fake empty slot to put new items in probably. // Services.Logger.Debug($"Moving Item from {inventoryType} Slot {sourceSlot} to {itemInfo.Item.Container} Slot {itemInfo.Item.GetSlot()}"); - InventoryManager.Instance()->MoveItemSlot(inventoryType, sourceSlot, itemInfo.Item.Container, itemInfo.Item.GetSlot(), false); //MoveItem(inventoryType, sourceSlot, itemInfo.Item.Container, itemInfo.Item.GetSlot()); } diff --git a/AetherBags/Plugin.cs b/AetherBags/Plugin.cs index 258fa71..2c83b1c 100644 --- a/AetherBags/Plugin.cs +++ b/AetherBags/Plugin.cs @@ -1,14 +1,16 @@ +using System; using System.Numerics; using AetherBags.Addons; -using AetherBags.Configuration; using AetherBags.Helpers; using Dalamud.Plugin; using Dalamud.Game.Command; +using Dalamud.Hooking; +using FFXIVClientStructs.FFXIV.Client.Game; using KamiToolKit; namespace AetherBags; -public class Plugin : IDalamudPlugin +public unsafe class Plugin : IDalamudPlugin { private static string HelpDescription => "Opens your inventory."; public Plugin(IDalamudPluginInterface pluginInterface) @@ -56,6 +58,32 @@ public class Plugin : IDalamudPlugin if (Services.ClientState.IsLoggedIn) { Services.Framework.RunOnFrameworkThread(OnLogin); } + + try + { + _moveItemSlotHook = Services.GameInteropProvider.HookFromSignature("E8 ?? ?? ?? ?? 48 8B 03 66 FF C5", MoveItemSlotDetour); + _moveItemSlotHook.Enable(); + + Services.Logger.Debug("MoveItemSlot hooked successfully."); + } + catch (Exception e) + { + Services.Logger.Error(e, "Failed to hook MoveItemSlot"); + } + } + + private unsafe delegate int MoveItemSlotDelegate(InventoryManager* inventoryManager, InventoryType srcContainer, ushort srcSlot, InventoryType dstContainer, ushort dstSlot, bool unk); + + private Hook? _moveItemSlotHook; + + private unsafe int MoveItemSlotDetour(InventoryManager* manager, InventoryType srcType, ushort srcSlot, InventoryType dstType, ushort dstSlot, bool unk) + { + InventoryItem* sourceItem = InventoryManager.Instance()->GetInventorySlot(srcType, srcSlot); + InventoryItem* destItem = InventoryManager.Instance()->GetInventorySlot(dstType, dstSlot); + Services.Logger.Info($"[MoveItemSlot] Moving {srcType}@{srcSlot} ID:{sourceItem->ItemId} -> {dstType}@{dstSlot} ID:{destItem->ItemId} Unk: {unk}"); + + // Call the original function + return _moveItemSlotHook!.Original(manager, srcType, srcSlot, dstType, dstSlot, unk); } public void Dispose() @@ -72,6 +100,8 @@ public class Plugin : IDalamudPlugin System.AddonConfigurationWindow.Dispose(); KamiToolKitLibrary.Dispose(); + + _moveItemSlotHook?.Dispose(); } private void OnCommand(string command, string args) diff --git a/AetherBags/Services.cs b/AetherBags/Services.cs index 77fe4c8..00eeddf 100644 --- a/AetherBags/Services.cs +++ b/AetherBags/Services.cs @@ -16,4 +16,7 @@ public class Services [PluginService] public static IKeyState KeyState { get; private set; } = null!; [PluginService] public static IPluginLog Logger { get; private set; } = null!; [PluginService] public static INotificationManager NotificationManager { get; private set; } = null!; + // TODO: Remove cause temp + [PluginService] public static ISigScanner SigScanner { get; private set; } = null!; + [PluginService] public static IGameInteropProvider GameInteropProvider { get; private set; } = null!; } \ No newline at end of file