Merge remote-tracking branch 'origin/master' into dev/pie-lover
This commit is contained in:
@@ -2,6 +2,7 @@ using System.Text.RegularExpressions;
|
|||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
using Lumina.Text.ReadOnly;
|
using Lumina.Text.ReadOnly;
|
||||||
|
|
||||||
@@ -62,6 +63,13 @@ public static unsafe class InventoryItemExtensions {
|
|||||||
return null;
|
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) {
|
public bool IsRegexMatch(string searchString) {
|
||||||
// Skip any data access if string is empty
|
// Skip any data access if string is empty
|
||||||
if (searchString.IsNullOrEmpty()) return true;
|
if (searchString.IsNullOrEmpty()) return true;
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
|
||||||
|
namespace AetherBags.Extensions;
|
||||||
|
|
||||||
|
public static unsafe class InventoryTypeExtensions
|
||||||
|
{
|
||||||
|
extension(InventoryType inventoryType)
|
||||||
|
{
|
||||||
|
public uint AgentItemContainerId =>
|
||||||
|
inventoryType switch
|
||||||
|
{
|
||||||
|
InventoryType.EquippedItems => 4,
|
||||||
|
InventoryType.KeyItems => 7,
|
||||||
|
InventoryType.Inventory1 => 48,
|
||||||
|
InventoryType.Inventory2 => 49,
|
||||||
|
InventoryType.Inventory3 => 50,
|
||||||
|
InventoryType.Inventory4 => 51,
|
||||||
|
InventoryType.ArmoryMainHand => 57,
|
||||||
|
InventoryType.ArmoryHead => 58,
|
||||||
|
InventoryType.ArmoryBody => 59,
|
||||||
|
InventoryType.ArmoryHands => 60,
|
||||||
|
InventoryType.ArmoryLegs => 61,
|
||||||
|
InventoryType.ArmoryFeets => 62,
|
||||||
|
InventoryType.ArmoryOffHand => 63,
|
||||||
|
InventoryType.ArmoryEar => 64,
|
||||||
|
InventoryType.ArmoryNeck => 65,
|
||||||
|
InventoryType.ArmoryWrist => 66,
|
||||||
|
InventoryType.ArmoryRings => 67,
|
||||||
|
InventoryType.ArmorySoulCrystal => 68,
|
||||||
|
InventoryType.SaddleBag1 => 69,
|
||||||
|
InventoryType.SaddleBag2 => 70,
|
||||||
|
InventoryType.PremiumSaddleBag1 => 71,
|
||||||
|
InventoryType.PremiumSaddleBag2 => 72,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
|
public static InventoryType GetInventoryTypeFromContainerId(int id) =>
|
||||||
|
id switch
|
||||||
|
{
|
||||||
|
4 => InventoryType.EquippedItems,
|
||||||
|
7 => InventoryType.KeyItems,
|
||||||
|
48 => InventoryType.Inventory1,
|
||||||
|
49 => InventoryType.Inventory2,
|
||||||
|
50 => InventoryType.Inventory3,
|
||||||
|
51 => InventoryType.Inventory4,
|
||||||
|
57 => InventoryType.ArmoryMainHand,
|
||||||
|
58 => InventoryType.ArmoryHead,
|
||||||
|
59 => InventoryType.ArmoryBody,
|
||||||
|
60 => InventoryType.ArmoryHands,
|
||||||
|
61 => InventoryType.ArmoryLegs,
|
||||||
|
62 => InventoryType.ArmoryFeets,
|
||||||
|
63 => InventoryType.ArmoryOffHand,
|
||||||
|
64 => InventoryType.ArmoryEar,
|
||||||
|
65 => InventoryType.ArmoryNeck,
|
||||||
|
66 => InventoryType.ArmoryWrist,
|
||||||
|
67 => InventoryType.ArmoryRings,
|
||||||
|
68 => InventoryType.ArmorySoulCrystal,
|
||||||
|
69 => InventoryType.SaddleBag1,
|
||||||
|
70 => InventoryType.SaddleBag2,
|
||||||
|
71 => InventoryType.PremiumSaddleBag1,
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -630,6 +630,11 @@ public static unsafe class InventoryState
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static InventoryContainer* GetInventoryContainer(InventoryType inventoryType)
|
||||||
|
{
|
||||||
|
return InventoryManager.Instance()->GetInventoryContainer(inventoryType);
|
||||||
|
}
|
||||||
|
|
||||||
private struct AggregatedItem
|
private struct AggregatedItem
|
||||||
{
|
{
|
||||||
public InventoryItem First;
|
public InventoryItem First;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Lumina.Excel.Sheets;
|
|||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
|
||||||
namespace AetherBags.Inventory;
|
namespace AetherBags.Inventory;
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,12 @@ using KamiToolKit.Classes;
|
|||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
|
||||||
// TODO: Switch back to CS version when Dalamud Updated
|
// TODO: Switch back to CS version when Dalamud Updated
|
||||||
using DragDropFixedNode = AetherBags.Nodes.DragDropNode;
|
using DragDropFixedNode = AetherBags.Nodes.DragDropNode;
|
||||||
|
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
|
||||||
|
|
||||||
namespace AetherBags.Nodes;
|
namespace AetherBags.Nodes;
|
||||||
|
|
||||||
@@ -285,11 +288,45 @@ public class InventoryCategoryNode : SimpleComponentNode
|
|||||||
|
|
||||||
private unsafe void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo itemInfo)
|
private unsafe void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo itemInfo)
|
||||||
{
|
{
|
||||||
Services.Logger.Debug($"Inventory DragDropNode Payload Accepted: {payload.Type} Int1: {payload.Int1} Int2: {payload.Int2}");
|
if (payload.Type != DragDropType.Item) return;
|
||||||
InventoryType inventoryType = (InventoryType)payload.Int1;
|
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;
|
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.
|
// Should work for swapping item but need a fake empty slot to put new items in probably.
|
||||||
InventoryManager.Instance()->MoveItemSlot(inventoryType, sourceSlot, itemInfo.Item.Container, itemInfo.Item.GetSlot());
|
// Services.Logger.Debug($"Moving Item from {inventoryType} Slot {sourceSlot} to {itemInfo.Item.Container} Slot {itemInfo.Item.GetSlot()}");
|
||||||
|
//MoveItem(inventoryType, sourceSlot, itemInfo.Item.Container, itemInfo.Item.GetSlot());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibly still use this
|
||||||
|
private unsafe void MoveItem(InventoryType sourceInventory, uint sourceSlot, InventoryType destinationInventory, uint destinationSlot)
|
||||||
|
{
|
||||||
|
var sourceContainerId = sourceInventory.AgentItemContainerId;
|
||||||
|
var destinationContainerId = destinationInventory.AgentItemContainerId;
|
||||||
|
|
||||||
|
if (sourceContainerId != 0 && destinationContainerId != 0) {
|
||||||
|
var atkValues = stackalloc AtkValue[4];
|
||||||
|
for (var i = 0; i < 4; i++) atkValues[i].Type = ValueType.UInt;
|
||||||
|
|
||||||
|
atkValues[0].UInt = sourceContainerId;
|
||||||
|
atkValues[1].UInt = sourceSlot;
|
||||||
|
atkValues[2].UInt = destinationContainerId;
|
||||||
|
atkValues[3].UInt = destinationSlot;
|
||||||
|
|
||||||
|
var retVal = stackalloc AtkValue[1];
|
||||||
|
|
||||||
|
RaptureAtkModule* atkModule = RaptureAtkModule.Instance();
|
||||||
|
// (RaptureAtkModule* a1, void* outValue, AtkValue* atkValues);
|
||||||
|
// (AtkValue* returnValue, AtkValue* values, uint valueCount)
|
||||||
|
atkModule->HandleItemMove(retVal, atkValues, 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-2
@@ -1,14 +1,16 @@
|
|||||||
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.Addons;
|
using AetherBags.Addons;
|
||||||
using AetherBags.Configuration;
|
|
||||||
using AetherBags.Helpers;
|
using AetherBags.Helpers;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using KamiToolKit;
|
using KamiToolKit;
|
||||||
|
|
||||||
namespace AetherBags;
|
namespace AetherBags;
|
||||||
|
|
||||||
public class Plugin : IDalamudPlugin
|
public unsafe class Plugin : IDalamudPlugin
|
||||||
{
|
{
|
||||||
private static string HelpDescription => "Opens your inventory.";
|
private static string HelpDescription => "Opens your inventory.";
|
||||||
public Plugin(IDalamudPluginInterface pluginInterface)
|
public Plugin(IDalamudPluginInterface pluginInterface)
|
||||||
@@ -56,6 +58,32 @@ public class Plugin : IDalamudPlugin
|
|||||||
if (Services.ClientState.IsLoggedIn) {
|
if (Services.ClientState.IsLoggedIn) {
|
||||||
Services.Framework.RunOnFrameworkThread(OnLogin);
|
Services.Framework.RunOnFrameworkThread(OnLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_moveItemSlotHook = Services.GameInteropProvider.HookFromSignature<MoveItemSlotDelegate>("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<MoveItemSlotDelegate>? _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()
|
public void Dispose()
|
||||||
@@ -72,6 +100,8 @@ public class Plugin : IDalamudPlugin
|
|||||||
System.AddonConfigurationWindow.Dispose();
|
System.AddonConfigurationWindow.Dispose();
|
||||||
|
|
||||||
KamiToolKitLibrary.Dispose();
|
KamiToolKitLibrary.Dispose();
|
||||||
|
|
||||||
|
_moveItemSlotHook?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCommand(string command, string args)
|
private void OnCommand(string command, string args)
|
||||||
|
|||||||
@@ -16,4 +16,7 @@ public class Services
|
|||||||
[PluginService] public static IKeyState KeyState { get; private set; } = null!;
|
[PluginService] public static IKeyState KeyState { get; private set; } = null!;
|
||||||
[PluginService] public static IPluginLog Logger { get; private set; } = null!;
|
[PluginService] public static IPluginLog Logger { get; private set; } = null!;
|
||||||
[PluginService] public static INotificationManager NotificationManager { 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!;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user