InventoryLocation things

This commit is contained in:
Zeffuro
2025-12-28 20:39:30 +01:00
parent e46be61b1c
commit aeb4fdcb9d
7 changed files with 148 additions and 3 deletions
@@ -20,6 +20,17 @@ public class InventoryLifecycles : IDisposable
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)
{
if (args is not AddonRefreshArgs refreshArgs)
@@ -152,6 +152,7 @@ public class AddonInventoryWindow : NativeAddon
{
base.OnRequestedUpdate(addon, numberArrayData, stringArrayData);
InventoryContextState.RefreshMaps();
InventoryState.RefreshFromGame();
RefreshCategoriesCore(autosize: true);
@@ -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);
}
@@ -10,3 +10,12 @@ public readonly record struct InventoryLocation(InventoryType Container, ushort
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}";
}
+2
View File
@@ -52,6 +52,8 @@ public static unsafe class InventoryState
InventoryScanner.ScanBags(inventoryManager, stackMode, AggByKey);
CategoryBucketManager.ResetBuckets(BucketsByKey);
InventoryScanner.BuildItemInfos(AggByKey, ItemInfoByKey);
InventoryContextState.RefreshMaps();
InventoryContextState.RefreshBlockedSlots();
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();
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)
{
if (string.IsNullOrEmpty(searchTerms))
@@ -6,6 +6,7 @@ using AetherBags.Inventory;
using AetherBags.Nodes.Layout;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Classes;
using KamiToolKit.Nodes;
@@ -213,19 +214,21 @@ public class InventoryCategoryNode : SimpleComponentNode
private unsafe InventoryDragDropNode CreateInventoryDragDropNode(ItemInfo data)
{
InventoryItem item = data.Item;
InventoryMappedLocation location = data.VisualLocation;
return new InventoryDragDropNode
{
Size = new Vector2(42, 46),
Alpha = data.IsEligibleForContext || data.IsSlotBlocked ? 1.0f : 0.4f,
IsVisible = true,
IconId = item.IconId,
AcceptedType = DragDropType.Item,
IsDraggable = true,
IsDraggable = !data.IsSlotBlocked,
Payload = new DragDropPayload
{
Type = DragDropType.Inventory_Item,
Int1 = (int)item.Container,
Int2 = item.Slot,
Int1 = location.Container,
Int2 = location.Slot,
},
IsClickable = true,
OnEnd = _ => System.AddonInventoryWindow.ManualInventoryRefresh(),