diff --git a/AetherBags/AddonLifecycles/InventoryLifecycles.cs b/AetherBags/AddonLifecycles/InventoryLifecycles.cs index f534a7e..8f4e53f 100644 --- a/AetherBags/AddonLifecycles/InventoryLifecycles.cs +++ b/AetherBags/AddonLifecycles/InventoryLifecycles.cs @@ -17,7 +17,8 @@ public class InventoryLifecycles : IDisposable 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"); } @@ -32,7 +33,7 @@ public class InventoryLifecycles : IDisposable 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) 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() { Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"]); + Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["InventoryBuddy"]); } } \ No newline at end of file diff --git a/AetherBags/Addons/AddonSaddleBagWindow.cs b/AetherBags/Addons/AddonSaddleBagWindow.cs index 5078b3b..361da3e 100644 --- a/AetherBags/Addons/AddonSaddleBagWindow.cs +++ b/AetherBags/Addons/AddonSaddleBagWindow.cs @@ -7,6 +7,7 @@ using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; +using KamiToolKit.Classes; using KamiToolKit.Nodes; namespace AetherBags.Addons; @@ -14,16 +15,20 @@ namespace AetherBags.Addons; public unsafe class AddonSaddleBagWindow : InventoryAddonBase { private readonly SaddleBagState _inventoryState = new(); + private TextNode _slotCounterNode = null!; protected override InventoryStateBase InventoryState => _inventoryState; protected override bool HasFooter => false; + protected override bool HasSlotCounter => true; protected override float MinWindowWidth => 400; protected override float MaxWindowWidth => 600; protected override void OnSetup(AtkUnitBase* addon) { + WindowNode?.AddColor = new Vector3(-16f / 255f, -4f / 255f, 8f / 255f); + CategoriesNode = new WrappingGridNode { Position = ContentStartPosition, @@ -64,6 +69,19 @@ public unsafe class AddonSaddleBagWindow : InventoryAddonBase }; 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(); Services.AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, "InventoryBuddy", OnSaddleBagUpdate); @@ -74,6 +92,13 @@ public unsafe class AddonSaddleBagWindow : InventoryAddonBase base.OnSetup(addon); } + protected override void RefreshCategoriesCore(bool autosize) + { + _slotCounterNode.String = _inventoryState.GetEmptySlotsString(); + + base.RefreshCategoriesCore(autosize); + } + protected override void OnUpdate(AtkUnitBase* addon) { if (RefreshQueued) diff --git a/AetherBags/Addons/InventoryAddonBase.cs b/AetherBags/Addons/InventoryAddonBase.cs index 0e83b9a..9dd1f35 100644 --- a/AetherBags/Addons/InventoryAddonBase.cs +++ b/AetherBags/Addons/InventoryAddonBase.cs @@ -21,6 +21,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon protected WrappingGridNode CategoriesNode = null!; protected TextInputWithHintNode SearchInputNode = null!; protected InventoryFooterNode FooterNode = null!; + protected TextNode? SlotCounterNode { get; set; } protected CircleButtonNode SettingsButtonNode = null!; protected virtual float MinWindowWidth => 600; @@ -41,6 +42,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon protected virtual bool HasFooter => true; protected virtual bool HasPinning => true; + protected virtual bool HasSlotCounter => false; public void ManualInventoryRefresh() { @@ -127,10 +129,16 @@ public abstract unsafe class InventoryAddonBase : NativeAddon Vector2 contentPos = ContentStartPosition; Vector2 contentSize = ContentSize; + float footerH = HasFooter || HasSlotCounter ? FooterHeight : 0; + if (HasFooter) { - FooterNode.Position = new Vector2(contentPos.X, contentPos.Y + contentSize.Y - FooterHeight); - FooterNode.Size = new Vector2(contentSize.X, FooterHeight); + FooterNode.Position = new Vector2(contentPos.X, contentPos.Y + contentSize.Y - footerH); + 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); @@ -168,7 +176,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon 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); CategoriesNode.Position = ContentStartPosition; diff --git a/AetherBags/Configuration/GeneralSettings.cs b/AetherBags/Configuration/GeneralSettings.cs index c8e8b3c..e1dd4e1 100644 --- a/AetherBags/Configuration/GeneralSettings.cs +++ b/AetherBags/Configuration/GeneralSettings.cs @@ -10,6 +10,8 @@ public class GeneralSettings public bool CompactStableInsert { get; set; } = true; public bool OpenWithGameInventory { get; set; } = true; 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 LinkItemEnabled { get; set; } = false; } diff --git a/AetherBags/Extensions/InventoryItemExtensions.cs b/AetherBags/Extensions/InventoryItemExtensions.cs index 7189894..1dbe710 100644 --- a/AetherBags/Extensions/InventoryItemExtensions.cs +++ b/AetherBags/Extensions/InventoryItemExtensions.cs @@ -115,6 +115,9 @@ public static unsafe class InventoryItemExtensions { if (InventoryManager.Instance()->GetInventoryItemCount(itemId, true) > 0) itemId += 1_000_000; + if (!item.Container.IsMainInventory) + return; + AgentInventoryContext.Instance()->UseItem(itemId, type); } } diff --git a/AetherBags/Extensions/InventoryTypeExtensions.cs b/AetherBags/Extensions/InventoryTypeExtensions.cs index 37a2b7d..809642c 100644 --- a/AetherBags/Extensions/InventoryTypeExtensions.cs +++ b/AetherBags/Extensions/InventoryTypeExtensions.cs @@ -165,6 +165,8 @@ public static unsafe class InventoryTypeExtensions _ => 0, }; + public bool IsLoaded => InventoryManager.Instance()->GetInventoryContainer(inventoryType)->IsLoaded; + public bool IsSameContainerGroup(InventoryType other) => inventoryType.ContainerGroup == other.ContainerGroup; diff --git a/AetherBags/Helpers/InventoryMoveHelper.cs b/AetherBags/Helpers/InventoryMoveHelper.cs index 9fef5cc..41e5434 100644 --- a/AetherBags/Helpers/InventoryMoveHelper.cs +++ b/AetherBags/Helpers/InventoryMoveHelper.cs @@ -4,7 +4,6 @@ namespace AetherBags. Helpers; 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) { Services.Logger.Debug($"[MoveItem] {sourceContainer}@{sourceSlot} -> {destContainer}@{destSlot}"); diff --git a/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs b/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs index 8d66311..79321ff 100644 --- a/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs +++ b/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs @@ -266,17 +266,20 @@ public class InventoryCategoryNode : SimpleComponentNode private void OnPayloadAccepted(DragDropNode node, DragDropPayload payload, ItemInfo targetItemInfo) { InventoryItem item = targetItemInfo.Item; - if (!payload.IsValidInventoryPayload) + if (! payload.IsValidInventoryPayload) { Services.Logger.Warning($"[OnPayload] Invalid payload type: {payload.Type}"); 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; - 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; } @@ -285,6 +288,11 @@ public class InventoryCategoryNode : SimpleComponentNode (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)) { 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; }; + 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}"); InventoryMoveHelper.MoveItem( diff --git a/AetherBags/Plugin.cs b/AetherBags/Plugin.cs index 074c8fe..b688706 100644 --- a/AetherBags/Plugin.cs +++ b/AetherBags/Plugin.cs @@ -80,6 +80,8 @@ public unsafe class Plugin : IDalamudPlugin _commandHandler.Dispose(); System.AddonInventoryWindow.Dispose(); + System.AddonSaddleBagWindow.Dispose(); + //System.AddonRetainerWindow.Dispose(); System.AddonConfigurationWindow.Dispose(); KamiToolKitLibrary.Dispose(); @@ -104,6 +106,7 @@ public unsafe class Plugin : IDalamudPlugin Util.SaveConfig(System.Config); InventoryState.TrackLootedItems = false; System.AddonInventoryWindow.Close(); + System.AddonSaddleBagWindow.Close(); System.AddonConfigurationWindow.Close(); } } \ No newline at end of file