First iteration of retainer
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentInventory_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9e458ae8a124476099a99b081d71ce27826848_003F26_003F0a847424_003FAgentInventory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentInventory_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9e458ae8a124476099a99b081d71ce27826848_003F26_003F0a847424_003FAgentInventory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentModule_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F62fc9015e2e371da72fd36b5b87887f29d8d66f2fdc2f1947c6a7380f8448e_003FAgentModule_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentRetainerItemTransfer_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9e458ae8a124476099a99b081d71ce27826848_003F91_003F8b3682cb_003FAgentRetainerItemTransfer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentSatisfactionSupply_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb2cd0663609440e590f52980cafc1ba3822648_003F28_003Ffa48b62e_003FAgentSatisfactionSupply_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentSatisfactionSupply_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb2cd0663609440e590f52980cafc1ba3822648_003F28_003Ffa48b62e_003FAgentSatisfactionSupply_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentUpdateFlag_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7097e6bfd2288e8ff8dacc8d1e21863898453e58b9546b9752e0c0a5bed4dc_003FAgentUpdateFlag_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAgentUpdateFlag_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7097e6bfd2288e8ff8dacc8d1e21863898453e58b9546b9752e0c0a5bed4dc_003FAgentUpdateFlag_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAtkValue_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1b966bf9f0d5b3eb39a7ee3ff6ab5c83f5bea8a841eafd7c8a1e55532d2d952_003FAtkValue_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAtkValue_002Ecs_002Fl_003AC_0021_003FUsers_003FJeffro_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1b966bf9f0d5b3eb39a7ee3ff6ab5c83f5bea8a841eafd7c8a1e55532d2d952_003FAtkValue_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public class InventoryLifecycles : IDisposable
|
|||||||
{
|
{
|
||||||
Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"], InventoryPreRefreshHandler);
|
Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["Inventory", "InventoryLarge", "InventoryExpansion"], InventoryPreRefreshHandler);
|
||||||
Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["InventoryBuddy"], InventoryBuddyPreRefreshHandler);
|
Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["InventoryBuddy"], InventoryBuddyPreRefreshHandler);
|
||||||
|
//Services.AddonLifecycle.RegisterListener(AddonEvent.PreRefresh, ["RetainerGrid0"], InventoryRetainerPreRefreshHandler);
|
||||||
Services.Logger.Verbose("InventoryLifecycles initialized");
|
Services.Logger.Verbose("InventoryLifecycles initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ public class InventoryLifecycles : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Inventory/Retainers are not perma open, need some way to close it too.
|
||||||
private void InventoryBuddyPreRefreshHandler(AddonEvent type, AddonArgs args)
|
private void InventoryBuddyPreRefreshHandler(AddonEvent type, AddonArgs args)
|
||||||
{
|
{
|
||||||
if (args is not AddonRefreshArgs refreshArgs)
|
if (args is not AddonRefreshArgs refreshArgs)
|
||||||
@@ -84,9 +86,26 @@ public class InventoryLifecycles : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Inventory/Retainers are not perma open, need some way to close it too.
|
||||||
|
// TODO: Don't have the right retainer prerefresh handler yet.
|
||||||
|
private void InventoryRetainerPreRefreshHandler(AddonEvent type, AddonArgs args)
|
||||||
|
{
|
||||||
|
if (args is not AddonRefreshArgs refreshArgs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GeneralSettings config = System.Config.General;
|
||||||
|
|
||||||
|
if (config.HideGameRetainer) refreshArgs.AtkValueCount = 0;
|
||||||
|
if (config.OpenRetainerWithGameInventory)
|
||||||
|
{
|
||||||
|
System.AddonRetainerWindow.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"]);
|
Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["InventoryBuddy"]);
|
||||||
|
Services.AddonLifecycle.UnregisterListener(AddonEvent.PreRefresh, ["RetainerGrid0"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
using System. Numerics;
|
||||||
|
using AetherBags.Inventory.State;
|
||||||
|
using AetherBags. Nodes. Input;
|
||||||
|
using AetherBags. Nodes. Inventory;
|
||||||
|
using AetherBags. Nodes.Layout;
|
||||||
|
using Dalamud.Game. Addon.Lifecycle;
|
||||||
|
using Dalamud.Game. Addon.Lifecycle.AddonArgTypes;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
using FFXIVClientStructs. FFXIV. Component. GUI;
|
||||||
|
using KamiToolKit.Classes;
|
||||||
|
using KamiToolKit. Nodes;
|
||||||
|
|
||||||
|
namespace AetherBags.Addons;
|
||||||
|
|
||||||
|
public unsafe class AddonRetainerWindow : InventoryAddonBase
|
||||||
|
{
|
||||||
|
private readonly RetainerState _inventoryState = new();
|
||||||
|
private TextNode _slotCounterNode = null!;
|
||||||
|
private TextNode _retainerNameNode = null!;
|
||||||
|
private TextButtonNode _entrustDuplicatesButton = 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 => 700;
|
||||||
|
|
||||||
|
protected override void OnSetup(AtkUnitBase* addon)
|
||||||
|
{
|
||||||
|
WindowNode?.AddColor = new Vector3(8f / 255f, -8f / 255f, -4f / 255f);
|
||||||
|
|
||||||
|
CategoriesNode = new WrappingGridNode<InventoryCategoryNode>
|
||||||
|
{
|
||||||
|
Position = ContentStartPosition,
|
||||||
|
Size = ContentSize,
|
||||||
|
HorizontalSpacing = CategorySpacing,
|
||||||
|
VerticalSpacing = CategorySpacing,
|
||||||
|
TopPadding = 4.0f,
|
||||||
|
BottomPadding = 4.0f,
|
||||||
|
};
|
||||||
|
CategoriesNode.AttachNode(this);
|
||||||
|
|
||||||
|
var size = new Vector2(addon->Size. X / 2.0f, 28.0f);
|
||||||
|
|
||||||
|
var header = addon->WindowHeaderCollisionNode;
|
||||||
|
|
||||||
|
float headerX = header->X;
|
||||||
|
float headerY = header->Y;
|
||||||
|
float headerW = header->Width;
|
||||||
|
float headerH = header->Height;
|
||||||
|
|
||||||
|
float x = headerX + (headerW - size.X) * 0.5f;
|
||||||
|
float y = headerY + (headerH - size.Y) * 0.5f;
|
||||||
|
|
||||||
|
SearchInputNode = new TextInputWithHintNode
|
||||||
|
{
|
||||||
|
Position = new Vector2(x, y),
|
||||||
|
Size = size,
|
||||||
|
OnInputReceived = _ => RefreshCategoriesCore(autosize: false),
|
||||||
|
};
|
||||||
|
SearchInputNode. AttachNode(this);
|
||||||
|
|
||||||
|
SettingsButtonNode = new CircleButtonNode
|
||||||
|
{
|
||||||
|
Position = new Vector2(headerW - 48f, y),
|
||||||
|
Size = new Vector2(28f),
|
||||||
|
Icon = ButtonIcon.GearCog,
|
||||||
|
OnClick = System.AddonConfigurationWindow.Toggle
|
||||||
|
};
|
||||||
|
SettingsButtonNode. AttachNode(this);
|
||||||
|
|
||||||
|
// Retainer name display
|
||||||
|
_retainerNameNode = new TextNode
|
||||||
|
{
|
||||||
|
Position = new Vector2(8f, 0),
|
||||||
|
Size = new Vector2(200, 20),
|
||||||
|
AlignmentType = AlignmentType.Left,
|
||||||
|
FontType = FontType.MiedingerMed,
|
||||||
|
TextFlags = TextFlags.Glare,
|
||||||
|
TextColor = ColorHelper.GetColor(50),
|
||||||
|
TextOutlineColor = ColorHelper.GetColor(32),
|
||||||
|
};
|
||||||
|
_retainerNameNode.AttachNode(this);
|
||||||
|
|
||||||
|
_entrustDuplicatesButton = new TextButtonNode
|
||||||
|
{
|
||||||
|
Size = new Vector2(120, 28),
|
||||||
|
String = "Entrust Duplicates",
|
||||||
|
OnClick = OnEntrustDuplicates,
|
||||||
|
};
|
||||||
|
_entrustDuplicatesButton.AttachNode(this);
|
||||||
|
|
||||||
|
// Slot counter
|
||||||
|
_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),
|
||||||
|
};
|
||||||
|
_slotCounterNode.AttachNode(this);
|
||||||
|
SlotCounterNode = _slotCounterNode;
|
||||||
|
|
||||||
|
LayoutContent();
|
||||||
|
|
||||||
|
Services.AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, ["InventoryRetainer", "InventoryRetainerLarge"], OnRetainerInventoryUpdate);
|
||||||
|
|
||||||
|
_inventoryState.RefreshFromGame();
|
||||||
|
RefreshCategoriesCore(autosize: true);
|
||||||
|
|
||||||
|
base.OnSetup(addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RefreshCategoriesCore(bool autosize)
|
||||||
|
{
|
||||||
|
_slotCounterNode. String = _inventoryState.GetEmptySlotsString();
|
||||||
|
_retainerNameNode.String = RetainerState.CurrentRetainerName;
|
||||||
|
|
||||||
|
base.RefreshCategoriesCore(autosize);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LayoutContent()
|
||||||
|
{
|
||||||
|
base.LayoutContent();
|
||||||
|
|
||||||
|
Vector2 contentPos = ContentStartPosition;
|
||||||
|
Vector2 contentSize = ContentSize;
|
||||||
|
|
||||||
|
float footerY = contentPos.Y + contentSize.Y - FooterHeight + 4f;
|
||||||
|
|
||||||
|
_retainerNameNode. Position = new Vector2(contentPos.X + 8f, footerY);
|
||||||
|
|
||||||
|
float buttonWidth = _entrustDuplicatesButton.Width;
|
||||||
|
float buttonX = contentPos.X + (contentSize.X - buttonWidth) / 2f;
|
||||||
|
_entrustDuplicatesButton.Position = new Vector2(buttonX, footerY - 2f);
|
||||||
|
|
||||||
|
if (SlotCounterNode != null)
|
||||||
|
SlotCounterNode.Position = new Vector2(contentSize.X - 80f, footerY);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUpdate(AtkUnitBase* addon)
|
||||||
|
{
|
||||||
|
if (RefreshQueued)
|
||||||
|
{
|
||||||
|
bool doAutosize = RefreshAutosizeQueued;
|
||||||
|
RefreshQueued = false;
|
||||||
|
RefreshAutosizeQueued = false;
|
||||||
|
|
||||||
|
RefreshCategoriesCore(doAutosize);
|
||||||
|
}
|
||||||
|
|
||||||
|
base. OnUpdate(addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEntrustDuplicates()
|
||||||
|
{
|
||||||
|
// TODO: Implement checking if the retainer bag is def open
|
||||||
|
var agent = AgentModule.Instance()->GetAgentByInternalId(AgentId.Retainer);
|
||||||
|
agent->SendCommand(0, [0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRetainerInventoryUpdate(AddonEvent type, AddonArgs args)
|
||||||
|
{
|
||||||
|
_inventoryState.RefreshFromGame();
|
||||||
|
RefreshCategoriesCore(autosize: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData)
|
||||||
|
{
|
||||||
|
base.OnRequestedUpdate(addon, numberArrayData, stringArrayData);
|
||||||
|
|
||||||
|
_inventoryState.RefreshFromGame();
|
||||||
|
RefreshCategoriesCore(autosize: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSearchText(string searchText)
|
||||||
|
{
|
||||||
|
Services.Framework.RunOnTick(() =>
|
||||||
|
{
|
||||||
|
if (IsOpen) SearchInputNode.SearchString = searchText;
|
||||||
|
RefreshCategoriesCore(autosize: true);
|
||||||
|
}, delayTicks: 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFinalize(AtkUnitBase* addon)
|
||||||
|
{
|
||||||
|
Services.AddonLifecycle.UnregisterListener(OnRetainerInventoryUpdate);
|
||||||
|
|
||||||
|
base.OnFinalize(addon);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon
|
|||||||
|
|
||||||
public void ManualRefresh()
|
public void ManualRefresh()
|
||||||
{
|
{
|
||||||
|
if (!IsOpen) return;
|
||||||
if (!Services.ClientState.IsLoggedIn) return;
|
if (!Services.ClientState.IsLoggedIn) return;
|
||||||
if (_isRefreshing) return;
|
if (_isRefreshing) return;
|
||||||
try
|
try
|
||||||
@@ -61,13 +62,13 @@ public abstract unsafe class InventoryAddonBase : NativeAddon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void RefreshAllInventoryWindows()
|
protected static void RefreshAllInventoryWindows()
|
||||||
{
|
{
|
||||||
Services.Framework.RunOnTick(() =>
|
Services.Framework.RunOnTick(() =>
|
||||||
{
|
{
|
||||||
System.AddonInventoryWindow?.ManualRefresh();
|
System.AddonInventoryWindow?.ManualRefresh();
|
||||||
System.AddonSaddleBagWindow?.ManualRefresh();
|
System.AddonSaddleBagWindow?.ManualRefresh();
|
||||||
//AetherBags.System.AddonRetainerWindow?.ManualRefresh();
|
System.AddonRetainerWindow?.ManualRefresh();
|
||||||
}, delayTicks: 2);
|
}, delayTicks: 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using AetherBags.Helpers;
|
|||||||
using AetherBags.Inventory;
|
using AetherBags.Inventory;
|
||||||
using AetherBags.Inventory.State;
|
using AetherBags.Inventory.State;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
|
||||||
namespace AetherBags.Commands;
|
namespace AetherBags.Commands;
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ public class CommandHandler : IDisposable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCommand(string command, string args)
|
private unsafe void OnCommand(string command, string args)
|
||||||
{
|
{
|
||||||
var argsParts = args.Trim().Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
|
var argsParts = args.Trim().Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var subCommand = argsParts.Length > 0 ? argsParts[0].ToLowerInvariant() : string.Empty;
|
var subCommand = argsParts.Length > 0 ? argsParts[0].ToLowerInvariant() : string.Empty;
|
||||||
@@ -95,6 +96,10 @@ public class CommandHandler : IDisposable
|
|||||||
System.AddonSaddleBagWindow.Toggle();
|
System.AddonSaddleBagWindow.Toggle();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "retainer":
|
||||||
|
System.AddonRetainerWindow.Toggle();
|
||||||
|
break;
|
||||||
|
|
||||||
case "help":
|
case "help":
|
||||||
case "?":
|
case "?":
|
||||||
PrintHelp();
|
PrintHelp();
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ public class GeneralSettings
|
|||||||
public bool HideGameInventory { get; set; } = false;
|
public bool HideGameInventory { get; set; } = false;
|
||||||
public bool OpenSaddleBagsWithGameInventory { get; set; } = true;
|
public bool OpenSaddleBagsWithGameInventory { get; set; } = true;
|
||||||
public bool HideGameSaddleBags { get; set; } = false;
|
public bool HideGameSaddleBags { get; set; } = false;
|
||||||
|
public bool OpenRetainerWithGameInventory { get; set; } = true;
|
||||||
|
public bool HideGameRetainer { 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
|
namespace AetherBags.Extensions;
|
||||||
|
|
||||||
|
public static unsafe class AgentInterfaceExtensions {
|
||||||
|
|
||||||
|
extension(ref AgentInterface agent)
|
||||||
|
{
|
||||||
|
public void SendCommand(uint eventKind, int[] commandValues)
|
||||||
|
{
|
||||||
|
using var returnValue = new AtkValue();
|
||||||
|
var command = stackalloc AtkValue[commandValues.Length];
|
||||||
|
|
||||||
|
for (var index = 0; index < commandValues.Length; index++)
|
||||||
|
{
|
||||||
|
command[index].SetInt(commandValues[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.ReceiveEvent(&returnValue, command, (uint)commandValues.Length, eventKind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -186,6 +186,8 @@ public static unsafe class InventoryScanner
|
|||||||
{
|
{
|
||||||
InventorySourceType.MainBags => InventoryManager.Instance()->GetEmptySlotsInBag(),
|
InventorySourceType.MainBags => InventoryManager.Instance()->GetEmptySlotsInBag(),
|
||||||
InventorySourceType.SaddleBag => GetEmptySlotsInContainer(InventorySourceDefinitions.SaddleBag),
|
InventorySourceType.SaddleBag => GetEmptySlotsInContainer(InventorySourceDefinitions.SaddleBag),
|
||||||
|
InventorySourceType.PremiumSaddleBag => GetEmptySlotsInContainer(InventorySourceDefinitions.PremiumSaddleBag),
|
||||||
|
InventorySourceType.AllSaddleBags => GetEmptySlotsInContainer(InventorySourceDefinitions.AllSaddleBags),
|
||||||
InventorySourceType.Retainer => GetEmptySlotsInContainer(InventorySourceDefinitions.Retainer),
|
InventorySourceType.Retainer => GetEmptySlotsInContainer(InventorySourceDefinitions.Retainer),
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using AetherBags. Inventory.Scanning;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
|
||||||
|
namespace AetherBags. Inventory.State;
|
||||||
|
|
||||||
|
public class RetainerState : InventoryStateBase
|
||||||
|
{
|
||||||
|
public override InventorySourceType SourceType => InventorySourceType.Retainer;
|
||||||
|
public override InventoryType[] Inventories => InventorySourceDefinitions.Retainer;
|
||||||
|
|
||||||
|
|
||||||
|
public static unsafe ulong CurrentRetainerId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var retainerManager = RetainerManager.Instance();
|
||||||
|
if (retainerManager == null) return 0;
|
||||||
|
|
||||||
|
return retainerManager->LastSelectedRetainerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe string CurrentRetainerName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var retainerManager = RetainerManager.Instance();
|
||||||
|
if (retainerManager == null) return string.Empty;
|
||||||
|
|
||||||
|
var retainer = retainerManager->GetActiveRetainer();
|
||||||
|
if (retainer == null) return string.Empty;
|
||||||
|
|
||||||
|
return retainer->NameString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe bool IsRetainerActive
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (! Services.ClientState.IsLoggedIn) return false;
|
||||||
|
|
||||||
|
var retainerManager = RetainerManager. Instance();
|
||||||
|
if (retainerManager == null) return false;
|
||||||
|
|
||||||
|
return retainerManager->LastSelectedRetainerId != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe bool AreContainersLoaded
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsRetainerActive) return false;
|
||||||
|
|
||||||
|
var inventoryManager = InventoryManager.Instance();
|
||||||
|
if (inventoryManager == null) return false;
|
||||||
|
|
||||||
|
var container = inventoryManager->GetInventoryContainer(InventoryType.RetainerPage1);
|
||||||
|
return container != null && container->Size > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanMoveItems => AreContainersLoaded;
|
||||||
|
}
|
||||||
@@ -43,6 +43,13 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
Size = new Vector2(750, 750),
|
Size = new Vector2(750, 750),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
System.AddonRetainerWindow = new AddonRetainerWindow
|
||||||
|
{
|
||||||
|
InternalName = "AetherBags_Retainer",
|
||||||
|
Title = "AetherBags",
|
||||||
|
Size = new Vector2(750, 750),
|
||||||
|
};
|
||||||
|
|
||||||
System.AddonConfigurationWindow = new AddonConfigurationWindow
|
System.AddonConfigurationWindow = new AddonConfigurationWindow
|
||||||
{
|
{
|
||||||
InternalName = "AetherBags Config",
|
InternalName = "AetherBags Config",
|
||||||
@@ -81,7 +88,7 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
|
|
||||||
System.AddonInventoryWindow.Dispose();
|
System.AddonInventoryWindow.Dispose();
|
||||||
System.AddonSaddleBagWindow.Dispose();
|
System.AddonSaddleBagWindow.Dispose();
|
||||||
//System.AddonRetainerWindow.Dispose();
|
System.AddonRetainerWindow.Dispose();
|
||||||
System.AddonConfigurationWindow.Dispose();
|
System.AddonConfigurationWindow.Dispose();
|
||||||
|
|
||||||
KamiToolKitLibrary.Dispose();
|
KamiToolKitLibrary.Dispose();
|
||||||
@@ -107,6 +114,7 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
InventoryState.TrackLootedItems = false;
|
InventoryState.TrackLootedItems = false;
|
||||||
System.AddonInventoryWindow.Close();
|
System.AddonInventoryWindow.Close();
|
||||||
System.AddonSaddleBagWindow.Close();
|
System.AddonSaddleBagWindow.Close();
|
||||||
|
System.AddonRetainerWindow.Close();
|
||||||
System.AddonConfigurationWindow.Close();
|
System.AddonConfigurationWindow.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ public static class System
|
|||||||
{
|
{
|
||||||
public static AddonInventoryWindow AddonInventoryWindow { get; set; } = null!;
|
public static AddonInventoryWindow AddonInventoryWindow { get; set; } = null!;
|
||||||
public static AddonSaddleBagWindow AddonSaddleBagWindow { get; set; } = null!;
|
public static AddonSaddleBagWindow AddonSaddleBagWindow { get; set; } = null!;
|
||||||
//public static AddonRetainerWindow AddonRetainerWindow { get; set; } = null!;
|
public static AddonRetainerWindow AddonRetainerWindow { get; set; } = null!;
|
||||||
public static AddonConfigurationWindow AddonConfigurationWindow { get; set; } = null!;
|
public static AddonConfigurationWindow AddonConfigurationWindow { get; set; } = null!;
|
||||||
public static SystemConfiguration Config { get; set; } = null!;
|
public static SystemConfiguration Config { get; set; } = null!;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user