Merge remote-tracking branch 'origin/master' into dev/pie-lover
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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}";
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
Type = DragDropType.Item,
|
||||
Int1 = location.Container,
|
||||
Int2 = location.Slot,
|
||||
},
|
||||
IsClickable = true,
|
||||
OnEnd = _ => System.AddonInventoryWindow.ManualInventoryRefresh(),
|
||||
@@ -248,7 +251,6 @@ public class InventoryCategoryNode : SimpleComponentNode
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@@ -260,10 +262,16 @@ public class InventoryCategoryNode : SimpleComponentNode
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user