Basic Saddlebags

This commit is contained in:
Zeffuro
2025-12-30 01:25:57 +01:00
parent acdd79f73a
commit 5f73a47fee
9 changed files with 81 additions and 9 deletions
@@ -17,7 +17,8 @@ public class InventoryLifecycles : IDisposable
public InventoryLifecycles() public InventoryLifecycles()
{ {
Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"], PreRefreshHandler); Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"], InventoryPreRefreshHandler);
Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["InventoryBuddy"], InventoryBuddyPreRefreshHandler);
Services.Logger.Verbose("InventoryLifecycles initialized"); Services.Logger.Verbose("InventoryLifecycles initialized");
} }
@@ -32,7 +33,7 @@ public class InventoryLifecycles : IDisposable
values[7] = can use Saddlebags (Agent InventoryBuddy IsActivatable) values[7] = can use Saddlebags (Agent InventoryBuddy IsActivatable)
*/ */
private unsafe void PreRefreshHandler(AddonEvent type, AddonArgs args) private unsafe void InventoryPreRefreshHandler(AddonEvent type, AddonArgs args)
{ {
if (args is not AddonRefreshArgs refreshArgs) if (args is not AddonRefreshArgs refreshArgs)
return; return;
@@ -69,8 +70,23 @@ public class InventoryLifecycles : IDisposable
} }
} }
private void InventoryBuddyPreRefreshHandler(AddonEvent type, AddonArgs args)
{
if (args is not AddonRefreshArgs refreshArgs)
return;
GeneralSettings config = System.Config.General;
if (config.HideGameSaddleBags) refreshArgs.AtkValueCount = 0;
if (config.OpenSaddleBagsWithGameInventory)
{
System.AddonSaddleBagWindow.Toggle();
}
}
public void Dispose() public void Dispose()
{ {
Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"]); Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"]);
Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["InventoryBuddy"]);
} }
} }
+25
View File
@@ -7,6 +7,7 @@ using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Classes;
using KamiToolKit.Nodes; using KamiToolKit.Nodes;
namespace AetherBags.Addons; namespace AetherBags.Addons;
@@ -14,16 +15,20 @@ namespace AetherBags.Addons;
public unsafe class AddonSaddleBagWindow : InventoryAddonBase public unsafe class AddonSaddleBagWindow : InventoryAddonBase
{ {
private readonly SaddleBagState _inventoryState = new(); private readonly SaddleBagState _inventoryState = new();
private TextNode _slotCounterNode = null!;
protected override InventoryStateBase InventoryState => _inventoryState; protected override InventoryStateBase InventoryState => _inventoryState;
protected override bool HasFooter => false; protected override bool HasFooter => false;
protected override bool HasSlotCounter => true;
protected override float MinWindowWidth => 400; protected override float MinWindowWidth => 400;
protected override float MaxWindowWidth => 600; protected override float MaxWindowWidth => 600;
protected override void OnSetup(AtkUnitBase* addon) protected override void OnSetup(AtkUnitBase* addon)
{ {
WindowNode?.AddColor = new Vector3(-16f / 255f, -4f / 255f, 8f / 255f);
CategoriesNode = new WrappingGridNode<InventoryCategoryNode> CategoriesNode = new WrappingGridNode<InventoryCategoryNode>
{ {
Position = ContentStartPosition, Position = ContentStartPosition,
@@ -64,6 +69,19 @@ public unsafe class AddonSaddleBagWindow : InventoryAddonBase
}; };
SettingsButtonNode.AttachNode(this); SettingsButtonNode.AttachNode(this);
_slotCounterNode = new TextNode
{
Position = new Vector2(Size.X - 10, 0),
Size = new Vector2(82, 20),
AlignmentType = AlignmentType.Right,
FontType = FontType.MiedingerMed,
TextFlags = TextFlags.Glare,
TextColor = ColorHelper.GetColor(50),
TextOutlineColor = ColorHelper.GetColor(32) // Could also be Color 65
};
_slotCounterNode.AttachNode(this);
SlotCounterNode = _slotCounterNode;
LayoutContent(); LayoutContent();
Services.AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, "InventoryBuddy", OnSaddleBagUpdate); Services.AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, "InventoryBuddy", OnSaddleBagUpdate);
@@ -74,6 +92,13 @@ public unsafe class AddonSaddleBagWindow : InventoryAddonBase
base.OnSetup(addon); base.OnSetup(addon);
} }
protected override void RefreshCategoriesCore(bool autosize)
{
_slotCounterNode.String = _inventoryState.GetEmptySlotsString();
base.RefreshCategoriesCore(autosize);
}
protected override void OnUpdate(AtkUnitBase* addon) protected override void OnUpdate(AtkUnitBase* addon)
{ {
if (RefreshQueued) if (RefreshQueued)
+11 -3
View File
@@ -21,6 +21,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon
protected WrappingGridNode<InventoryCategoryNode> CategoriesNode = null!; protected WrappingGridNode<InventoryCategoryNode> CategoriesNode = null!;
protected TextInputWithHintNode SearchInputNode = null!; protected TextInputWithHintNode SearchInputNode = null!;
protected InventoryFooterNode FooterNode = null!; protected InventoryFooterNode FooterNode = null!;
protected TextNode? SlotCounterNode { get; set; }
protected CircleButtonNode SettingsButtonNode = null!; protected CircleButtonNode SettingsButtonNode = null!;
protected virtual float MinWindowWidth => 600; protected virtual float MinWindowWidth => 600;
@@ -41,6 +42,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon
protected virtual bool HasFooter => true; protected virtual bool HasFooter => true;
protected virtual bool HasPinning => true; protected virtual bool HasPinning => true;
protected virtual bool HasSlotCounter => false;
public void ManualInventoryRefresh() public void ManualInventoryRefresh()
{ {
@@ -127,10 +129,16 @@ public abstract unsafe class InventoryAddonBase : NativeAddon
Vector2 contentPos = ContentStartPosition; Vector2 contentPos = ContentStartPosition;
Vector2 contentSize = ContentSize; Vector2 contentSize = ContentSize;
float footerH = HasFooter || HasSlotCounter ? FooterHeight : 0;
if (HasFooter) if (HasFooter)
{ {
FooterNode.Position = new Vector2(contentPos.X, contentPos.Y + contentSize.Y - FooterHeight); FooterNode.Position = new Vector2(contentPos.X, contentPos.Y + contentSize.Y - footerH);
FooterNode.Size = new Vector2(contentSize.X, FooterHeight); FooterNode.Size = new Vector2(contentSize.X, footerH);
}
else if (HasSlotCounter && SlotCounterNode != null)
{
SlotCounterNode.Position = new Vector2(contentSize.X -80f, contentPos.Y + contentSize.Y - footerH + 4f);
} }
float gridH = contentSize.Y - (HasFooter ? FooterHeight + FooterTopSpacing : 0); float gridH = contentSize.Y - (HasFooter ? FooterHeight + FooterTopSpacing : 0);
@@ -168,7 +176,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon
float contentWidth = finalWidth - (ContentStartPosition.X * 2); float contentWidth = finalWidth - (ContentStartPosition.X * 2);
float footerSpace = HasFooter ? FooterHeight + FooterTopSpacing : 0; float footerSpace = HasFooter || HasSlotCounter ? FooterHeight + FooterTopSpacing : 0;
float gridBudget = Math.Max(0f, MaxWindowHeight - footerSpace); float gridBudget = Math.Max(0f, MaxWindowHeight - footerSpace);
CategoriesNode.Position = ContentStartPosition; CategoriesNode.Position = ContentStartPosition;
@@ -10,6 +10,8 @@ public class GeneralSettings
public bool CompactStableInsert { get; set; } = true; public bool CompactStableInsert { get; set; } = true;
public bool OpenWithGameInventory { get; set; } = true; public bool OpenWithGameInventory { get; set; } = true;
public bool HideGameInventory { get; set; } = false; public bool HideGameInventory { get; set; } = false;
public bool OpenSaddleBagsWithGameInventory { get; set; } = true;
public bool HideGameSaddleBags { get; set; } = false;
public bool ShowCategoryItemCount { get; set; } = false; public bool ShowCategoryItemCount { get; set; } = false;
public bool LinkItemEnabled { get; set; } = false; public bool LinkItemEnabled { get; set; } = false;
} }
@@ -115,6 +115,9 @@ public static unsafe class InventoryItemExtensions {
if (InventoryManager.Instance()->GetInventoryItemCount(itemId, true) > 0) if (InventoryManager.Instance()->GetInventoryItemCount(itemId, true) > 0)
itemId += 1_000_000; itemId += 1_000_000;
if (!item.Container.IsMainInventory)
return;
AgentInventoryContext.Instance()->UseItem(itemId, type); AgentInventoryContext.Instance()->UseItem(itemId, type);
} }
} }
@@ -165,6 +165,8 @@ public static unsafe class InventoryTypeExtensions
_ => 0, _ => 0,
}; };
public bool IsLoaded => InventoryManager.Instance()->GetInventoryContainer(inventoryType)->IsLoaded;
public bool IsSameContainerGroup(InventoryType other) public bool IsSameContainerGroup(InventoryType other)
=> inventoryType.ContainerGroup == other.ContainerGroup; => inventoryType.ContainerGroup == other.ContainerGroup;
@@ -4,7 +4,6 @@ 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)
{ {
Services.Logger.Debug($"[MoveItem] {sourceContainer}@{sourceSlot} -> {destContainer}@{destSlot}"); Services.Logger.Debug($"[MoveItem] {sourceContainer}@{sourceSlot} -> {destContainer}@{destSlot}");
@@ -266,17 +266,20 @@ public class InventoryCategoryNode : SimpleComponentNode
private void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo targetItemInfo) private void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo targetItemInfo)
{ {
InventoryItem item = targetItemInfo.Item; InventoryItem item = targetItemInfo.Item;
if (!payload.IsValidInventoryPayload) if (! payload.IsValidInventoryPayload)
{ {
Services.Logger.Warning($"[OnPayload] Invalid payload type: {payload.Type}"); Services.Logger.Warning($"[OnPayload] Invalid payload type: {payload.Type}");
return; return;
} }
// Debug: log raw payload values
Services. Logger.Debug($"[OnPayload] Raw payload: Type={payload.Type} Int1={payload.Int1} Int2={payload.Int2}");
InventoryLocation sourceLocation = payload.InventoryLocation; InventoryLocation sourceLocation = payload.InventoryLocation;
if (!sourceLocation.IsValid) 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;
} }
@@ -285,6 +288,11 @@ public class InventoryCategoryNode : SimpleComponentNode
(ushort)item.Slot (ushort)item.Slot
); );
// Debug: log resolved locations
Services.Logger.Debug($"[OnPayload] Source: {sourceLocation. Container} @ {sourceLocation. Slot}");
Services.Logger.Debug($"[OnPayload] Target: {targetLocation.Container} @ {targetLocation.Slot}");
if (sourceLocation.Container.IsSameContainerGroup(targetLocation.Container)) if (sourceLocation.Container.IsSameContainerGroup(targetLocation.Container))
{ {
Services.Logger.Debug($"[OnPayload] Source and target are in the same container group; no move performed"); Services.Logger.Debug($"[OnPayload] Source and target are in the same container group; no move performed");
@@ -294,6 +302,12 @@ public class InventoryCategoryNode : SimpleComponentNode
return; return;
}; };
if (!sourceLocation.Container.IsLoaded || !targetLocation.Container.IsLoaded)
{
Services.Logger.Debug($"[OnPayload] Source or target container is not loaded; cannot move");
return;
}
Services.Logger.Debug($"[OnPayload] Moving {sourceLocation} -> {targetLocation}"); Services.Logger.Debug($"[OnPayload] Moving {sourceLocation} -> {targetLocation}");
InventoryMoveHelper.MoveItem( InventoryMoveHelper.MoveItem(
+3
View File
@@ -80,6 +80,8 @@ public unsafe class Plugin : IDalamudPlugin
_commandHandler.Dispose(); _commandHandler.Dispose();
System.AddonInventoryWindow.Dispose(); System.AddonInventoryWindow.Dispose();
System.AddonSaddleBagWindow.Dispose();
//System.AddonRetainerWindow.Dispose();
System.AddonConfigurationWindow.Dispose(); System.AddonConfigurationWindow.Dispose();
KamiToolKitLibrary.Dispose(); KamiToolKitLibrary.Dispose();
@@ -104,6 +106,7 @@ public unsafe class Plugin : IDalamudPlugin
Util.SaveConfig(System.Config); Util.SaveConfig(System.Config);
InventoryState.TrackLootedItems = false; InventoryState.TrackLootedItems = false;
System.AddonInventoryWindow.Close(); System.AddonInventoryWindow.Close();
System.AddonSaddleBagWindow.Close();
System.AddonConfigurationWindow.Close(); System.AddonConfigurationWindow.Close();
} }
} }