Merge remote-tracking branch 'origin/master' into dev/pie-lover

This commit is contained in:
Shawrkie Williams
2025-12-29 04:50:54 -05:00
6 changed files with 157 additions and 8 deletions
@@ -20,6 +20,17 @@ public class InventoryLifecycles : IDisposable
Services.Logger.Verbose("InventoryLifecycles initialized"); Services.Logger.Verbose("InventoryLifecycles initialized");
} }
/*
values[0] = OpenType
values[1] = OpenTitleId
values[2] = tab index
values[3] = InventoryAddonId | (OpenerAddonId << 16)
values[4] = focus
values[5] = title
values[6] = upper title
values[7] = can use Saddlebags (Agent InventoryBuddy IsActivatable)
*/
private unsafe void PreRefreshHandler(AddonEvent type, AddonArgs args) private unsafe void PreRefreshHandler(AddonEvent type, AddonArgs args)
{ {
if (args is not AddonRefreshArgs refreshArgs) if (args is not AddonRefreshArgs refreshArgs)
@@ -0,0 +1,90 @@
using System.Collections.Generic;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Client.UI.Arrays;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
namespace AetherBags.Inventory;
public static unsafe class InventoryContextState
{
private static readonly HashSet<(int page, int slot)> EligibleSlots = new();
private static readonly HashSet<(InventoryType container, int slot)> BlockedSlots = new();
private static readonly Dictionary<InventoryMappedLocation, InventoryMappedLocation> VisualLocationMap = new();
private static uint _lastContextId;
public static void RefreshMaps()
{
EligibleSlots. Clear();
VisualLocationMap. Clear();
var sorter = ItemOrderModule.Instance()->InventorySorter;
if (sorter == null) return;
var agentInventory = AgentInventory.Instance();
bool hasContext = agentInventory != null && agentInventory->OpenTitleId != 0;
_lastContextId = hasContext ? agentInventory->OpenTitleId : 0;
var invArray = hasContext ? InventoryNumberArray.Instance() : null;
int itemsPerPage = sorter->ItemsPerPage;
for (int displayIdx = 0; displayIdx < 140; displayIdx++)
{
var entry = sorter->Items[displayIdx]. Value;
if (entry == null) continue;
int realPage = entry->Page;
int realSlot = entry->Slot;
int visualPage = displayIdx / itemsPerPage;
int visualSlot = displayIdx % itemsPerPage;
int visualContainerId = 48 + visualPage;
VisualLocationMap[new InventoryMappedLocation(realPage, realSlot)] = new InventoryMappedLocation(visualContainerId, visualSlot);
if (hasContext && invArray != null)
{
var itemData = invArray->Items[displayIdx];
if (itemData. IconId == 0) continue;
bool eligible = itemData.ItemFlags.MirageFlag == 0;
if (eligible)
{
EligibleSlots.Add((realPage, realSlot));
}
}
}
}
public static void RefreshBlockedSlots()
{
BlockedSlots.Clear();
var inventoryManager = InventoryManager.Instance();
if (inventoryManager == null) return;
var blockedContainer = inventoryManager->GetInventoryContainer(InventoryType.BlockedItems);
if (blockedContainer == null) return;
for (int i = 0; i < blockedContainer->Size; i++)
{
ref var item = ref blockedContainer->Items[i];
if (item.ItemId == 0) continue;
BlockedSlots.Add((item.Container, item.Slot));
}
}
public static bool IsEligible(int page, int slot)
=> EligibleSlots.Contains((page, slot));
public static bool IsSlotBlocked(InventoryType container, int slot)
=> BlockedSlots.Contains((container, slot));
public static bool HasActiveContext
=> _lastContextId != 0;
public static InventoryMappedLocation GetVisualLocation(int page, int slot)
=> VisualLocationMap.TryGetValue(new InventoryMappedLocation(page, slot), out var result) ? result : new InventoryMappedLocation(48 + page, slot);
}
@@ -8,5 +8,14 @@ public readonly record struct InventoryLocation(InventoryType Container, ushort
public bool IsValid => Container != 0; public bool IsValid => Container != 0;
public override string ToString() => $"{Container}@{Slot}";
}
public readonly record struct InventoryMappedLocation(int Container, int Slot)
{
public static readonly InventoryMappedLocation Invalid = new(0, 0);
public bool IsValid => Container != 0;
public override string ToString() => $"{Container}@{Slot}"; public override string ToString() => $"{Container}@{Slot}";
} }
+2
View File
@@ -52,6 +52,8 @@ public static unsafe class InventoryState
InventoryScanner.ScanBags(inventoryManager, stackMode, AggByKey); InventoryScanner.ScanBags(inventoryManager, stackMode, AggByKey);
CategoryBucketManager.ResetBuckets(BucketsByKey); CategoryBucketManager.ResetBuckets(BucketsByKey);
InventoryScanner.BuildItemInfos(AggByKey, ItemInfoByKey); InventoryScanner.BuildItemInfos(AggByKey, ItemInfoByKey);
InventoryContextState.RefreshMaps();
InventoryContextState.RefreshBlockedSlots();
if (userCategoriesEnabled && userCategories.Count > 0) if (userCategoriesEnabled && userCategories.Count > 0)
{ {
+29
View File
@@ -59,6 +59,35 @@ public sealed class ItemInfo : IEquatable<ItemInfo>
private string Description => _description ??= Row.Description.ToString(); private string Description => _description ??= Row.Description.ToString();
public InventoryMappedLocation VisualLocation =>
IsMainInventory ? InventoryContextState.GetVisualLocation(InventoryPage, Item.Slot)
: new InventoryMappedLocation((int)Item.Container.AgentItemContainerId, Item. Slot);
public int InventoryPage => Item.Container switch
{
InventoryType.Inventory1 => 0,
InventoryType.Inventory2 => 1,
InventoryType.Inventory3 => 2,
InventoryType.Inventory4 => 3,
_ => -1
};
public bool IsSlotBlocked => InventoryContextState.IsSlotBlocked(Item.Container, Item.Slot);
public bool IsEligibleForContext
{
get
{
if (!InventoryContextState.HasActiveContext)
return true;
return IsMainInventory && InventoryContextState.IsEligible(InventoryPage, Item.Slot);
}
}
public bool IsMainInventory => InventoryPage >= 0;
public bool IsRegexMatch(string searchTerms) public bool IsRegexMatch(string searchTerms)
{ {
if (string.IsNullOrEmpty(searchTerms)) if (string.IsNullOrEmpty(searchTerms))
@@ -6,6 +6,7 @@ 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.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Classes; using KamiToolKit.Classes;
using KamiToolKit.Nodes; using KamiToolKit.Nodes;
@@ -213,19 +214,21 @@ public class InventoryCategoryNode : SimpleComponentNode
private unsafe InventoryDragDropNode CreateInventoryDragDropNode(ItemInfo data) private unsafe InventoryDragDropNode CreateInventoryDragDropNode(ItemInfo data)
{ {
InventoryItem item = data.Item; InventoryItem item = data.Item;
InventoryMappedLocation location = data.VisualLocation;
return new InventoryDragDropNode return new InventoryDragDropNode
{ {
Size = new Vector2(42, 46), Size = new Vector2(42, 46),
Alpha = data.IsEligibleForContext || data.IsSlotBlocked ? 1.0f : 0.4f,
IsVisible = true, IsVisible = true,
IconId = item.IconId, IconId = item.IconId,
AcceptedType = DragDropType.Item, AcceptedType = DragDropType.Item,
IsDraggable = true, IsDraggable = !data.IsSlotBlocked,
Payload = new DragDropPayload Payload = new DragDropPayload
{ {
Type = DragDropType.Inventory_Item, Type = DragDropType.Item,
Int1 = (int)item.Container, Int1 = location.Container,
Int2 = item.Slot, Int2 = location.Slot,
}, },
IsClickable = true, IsClickable = true,
OnEnd = _ => System.AddonInventoryWindow.ManualInventoryRefresh(), OnEnd = _ => System.AddonInventoryWindow.ManualInventoryRefresh(),
@@ -248,7 +251,6 @@ public class InventoryCategoryNode : SimpleComponentNode
private void OnPayloadAccepted(DragDropNode _, DragDropPayload payload, ItemInfo targetItemInfo) private void OnPayloadAccepted(DragDropNode _, DragDropPayload payload, ItemInfo targetItemInfo)
{ {
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) if (!payload.IsValidInventoryPayload)
return; return;
@@ -260,10 +262,16 @@ public class InventoryCategoryNode : SimpleComponentNode
return; return;
} }
InventoryLocation targetLocation = new InventoryLocation(targetItemInfo.Item.Container, (ushort)targetItemInfo.Item.Slot); InventoryLocation targetLocation = new InventoryLocation(
targetItemInfo.Item.Container,
(ushort)targetItemInfo.Item.Slot
);
Services.Logger.Debug($"[OnPayload] Moving {sourceLocation.ToString()} -> {targetLocation.ToString()}"); Services.Logger.Debug($"[OnPayload] Moving {sourceLocation} -> {targetLocation}");
InventoryMoveHelper.MoveItem(sourceLocation.Container, sourceLocation.Slot, targetLocation.Container, targetLocation.Slot); InventoryMoveHelper.MoveItem(
sourceLocation.Container, sourceLocation.Slot,
targetLocation.Container, targetLocation.Slot
);
} }
} }