Merge remote-tracking branch 'origin/master' into dev/pie-lover
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentInventory_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9e458ae8a124476099a99b081d71ce27826848_003F26_003F0a847424_003FAgentInventory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentSatisfactionSupply_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb2cd0663609440e590f52980cafc1ba3822648_003F28_003Ffa48b62e_003FAgentSatisfactionSupply_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentSatisfactionSupply_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb2cd0663609440e590f52980cafc1ba3822648_003F28_003Ffa48b62e_003FAgentSatisfactionSupply_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentUpdateFlag_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7097e6bfd2288e8ff8dacc8d1e21863898453e58b9546b9752e0c0a5bed4dc_003FAgentUpdateFlag_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAtkValue_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1b966bf9f0d5b3eb39a7ee3ff6ab5c83f5bea8a841eafd7c8a1e55532d2d952_003FAtkValue_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAtkValue_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1b966bf9f0d5b3eb39a7ee3ff6ab5c83f5bea8a841eafd7c8a1e55532d2d952_003FAtkValue_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACurrencyManager_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe66db7cd515142b9bbfb1b4e18f82ace825448_003Ffc_003F78df30c7_003FCurrencyManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACurrencyManager_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe66db7cd515142b9bbfb1b4e18f82ace825448_003Ffc_003F78df30c7_003FCurrencyManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AInventoryItem_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9e458ae8a124476099a99b081d71ce27826848_003F6f_003Ffa56b446_003FInventoryItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AInventoryManager_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7d322ffbe41aca452171c1858ac4d72a967922191dfb8ada66667df5fd58b_003FInventoryManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AInventoryManager_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7d322ffbe41aca452171c1858ac4d72a967922191dfb8ada66667df5fd58b_003FInventoryManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AItemOrderModule_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F77e1e4eb417120eb1e45bbb81bf6a70e47ea3c097bdf493584be7f333fa_003FItemOrderModule_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AItem_002Eg_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F8ec7cc8a18dbb6a6f3c21f8adcb4e2661dc7979_003FItem_002Eg_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AItem_002Eg_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F8ec7cc8a18dbb6a6f3c21f8adcb4e2661dc7979_003FItem_002Eg_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||||
@@ -9,6 +9,7 @@ using AetherBags.Nodes.Inventory;
|
|||||||
using AetherBags.Nodes.Layout;
|
using AetherBags.Nodes.Layout;
|
||||||
using Dalamud.Game.Addon.Lifecycle;
|
using Dalamud.Game.Addon.Lifecycle;
|
||||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||||
|
using Dalamud.Game.Gui;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
using KamiToolKit;
|
using KamiToolKit;
|
||||||
@@ -22,6 +23,7 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
private readonly InventoryCategoryHoverCoordinator _hoverCoordinator = new();
|
private readonly InventoryCategoryHoverCoordinator _hoverCoordinator = new();
|
||||||
private readonly HashSet<InventoryCategoryNode> _hoverSubscribed = new();
|
private readonly HashSet<InventoryCategoryNode> _hoverSubscribed = new();
|
||||||
|
|
||||||
|
private InventoryNotificationNode _notificationNode = null!;
|
||||||
private WrappingGridNode<InventoryCategoryNode> _categoriesNode = null!;
|
private WrappingGridNode<InventoryCategoryNode> _categoriesNode = null!;
|
||||||
private TextInputWithHintNode _searchInputNode = null!;
|
private TextInputWithHintNode _searchInputNode = null!;
|
||||||
private CircleButtonNode _settingsButtonNode = null!;
|
private CircleButtonNode _settingsButtonNode = null!;
|
||||||
@@ -69,6 +71,13 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
float x = headerX + (headerW - size.X) * 0.5f;
|
float x = headerX + (headerW - size.X) * 0.5f;
|
||||||
float y = headerY + (headerH - size.Y) * 0.5f;
|
float y = headerY + (headerH - size.Y) * 0.5f;
|
||||||
|
|
||||||
|
_notificationNode = new InventoryNotificationNode
|
||||||
|
{
|
||||||
|
Position = new Vector2(WindowNode!.X - 4f, WindowNode!.Y - 32f),
|
||||||
|
Size = new Vector2(headerW, 28f),
|
||||||
|
};
|
||||||
|
_notificationNode.AttachNode(this);
|
||||||
|
|
||||||
_searchInputNode = new TextInputWithHintNode
|
_searchInputNode = new TextInputWithHintNode
|
||||||
{
|
{
|
||||||
Position = new Vector2(x, y),
|
Position = new Vector2(x, y),
|
||||||
@@ -105,7 +114,6 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
base.OnSetup(addon);
|
base.OnSetup(addon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override unsafe void OnUpdate(AtkUnitBase* addon)
|
protected override unsafe void OnUpdate(AtkUnitBase* addon)
|
||||||
{
|
{
|
||||||
if (_refreshQueued)
|
if (_refreshQueued)
|
||||||
@@ -117,6 +125,9 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
RefreshCategoriesCore(doAutosize);
|
RefreshCategoriesCore(doAutosize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InventoryNotificationType currentNotificationType = (InventoryNotificationType) AgentInventory.Instance()->OpenTitleId;
|
||||||
|
if(currentNotificationType != _notificationNode.NotificationType) _notificationNode.NotificationType = currentNotificationType;
|
||||||
|
|
||||||
base.OnUpdate(addon);
|
base.OnUpdate(addon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using AetherBags.Interop;
|
using AetherBags.Interop;
|
||||||
|
using AetherBags.Inventory;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
using KamiToolKit.Classes;
|
using KamiToolKit.Classes;
|
||||||
using Lumina.Text.ReadOnly;
|
using Lumina.Text.ReadOnly;
|
||||||
@@ -6,7 +8,7 @@ using Lumina.Text;
|
|||||||
|
|
||||||
namespace AetherBags.Extensions;
|
namespace AetherBags.Extensions;
|
||||||
|
|
||||||
// TODO: Remove this when CS is merged into Dalamud.
|
// TODO: Remove FixedInterface when CS is merged into Dalamud.
|
||||||
public static unsafe class DragDropPayloadExtensions
|
public static unsafe class DragDropPayloadExtensions
|
||||||
{
|
{
|
||||||
public static DragDropPayload FromFixedInterface(AtkDragDropInterface* dragDropInterface)
|
public static DragDropPayload FromFixedInterface(AtkDragDropInterface* dragDropInterface)
|
||||||
@@ -54,4 +56,59 @@ public static unsafe class DragDropPayloadExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension(DragDropPayload payload)
|
||||||
|
{
|
||||||
|
public bool IsValidInventoryPayload =>
|
||||||
|
payload.Type is DragDropType.Inventory_Item
|
||||||
|
or DragDropType.Inventory_Crystal
|
||||||
|
or DragDropType.RemoteInventory_Item
|
||||||
|
or DragDropType.Item;
|
||||||
|
|
||||||
|
public InventoryLocation InventoryLocation
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!payload.IsValidInventoryPayload) return default;
|
||||||
|
|
||||||
|
if (payload.Type == DragDropType.Inventory_Item)
|
||||||
|
{
|
||||||
|
return new InventoryLocation((InventoryType)payload.Int1, (ushort)payload.Int2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int containerId = payload.Int1;
|
||||||
|
int uiSlot = payload.Int2;
|
||||||
|
|
||||||
|
InventoryType sourceContainer = InventoryType.GetInventoryTypeFromContainerId(containerId);
|
||||||
|
|
||||||
|
if (sourceContainer == 0)
|
||||||
|
return new InventoryLocation(0, 0);
|
||||||
|
|
||||||
|
// Retainers have special handling: UI has 5 tabs × 35 slots, data has 7 pages × 25 slots
|
||||||
|
if (sourceContainer.IsRetainer)
|
||||||
|
{
|
||||||
|
// Container IDs 52-56 = UI tabs 0-4
|
||||||
|
int uiTabIndex = containerId - 52;
|
||||||
|
|
||||||
|
// Convert to global data index
|
||||||
|
int globalDataIndex = (uiTabIndex * 35) + uiSlot;
|
||||||
|
|
||||||
|
// Calculate data page and slot
|
||||||
|
int dataPage = globalDataIndex / 25;
|
||||||
|
int dataSlot = globalDataIndex % 25;
|
||||||
|
|
||||||
|
InventoryType dataContainer = InventoryType.RetainerPage1 + (uint)dataPage;
|
||||||
|
|
||||||
|
// Now resolve through sorter for the actual storage location
|
||||||
|
var (realContainer, realSlot) = dataContainer.GetRealItemLocation(dataSlot);
|
||||||
|
return new InventoryLocation(realContainer, realSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-retainers, use the standard resolution
|
||||||
|
var (container, slot) = sourceContainer.GetRealItemLocation(uiSlot);
|
||||||
|
return new InventoryLocation(container, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using AetherBags.Inventory;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
|
||||||
@@ -17,6 +18,12 @@ public static unsafe class InventoryTypeExtensions
|
|||||||
InventoryType.Inventory2 => 49,
|
InventoryType.Inventory2 => 49,
|
||||||
InventoryType.Inventory3 => 50,
|
InventoryType.Inventory3 => 50,
|
||||||
InventoryType.Inventory4 => 51,
|
InventoryType.Inventory4 => 51,
|
||||||
|
// It's possible that these are actually UI IDs
|
||||||
|
InventoryType.RetainerPage1 => 52,
|
||||||
|
InventoryType.RetainerPage2 => 53,
|
||||||
|
InventoryType.RetainerPage3 => 54,
|
||||||
|
InventoryType.RetainerPage4 => 55,
|
||||||
|
InventoryType.RetainerPage5 => 56,
|
||||||
InventoryType.ArmoryMainHand => 57,
|
InventoryType.ArmoryMainHand => 57,
|
||||||
InventoryType.ArmoryHead => 58,
|
InventoryType.ArmoryHead => 58,
|
||||||
InventoryType.ArmoryBody => 59,
|
InventoryType.ArmoryBody => 59,
|
||||||
@@ -45,6 +52,11 @@ public static unsafe class InventoryTypeExtensions
|
|||||||
49 => InventoryType.Inventory2,
|
49 => InventoryType.Inventory2,
|
||||||
50 => InventoryType.Inventory3,
|
50 => InventoryType.Inventory3,
|
||||||
51 => InventoryType.Inventory4,
|
51 => InventoryType.Inventory4,
|
||||||
|
52 => InventoryType.RetainerPage1,
|
||||||
|
53 => InventoryType.RetainerPage2,
|
||||||
|
54 => InventoryType.RetainerPage3,
|
||||||
|
55 => InventoryType.RetainerPage4,
|
||||||
|
56 => InventoryType.RetainerPage5,
|
||||||
57 => InventoryType.ArmoryMainHand,
|
57 => InventoryType.ArmoryMainHand,
|
||||||
58 => InventoryType.ArmoryHead,
|
58 => InventoryType.ArmoryHead,
|
||||||
59 => InventoryType.ArmoryBody,
|
59 => InventoryType.ArmoryBody,
|
||||||
@@ -85,6 +97,13 @@ public static unsafe class InventoryTypeExtensions
|
|||||||
InventoryType.SaddleBag2 => ItemOrderModule.Instance()->SaddleBagSorter,
|
InventoryType.SaddleBag2 => ItemOrderModule.Instance()->SaddleBagSorter,
|
||||||
InventoryType.PremiumSaddleBag1 => ItemOrderModule.Instance()->PremiumSaddleBagSorter,
|
InventoryType.PremiumSaddleBag1 => ItemOrderModule.Instance()->PremiumSaddleBagSorter,
|
||||||
InventoryType.PremiumSaddleBag2 => ItemOrderModule.Instance()->PremiumSaddleBagSorter,
|
InventoryType.PremiumSaddleBag2 => ItemOrderModule.Instance()->PremiumSaddleBagSorter,
|
||||||
|
InventoryType.RetainerPage1 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
|
InventoryType.RetainerPage2 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
|
InventoryType.RetainerPage3 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
|
InventoryType.RetainerPage4 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
|
InventoryType.RetainerPage5 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
|
InventoryType.RetainerPage6 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
|
InventoryType.RetainerPage7 => ItemOrderModule.Instance()->GetActiveRetainerSorter(),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,6 +113,12 @@ public static unsafe class InventoryTypeExtensions
|
|||||||
InventoryType.Inventory4 => inventoryType.GetInventorySorter->ItemsPerPage * 3,
|
InventoryType.Inventory4 => inventoryType.GetInventorySorter->ItemsPerPage * 3,
|
||||||
InventoryType.SaddleBag2 => inventoryType.GetInventorySorter->ItemsPerPage,
|
InventoryType.SaddleBag2 => inventoryType.GetInventorySorter->ItemsPerPage,
|
||||||
InventoryType.PremiumSaddleBag2 => inventoryType.GetInventorySorter->ItemsPerPage,
|
InventoryType.PremiumSaddleBag2 => inventoryType.GetInventorySorter->ItemsPerPage,
|
||||||
|
InventoryType.RetainerPage2 => inventoryType.GetInventorySorter->ItemsPerPage,
|
||||||
|
InventoryType.RetainerPage3 => inventoryType.GetInventorySorter->ItemsPerPage * 2,
|
||||||
|
InventoryType.RetainerPage4 => inventoryType.GetInventorySorter->ItemsPerPage * 3,
|
||||||
|
InventoryType.RetainerPage5 => inventoryType.GetInventorySorter->ItemsPerPage * 4,
|
||||||
|
InventoryType.RetainerPage6 => inventoryType.GetInventorySorter->ItemsPerPage * 5,
|
||||||
|
InventoryType.RetainerPage7 => inventoryType.GetInventorySorter->ItemsPerPage * 6,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,11 +148,21 @@ public static unsafe class InventoryTypeExtensions
|
|||||||
InventoryType.ArmoryRings or
|
InventoryType.ArmoryRings or
|
||||||
InventoryType.ArmorySoulCrystal;
|
InventoryType.ArmorySoulCrystal;
|
||||||
|
|
||||||
|
public bool IsRetainer => inventoryType is
|
||||||
|
InventoryType.RetainerPage1 or
|
||||||
|
InventoryType.RetainerPage2 or
|
||||||
|
InventoryType.RetainerPage3 or
|
||||||
|
InventoryType.RetainerPage4 or
|
||||||
|
InventoryType.RetainerPage5 or
|
||||||
|
InventoryType.RetainerPage6 or
|
||||||
|
InventoryType.RetainerPage7;
|
||||||
|
|
||||||
public int ContainerGroup => inventoryType switch
|
public int ContainerGroup => inventoryType switch
|
||||||
{
|
{
|
||||||
_ when inventoryType.IsMainInventory => 1,
|
_ when inventoryType.IsMainInventory => 1,
|
||||||
_ when inventoryType.IsSaddleBag => 2,
|
_ when inventoryType.IsSaddleBag => 2,
|
||||||
_ when inventoryType.IsArmory => 3,
|
_ when inventoryType.IsArmory => 3,
|
||||||
|
_ when inventoryType.IsRetainer => 4,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,35 +173,36 @@ public static unsafe class InventoryTypeExtensions
|
|||||||
/// Resolves the real container and slot for this inventory type using ItemOrderModule.
|
/// Resolves the real container and slot for this inventory type using ItemOrderModule.
|
||||||
/// For sorted inventories, the visual slot differs from the actual storage slot.
|
/// For sorted inventories, the visual slot differs from the actual storage slot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public (InventoryType Container, ushort Slot) GetRealItemLocation(int visualSlot)
|
public InventoryLocation GetRealItemLocation(int visualSlot)
|
||||||
{
|
{
|
||||||
var sorter = inventoryType.GetInventorySorter;
|
var sorter = inventoryType.GetInventorySorter;
|
||||||
if (sorter == null)
|
if (sorter == null)
|
||||||
return (inventoryType, (ushort)visualSlot);
|
return new InventoryLocation(inventoryType, (ushort)visualSlot);
|
||||||
|
|
||||||
int startIndex = inventoryType.GetInventoryStartIndex;
|
int startIndex = inventoryType.GetInventoryStartIndex;
|
||||||
int sorterIndex = startIndex + visualSlot;
|
int sorterIndex = startIndex + visualSlot;
|
||||||
|
|
||||||
if (sorterIndex < 0 || sorterIndex >= sorter->Items.LongCount)
|
if (sorterIndex < 0 || sorterIndex >= sorter->Items.LongCount)
|
||||||
return (inventoryType, (ushort)visualSlot);
|
return new InventoryLocation(inventoryType, (ushort)visualSlot);
|
||||||
|
|
||||||
var entry = sorter->Items[sorterIndex].Value;
|
var entry = sorter->Items[sorterIndex].Value;
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
return (inventoryType, (ushort)visualSlot);
|
return new InventoryLocation(inventoryType, (ushort)visualSlot);
|
||||||
|
|
||||||
InventoryType baseType = inventoryType switch
|
InventoryType baseType = inventoryType switch
|
||||||
{
|
{
|
||||||
_ when inventoryType.IsMainInventory => InventoryType.Inventory1,
|
_ when inventoryType.IsMainInventory => InventoryType.Inventory1,
|
||||||
_ when inventoryType.IsSaddleBag => inventoryType is InventoryType. SaddleBag1 or InventoryType.SaddleBag2
|
_ when inventoryType.IsSaddleBag => inventoryType is InventoryType.SaddleBag1 or InventoryType.SaddleBag2
|
||||||
? InventoryType. SaddleBag1
|
? InventoryType.SaddleBag1
|
||||||
: InventoryType.PremiumSaddleBag1,
|
: InventoryType.PremiumSaddleBag1,
|
||||||
|
_ when inventoryType.IsRetainer => InventoryType.RetainerPage1,
|
||||||
_ => inventoryType,
|
_ => inventoryType,
|
||||||
};
|
};
|
||||||
|
|
||||||
InventoryType realContainer = baseType + entry->Page;
|
InventoryType realContainer = baseType + entry->Page;
|
||||||
ushort realSlot = entry->Slot;
|
ushort realSlot = entry->Slot;
|
||||||
|
|
||||||
return (realContainer, realSlot);
|
return new InventoryLocation(realContainer, realSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,20 +8,16 @@ namespace AetherBags. Helpers;
|
|||||||
|
|
||||||
public static unsafe class InventoryMoveHelper
|
public static unsafe class InventoryMoveHelper
|
||||||
{
|
{
|
||||||
|
// Requires the visual UI slots instead of actual slots.
|
||||||
public static void MoveItem(InventoryType sourceContainer, ushort sourceSlot, InventoryType destContainer, ushort destSlot)
|
public static void MoveItem(InventoryType sourceContainer, ushort sourceSlot, InventoryType destContainer, ushort destSlot)
|
||||||
{
|
{
|
||||||
bool isCrossContainerMove = ! sourceContainer.IsSameContainerGroup(destContainer);
|
Services.Logger.Debug($"[MoveItem] {sourceContainer}@{sourceSlot} -> {destContainer}@{destSlot}");
|
||||||
|
InventoryManager.Instance()->MoveItemSlot(sourceContainer, sourceSlot, destContainer, destSlot, true);
|
||||||
if (isCrossContainerMove)
|
Services.Framework.DelayTicks(2);
|
||||||
{
|
Services.Framework.RunOnFrameworkThread(System.AddonInventoryWindow.ManualInventoryRefresh);
|
||||||
MoveItemViaAgent(sourceContainer, sourceSlot, destContainer, destSlot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InventoryManager.Instance()->MoveItemSlot(sourceContainer, sourceSlot, destContainer, destSlot, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private static void MoveItemViaAgent(InventoryType sourceInventory, ushort sourceSlot, InventoryType destInventory, ushort destSlot)
|
private static void MoveItemViaAgent(InventoryType sourceInventory, ushort sourceSlot, InventoryType destInventory, ushort destSlot)
|
||||||
{
|
{
|
||||||
uint sourceContainerId = sourceInventory.AgentItemContainerId;
|
uint sourceContainerId = sourceInventory.AgentItemContainerId;
|
||||||
@@ -49,4 +45,5 @@ public static unsafe class InventoryMoveHelper
|
|||||||
RaptureAtkModule* atkModule = RaptureAtkModule.Instance();
|
RaptureAtkModule* atkModule = RaptureAtkModule.Instance();
|
||||||
atkModule->HandleItemMove(retVal, atkValues, 4);
|
atkModule->HandleItemMove(retVal, atkValues, 4);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ public sealed unsafe class InventoryHooks : IDisposable
|
|||||||
InventoryItem* sourceItem = InventoryManager.Instance()->GetInventorySlot(srcType, srcSlot);
|
InventoryItem* sourceItem = InventoryManager.Instance()->GetInventorySlot(srcType, srcSlot);
|
||||||
InventoryItem* destItem = InventoryManager.Instance()->GetInventorySlot(dstType, dstSlot);
|
InventoryItem* destItem = InventoryManager.Instance()->GetInventorySlot(dstType, dstSlot);
|
||||||
|
|
||||||
Services.Logger.Debug($"[MoveItemSlot] Moving {srcType}@{srcSlot} ID:{sourceItem->ItemId} -> {dstType}@{dstSlot} ID:{destItem->ItemId} Unk: {unk}");
|
Services.Logger.Debug($"[MoveItemSlot Hook] Moving {srcType}@{srcSlot} ID:{sourceItem->ItemId} -> {dstType}@{dstSlot} ID:{destItem->ItemId} Unk: {unk}");
|
||||||
|
|
||||||
return _moveItemSlotHook!.Original(manager, srcType, srcSlot, dstType, dstSlot, unk);
|
return _moveItemSlotHook!.Original(manager, srcType, srcSlot, dstType, dstSlot, unk);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
|
||||||
|
namespace AetherBags.Inventory;
|
||||||
|
|
||||||
|
public readonly record struct InventoryLocation(InventoryType Container, ushort Slot)
|
||||||
|
{
|
||||||
|
public static readonly InventoryLocation Invalid = new(0, 0);
|
||||||
|
|
||||||
|
public bool IsValid => Container != 0;
|
||||||
|
|
||||||
|
public override string ToString() => $"{Container}@{Slot}";
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Lumina.Excel;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using Lumina.Text.ReadOnly;
|
||||||
|
|
||||||
|
namespace AetherBags.Inventory;
|
||||||
|
|
||||||
|
public class InventoryNotificationState
|
||||||
|
{
|
||||||
|
private readonly Dictionary<InventoryNotificationType, InventoryNotificationInfo> notificationCache;
|
||||||
|
|
||||||
|
public InventoryNotificationState()
|
||||||
|
{
|
||||||
|
var addonSheet = Services.DataManager.GetExcelSheet<Addon>();
|
||||||
|
notificationCache = new Dictionary<InventoryNotificationType, InventoryNotificationInfo>
|
||||||
|
{
|
||||||
|
{ InventoryNotificationType.Sell, new InventoryNotificationInfo(addonSheet.GetRow(530).Text, addonSheet.GetRow(3576).Text) },
|
||||||
|
{ InventoryNotificationType.Trade, new InventoryNotificationInfo(addonSheet.GetRow(531).Text, addonSheet.GetRow(3572).Text) },
|
||||||
|
{ InventoryNotificationType.Letters, new InventoryNotificationInfo(addonSheet.GetRow(549).Text, addonSheet.GetRow(3575).Text) },
|
||||||
|
{ InventoryNotificationType.Retainer, new InventoryNotificationInfo(addonSheet.GetRow(532).Text, addonSheet.GetRow(3573).Text) },
|
||||||
|
{ InventoryNotificationType.RetainerEquip, new InventoryNotificationInfo(addonSheet.GetRow(778).Text, addonSheet.GetRow(3585).Text) },
|
||||||
|
{ InventoryNotificationType.Equip, new InventoryNotificationInfo(addonSheet.GetRow(538).Text, addonSheet.GetRow(3577).Text) },
|
||||||
|
{ InventoryNotificationType.Armory, new InventoryNotificationInfo(addonSheet.GetRow(775).Text, addonSheet.GetRow(3578).Text) },
|
||||||
|
{ InventoryNotificationType.Markets, new InventoryNotificationInfo(addonSheet.GetRow(548).Text, addonSheet.GetRow(3574).Text) },
|
||||||
|
{ InventoryNotificationType.Trade2, new InventoryNotificationInfo(addonSheet.GetRow(531).Text, addonSheet.GetRow(3572).Text) },
|
||||||
|
{ InventoryNotificationType.CompanyChest, new InventoryNotificationInfo(addonSheet.GetRow(776).Text, addonSheet.GetRow(3579).Text) },
|
||||||
|
{ InventoryNotificationType.Exterior, new InventoryNotificationInfo(addonSheet.GetRow(3583).Text, addonSheet.GetRow(3581).Text) },
|
||||||
|
{ InventoryNotificationType.Interior, new InventoryNotificationInfo(addonSheet.GetRow(3584).Text, addonSheet.GetRow(3582).Text) },
|
||||||
|
{ InventoryNotificationType.Layout, new InventoryNotificationInfo(addonSheet.GetRow(6237).Text, addonSheet.GetRow(3580).Text) },
|
||||||
|
{ InventoryNotificationType.Plant, new InventoryNotificationInfo(addonSheet.GetRow(6416).Text, addonSheet.GetRow(6418).Text) },
|
||||||
|
{ InventoryNotificationType.Fertilize, new InventoryNotificationInfo(addonSheet.GetRow(6417).Text, addonSheet.GetRow(6419).Text) },
|
||||||
|
{ InventoryNotificationType.Transmutation, new InventoryNotificationInfo(addonSheet.GetRow(3911).Text, addonSheet.GetRow(3901).Text) },
|
||||||
|
{ InventoryNotificationType.Reward, new InventoryNotificationInfo(addonSheet.GetRow(6503).Text, addonSheet.GetRow(6502).Text) },
|
||||||
|
{ InventoryNotificationType.Feed, new InventoryNotificationInfo(addonSheet.GetRow(6519).Text, addonSheet.GetRow(6518).Text) },
|
||||||
|
{ InventoryNotificationType.Charge, new InventoryNotificationInfo(addonSheet.GetRow(8638).Text, addonSheet.GetRow(8637).Text) },
|
||||||
|
{ InventoryNotificationType.Convert, new InventoryNotificationInfo(addonSheet.GetRow(8647).Text, addonSheet.GetRow(8646).Text) },
|
||||||
|
{ InventoryNotificationType.Covering, new InventoryNotificationInfo(addonSheet.GetRow(9029).Text, addonSheet.GetRow(9028).Text) },
|
||||||
|
{ InventoryNotificationType.Feed2, new InventoryNotificationInfo(addonSheet.GetRow(9041).Text, addonSheet.GetRow(9040).Text) },
|
||||||
|
{ InventoryNotificationType.Manual, new InventoryNotificationInfo(addonSheet.GetRow(9044).Text, addonSheet.GetRow(9043).Text) },
|
||||||
|
{ InventoryNotificationType.Chocobo, new InventoryNotificationInfo(addonSheet.GetRow(9073).Text, addonSheet.GetRow(9072).Text) },
|
||||||
|
{ InventoryNotificationType.Outfit, new InventoryNotificationInfo(addonSheet.GetRow(6578).Text, addonSheet.GetRow(6579).Text) },
|
||||||
|
{ InventoryNotificationType.Outfit2, new InventoryNotificationInfo(addonSheet.GetRow(6578).Text, addonSheet.GetRow(6579).Text) },
|
||||||
|
{ InventoryNotificationType.Plant2, new InventoryNotificationInfo(addonSheet.GetRow(6416).Text, addonSheet.GetRow(6418).Text) },
|
||||||
|
{ InventoryNotificationType.Aquarium, new InventoryNotificationInfo(addonSheet.GetRow(6808).Text, addonSheet.GetRow(6807).Text) },
|
||||||
|
{ InventoryNotificationType.SaddleBag, new InventoryNotificationInfo(addonSheet.GetRow(891).Text, addonSheet.GetRow(892).Text) },
|
||||||
|
{ InventoryNotificationType.Donate, new InventoryNotificationInfo(addonSheet.GetRow(11595).Text, addonSheet.GetRow(11596).Text) },
|
||||||
|
{ InventoryNotificationType.Trade3, new InventoryNotificationInfo(addonSheet.GetRow(531).Text, addonSheet.GetRow(3572).Text) },
|
||||||
|
{ InventoryNotificationType.Trade4, new InventoryNotificationInfo(addonSheet.GetRow(531).Text, addonSheet.GetRow(3572).Text) },
|
||||||
|
{ InventoryNotificationType.Exterior2, new InventoryNotificationInfo(addonSheet.GetRow(3583).Text, addonSheet.GetRow(3581).Text) },
|
||||||
|
{ InventoryNotificationType.Interior2, new InventoryNotificationInfo(addonSheet.GetRow(6237).Text, addonSheet.GetRow(3580).Text) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryNotificationInfo? GetNotificationInfo(uint openTitleId)
|
||||||
|
{
|
||||||
|
return notificationCache.GetValueOrDefault((InventoryNotificationType)openTitleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record InventoryNotificationInfo(ReadOnlySeString Title, ReadOnlySeString Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InventoryNotificationType : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Sell = 1,
|
||||||
|
Trade = 2,
|
||||||
|
Letters = 3,
|
||||||
|
Retainer = 4,
|
||||||
|
RetainerEquip = 5,
|
||||||
|
Equip = 6,
|
||||||
|
Armory = 7,
|
||||||
|
Markets = 8,
|
||||||
|
Trade2 = 9,
|
||||||
|
CompanyChest = 10,
|
||||||
|
Exterior = 11,
|
||||||
|
Interior = 12,
|
||||||
|
Layout = 13,
|
||||||
|
Plant = 14,
|
||||||
|
Fertilize = 15,
|
||||||
|
Transmutation = 16,
|
||||||
|
Reward = 17,
|
||||||
|
Feed = 18,
|
||||||
|
Charge = 19,
|
||||||
|
Convert = 20,
|
||||||
|
Covering = 21,
|
||||||
|
Feed2 = 22,
|
||||||
|
Manual = 23,
|
||||||
|
Chocobo = 24,
|
||||||
|
Outfit = 25,
|
||||||
|
Outfit2 = 26,
|
||||||
|
Plant2 = 27,
|
||||||
|
Aquarium = 28,
|
||||||
|
SaddleBag = 29,
|
||||||
|
Donate = 30,
|
||||||
|
Trade3 = 31,
|
||||||
|
Trade4 = 32,
|
||||||
|
Exterior2 = 33,
|
||||||
|
Interior2 = 34
|
||||||
|
}
|
||||||
@@ -151,28 +151,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ReadOnlySeString? Tooltip {
|
|
||||||
get;
|
|
||||||
set {
|
|
||||||
field = value;
|
|
||||||
switch (value) {
|
|
||||||
case { IsEmpty: false } when !TooltipRegistered:
|
|
||||||
AddEvent(AtkEventType.DragDropRollOver, ShowTooltip);
|
|
||||||
AddEvent(AtkEventType.DragDropRollOut, HideTooltip);
|
|
||||||
|
|
||||||
TooltipRegistered = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case null when TooltipRegistered:
|
|
||||||
RemoveEvent(AtkEventType.DragDropRollOver, ShowTooltip);
|
|
||||||
RemoveEvent(AtkEventType.DragDropRollOut, HideTooltip);
|
|
||||||
|
|
||||||
TooltipRegistered = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DragDropInsertHandler(AtkEventListener* thisPtr, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, AtkEventData* atkEventData) {
|
private void DragDropInsertHandler(AtkEventListener* thisPtr, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, AtkEventData* atkEventData) {
|
||||||
atkEvent->SetEventIsHandled();
|
atkEvent->SetEventIsHandled();
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class TextInputWithHintNode : SimpleComponentNode {
|
|||||||
TexturePath = "ui/uld/CircleButtons.tex",
|
TexturePath = "ui/uld/CircleButtons.tex",
|
||||||
TextureCoordinates = new Vector2(112.0f, 84.0f),
|
TextureCoordinates = new Vector2(112.0f, 84.0f),
|
||||||
TextureSize = new Vector2(28.0f, 28.0f),
|
TextureSize = new Vector2(28.0f, 28.0f),
|
||||||
Tooltip = new SeStringBuilder()
|
TextTooltip = new SeStringBuilder()
|
||||||
.Append("Supports Regex Search")
|
.Append("Supports Regex Search")
|
||||||
.AppendNewLine()
|
.AppendNewLine()
|
||||||
.Append("Start input with '$' to search by description")
|
.Append("Start input with '$' to search by description")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using AetherBags.Helpers;
|
|||||||
using AetherBags.Inventory;
|
using AetherBags.Inventory;
|
||||||
using AetherBags.Nodes.Layout;
|
using AetherBags.Nodes.Layout;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
using KamiToolKit.Classes;
|
using KamiToolKit.Classes;
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
@@ -74,7 +75,7 @@ public class InventoryCategoryNode : SimpleComponentNode
|
|||||||
|
|
||||||
_categoryNameTextNode.String = _fullHeaderText;
|
_categoryNameTextNode.String = _fullHeaderText;
|
||||||
_categoryNameTextNode.TextColor = value.Category.Color;
|
_categoryNameTextNode.TextColor = value.Category.Color;
|
||||||
_categoryNameTextNode.TooltipString = value.Category.Description;
|
_categoryNameTextNode.TextTooltip = value.Category.Description;
|
||||||
|
|
||||||
UpdateItemGrid();
|
UpdateItemGrid();
|
||||||
RecalculateSize();
|
RecalculateSize();
|
||||||
@@ -209,7 +210,7 @@ public class InventoryCategoryNode : SimpleComponentNode
|
|||||||
CreateInventoryDragDropNode);
|
CreateInventoryDragDropNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InventoryDragDropNode CreateInventoryDragDropNode(ItemInfo data)
|
private unsafe InventoryDragDropNode CreateInventoryDragDropNode(ItemInfo data)
|
||||||
{
|
{
|
||||||
InventoryItem item = data.Item;
|
InventoryItem item = data.Item;
|
||||||
|
|
||||||
@@ -228,65 +229,41 @@ public class InventoryCategoryNode : SimpleComponentNode
|
|||||||
},
|
},
|
||||||
IsClickable = true,
|
IsClickable = true,
|
||||||
OnEnd = _ => System.AddonInventoryWindow.ManualInventoryRefresh(),
|
OnEnd = _ => System.AddonInventoryWindow.ManualInventoryRefresh(),
|
||||||
OnPayloadAccepted = (n, p) => OnPayloadAccepted(n, p, data),
|
OnPayloadAccepted = (node, payload) => OnPayloadAccepted(node, payload, data),
|
||||||
OnRollOver = n =>
|
OnRollOver = node =>
|
||||||
{
|
{
|
||||||
BeginHeaderHover();
|
BeginHeaderHover();
|
||||||
n.ShowInventoryItemTooltip(item.Container, item.Slot);
|
node.ShowInventoryItemTooltip(item.Container, item.Slot);
|
||||||
},
|
},
|
||||||
OnRollOut = n =>
|
OnRollOut = node =>
|
||||||
{
|
{
|
||||||
EndHeaderHover();
|
EndHeaderHover();
|
||||||
n.HideTooltip();
|
|
||||||
|
ushort addonId = RaptureAtkUnitManager.Instance()->GetAddonByNode(node)->Id;
|
||||||
|
AtkStage.Instance()->TooltipManager.HideTooltip(addonId);
|
||||||
},
|
},
|
||||||
ItemInfo = data
|
ItemInfo = data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo targetItemInfo)
|
private void OnPayloadAccepted(DragDropNode _, DragDropPayload payload, ItemInfo targetItemInfo)
|
||||||
{
|
{
|
||||||
if (payload.Type != DragDropType.Item && payload.Type != DragDropType.Inventory_Item)
|
Services.Logger.Debug($"[OnPayload] Received payload of type {payload.Type}, Int1={payload.Int1}, Int2={payload.Int2}, RefIndex={payload.ReferenceIndex}, Text={payload.Text}");
|
||||||
|
if (!payload.IsValidInventoryPayload)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var (sourceContainer, sourceSlot) = ResolveSourceFromPayload(payload);
|
InventoryLocation sourceLocation = payload.InventoryLocation;
|
||||||
|
|
||||||
if (sourceContainer == 0)
|
if (!sourceLocation.IsValid)
|
||||||
{
|
{
|
||||||
Services.Logger.Warning($"[OnPayload] Could not resolve source from payload");
|
Services.Logger.Warning($"[OnPayload] Could not resolve source from payload");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryType targetContainer = targetItemInfo.Item.Container;
|
InventoryLocation targetLocation = new InventoryLocation(targetItemInfo.Item.Container, (ushort)targetItemInfo.Item.Slot);
|
||||||
ushort targetSlot = (ushort)targetItemInfo.Item.Slot;
|
|
||||||
|
|
||||||
Services.Logger.Debug($"[OnPayload] Moving {sourceContainer}@{sourceSlot} -> {targetContainer}@{targetSlot}");
|
Services.Logger.Debug($"[OnPayload] Moving {sourceLocation.ToString()} -> {targetLocation.ToString()}");
|
||||||
|
|
||||||
InventoryMoveHelper.MoveItem(sourceContainer, sourceSlot, targetContainer, targetSlot);
|
InventoryMoveHelper.MoveItem(sourceLocation.Container, sourceLocation.Slot, targetLocation.Container, targetLocation.Slot);
|
||||||
}
|
|
||||||
|
|
||||||
private static (InventoryType Container, ushort Slot) ResolveSourceFromPayload(DragDropPayload payload)
|
|
||||||
{
|
|
||||||
if (payload.Type == DragDropType.Inventory_Item)
|
|
||||||
{
|
|
||||||
return ((InventoryType)payload.Int1, (ushort)payload.Int2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int containerId = payload.Int1;
|
|
||||||
int slotIndex = payload.Int2;
|
|
||||||
|
|
||||||
InventoryType sourceContainer = InventoryType.GetInventoryTypeFromContainerId(containerId);
|
|
||||||
|
|
||||||
if (sourceContainer == 0)
|
|
||||||
return (0, 0);
|
|
||||||
|
|
||||||
// For main inventory, resolve the real slot via ItemOrderModule
|
|
||||||
if (sourceContainer.IsMainInventory)
|
|
||||||
{
|
|
||||||
var (realContainer, realSlot) = sourceContainer.GetRealItemLocation(slotIndex);
|
|
||||||
return (realContainer, realSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For other containers (saddlebags, armory, etc.), use the slot directly
|
|
||||||
return (sourceContainer, (ushort)slotIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using AetherBags.Inventory;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
using KamiToolKit;
|
||||||
|
using KamiToolKit.Classes;
|
||||||
|
using KamiToolKit.Classes.Timelines;
|
||||||
|
using KamiToolKit.Nodes;
|
||||||
|
using Lumina.Excel;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using Lumina.Text;
|
||||||
|
using Lumina.Text.ReadOnly;
|
||||||
|
|
||||||
|
namespace AetherBags.Nodes.Inventory;
|
||||||
|
|
||||||
|
public sealed class InventoryNotificationNode : SimpleComponentNode
|
||||||
|
{
|
||||||
|
private readonly SimpleNineGridNode glowNode;
|
||||||
|
private readonly TextNode titleTextNode;
|
||||||
|
private readonly TextNode messageTextNode;
|
||||||
|
|
||||||
|
private static readonly InventoryNotificationState NotificationState = new();
|
||||||
|
|
||||||
|
public InventoryNotificationNode()
|
||||||
|
{
|
||||||
|
AddTimeline(ParentLabels);
|
||||||
|
|
||||||
|
glowNode = new SimpleNineGridNode {
|
||||||
|
TexturePath = "ui/uld/Inventory.tex",
|
||||||
|
TextureSize = new Vector2(56.0f, 56.0f),
|
||||||
|
TextureCoordinates = new Vector2(88.0f, 0.0f),
|
||||||
|
TopOffset = 10,
|
||||||
|
BottomOffset = 10,
|
||||||
|
LeftOffset = 26,
|
||||||
|
RightOffset = 26,
|
||||||
|
};
|
||||||
|
glowNode.AttachNode(this);
|
||||||
|
glowNode.AddTimeline(GlowKeyFrames);
|
||||||
|
|
||||||
|
titleTextNode = new TextNode
|
||||||
|
{
|
||||||
|
Position = new Vector2(0, 10f),
|
||||||
|
FontType = FontType.MiedingerMed,
|
||||||
|
FontSize = 18,
|
||||||
|
TextColor = ColorHelper.GetColor(50),
|
||||||
|
TextOutlineColor = ColorHelper.GetColor(37),
|
||||||
|
TextFlags = TextFlags.Edge,
|
||||||
|
AlignmentType = AlignmentType.Center,
|
||||||
|
};
|
||||||
|
titleTextNode.AttachNode(this);
|
||||||
|
titleTextNode.AddTimeline(TextKeyFrames);
|
||||||
|
|
||||||
|
messageTextNode = new TextNode
|
||||||
|
{
|
||||||
|
Position = new Vector2(0, -10f),
|
||||||
|
FontType = FontType.Axis,
|
||||||
|
FontSize = 14,
|
||||||
|
TextColor = ColorHelper.GetColor(50),
|
||||||
|
TextOutlineColor = ColorHelper.GetColor(37),
|
||||||
|
TextFlags = TextFlags.Edge,
|
||||||
|
AlignmentType = AlignmentType.Center,
|
||||||
|
};
|
||||||
|
messageTextNode.AttachNode(this);
|
||||||
|
messageTextNode.AddTimeline(TextKeyFrames);
|
||||||
|
|
||||||
|
Timeline?.PlayAnimation(17);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSizeChanged()
|
||||||
|
{
|
||||||
|
base.OnSizeChanged();
|
||||||
|
|
||||||
|
glowNode.Size = Size with { Y = 40 };
|
||||||
|
titleTextNode.Size = Size with { Y = 20 };
|
||||||
|
messageTextNode.Size = Size with { Y = 16 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryNotificationType NotificationType
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
field = value;
|
||||||
|
if (value == InventoryNotificationType.None)
|
||||||
|
{
|
||||||
|
titleTextNode.String = string.Empty;
|
||||||
|
messageTextNode.String = string.Empty;
|
||||||
|
Timeline?.PlayAnimation(17); // Hide
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var info = NotificationState.GetNotificationInfo((uint)value);
|
||||||
|
if (info != null)
|
||||||
|
{
|
||||||
|
titleTextNode.SeString = info.Title;
|
||||||
|
messageTextNode.SeString = info.Message;
|
||||||
|
Timeline?.PlayAnimation(101); // Show
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} = InventoryNotificationType.None;
|
||||||
|
|
||||||
|
// Future Zeff, this always goes on a parent
|
||||||
|
private Timeline ParentLabels => new TimelineBuilder()
|
||||||
|
.BeginFrameSet(1, 59)
|
||||||
|
.AddLabel(1, 17, AtkTimelineJumpBehavior.PlayOnce, 0)
|
||||||
|
.AddLabel(10, 101, AtkTimelineJumpBehavior.Start, 0)
|
||||||
|
.AddLabel(25, 102, AtkTimelineJumpBehavior.Start, 0)
|
||||||
|
.AddLabel(59, 0, AtkTimelineJumpBehavior.LoopForever, 102)
|
||||||
|
.EndFrameSet()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Future Zeff, this always goes on a child
|
||||||
|
private Timeline GlowKeyFrames => new TimelineBuilder().BeginFrameSet(15, 59)
|
||||||
|
.AddFrame(10, scale: new Vector2(1.4f, 1.0f), alpha: 0, addColor: new Vector3(128, 128, 128))
|
||||||
|
.AddFrame(15, scale: new Vector2(1.0f, 1.0f), alpha: 255, addColor: new Vector3(128, 128, 128))
|
||||||
|
.AddFrame(21, scale: new Vector2(1.0f, 1.0f), alpha: 255, addColor: new Vector3(0, 0, 0))
|
||||||
|
.AddFrame(40, scale: new Vector2(1.0f, 1.0f), alpha: 255, addColor: new Vector3(0, 0, 0))
|
||||||
|
.AddFrame(46, scale: new Vector2(1.0f, 1.0f), alpha: 255, addColor: new Vector3(10, 10, 10))
|
||||||
|
.AddFrame(59, scale: new Vector2(1.0f, 1.0f), alpha: 255, addColor: new Vector3(0, 0, 0))
|
||||||
|
.EndFrameSet()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Future Zeff, this always goes on a child
|
||||||
|
private Timeline TextKeyFrames => new TimelineBuilder().BeginFrameSet(15, 59)
|
||||||
|
.AddFrame(15, alpha: 0, addColor: new Vector3(128, 128, 128))
|
||||||
|
.AddFrame(18, alpha: 255, addColor: new Vector3(64, 64, 64))
|
||||||
|
.AddFrame(25, alpha: 255, addColor: new Vector3(0, 0, 0))
|
||||||
|
.AddFrame(40, alpha: 255, addColor: new Vector3(0, 0, 0))
|
||||||
|
.AddFrame(46, alpha: 255, addColor: new Vector3(64, 64, 64))
|
||||||
|
.AddFrame(59, alpha: 255, addColor: new Vector3(0, 0, 0))
|
||||||
|
.EndFrameSet()
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ public class Services
|
|||||||
[PluginService] public static IDataManager DataManager { get; set; } = null!;
|
[PluginService] public static IDataManager DataManager { get; set; } = null!;
|
||||||
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
||||||
|
[PluginService] public static IGameGui GameGui { get; private set; } = null!;
|
||||||
[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!;
|
||||||
|
|||||||
+1
-1
Submodule KamiToolKit updated: f16338cf17...9519b07c8d
Reference in New Issue
Block a user