InventoryLocation things
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
{
|
{
|
||||||
base.OnRequestedUpdate(addon, numberArrayData, stringArrayData);
|
base.OnRequestedUpdate(addon, numberArrayData, stringArrayData);
|
||||||
|
|
||||||
|
InventoryContextState.RefreshMaps();
|
||||||
InventoryState.RefreshFromGame();
|
InventoryState.RefreshFromGame();
|
||||||
|
|
||||||
RefreshCategoriesCore(autosize: true);
|
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);
|
||||||
|
}
|
||||||
@@ -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}";
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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.Inventory_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(),
|
||||||
|
|||||||
Reference in New Issue
Block a user