Very basic IPC AT support

This commit is contained in:
Zeffuro
2026-01-01 22:12:05 +01:00
parent ca2baf917e
commit 6a4fc35c07
12 changed files with 505 additions and 77 deletions
@@ -8,8 +8,10 @@ namespace AetherBags.Configuration;
public class CategorySettings public class CategorySettings
{ {
public bool CategoriesEnabled { get; set; } = true;
public bool GameCategoriesEnabled { get; set; } = true; public bool GameCategoriesEnabled { get; set; } = true;
public bool UserCategoriesEnabled { get; set; } = true; public bool UserCategoriesEnabled { get; set; } = true;
public bool AllaganToolsCategoriesEnabled { get; set; } = false;
public List<UserCategoryDefinition> UserCategories { get; set; } = new(); public List<UserCategoryDefinition> UserCategories { get; set; } = new();
} }
+188
View File
@@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using Dalamud.Plugin.Ipc;
namespace AetherBags.IPC;
public class AllaganToolsIPC : IDisposable
{
private ICallGateSubscriber<bool>? _isInitialized;
private ICallGateSubscriber<bool, bool>? _initialized;
private ICallGateSubscriber<string, Dictionary<uint, uint>>? _getFilterItems;
private ICallGateSubscriber<Dictionary<string, string>>? _getSearchFilters;
private ICallGateSubscriber<string, bool>? _enableUiFilter;
private ICallGateSubscriber<string, bool>? _toggleUiFilter;
public bool IsReady { get; private set; }
/// <summary>
/// Cached filter items. Key = filterKey, Value = (ItemId -> Quantity).
/// </summary>
public Dictionary<string, Dictionary<uint, uint>> CachedFilterItems { get; } = new();
/// <summary>
/// Cached search filters. Key -> Name.
/// </summary>
public Dictionary<string, string> CachedSearchFilters { get; } = new();
/// <summary>
/// Quick lookup: ItemId -> List of filter keys that contain this item.
/// </summary>
public Dictionary<uint, List<string>> ItemToFilters { get; } = new();
public event Action? OnInitialized;
public event Action? OnFiltersRefreshed;
public AllaganToolsIPC()
{
try
{
_isInitialized = Services.PluginInterface.GetIpcSubscriber<bool>("AllaganTools.IsInitialized");
_initialized = Services.PluginInterface.GetIpcSubscriber<bool, bool>("AllaganTools.Initialized");
_getFilterItems = Services.PluginInterface.GetIpcSubscriber<string, Dictionary<uint, uint>>("AllaganTools.GetFilterItems");
_getSearchFilters = Services.PluginInterface.GetIpcSubscriber<Dictionary<string, string>>("AllaganTools.GetSearchFilters");
_enableUiFilter = Services.PluginInterface.GetIpcSubscriber<string, bool>("AllaganTools.EnableUiFilter");
_toggleUiFilter = Services.PluginInterface.GetIpcSubscriber<string, bool>("AllaganTools.ToggleUiFilter");
_initialized.Subscribe(OnAllaganInitialized);
// Check if already initialized
try
{
IsReady = _isInitialized.InvokeFunc();
if (IsReady)
{
RefreshFilters();
}
}
catch
{
IsReady = false;
}
}
catch (Exception ex)
{
Services.Logger.Debug($"Allagan Tools not available: {ex.Message}");
IsReady = false;
}
}
private void OnAllaganInitialized(bool initialized)
{
IsReady = initialized;
if (initialized)
{
Services.Logger.Information("Allagan Tools IPC connected");
RefreshFilters();
OnInitialized?.Invoke();
}
}
/// <summary>
/// Refreshes all cached filter data from Allagan Tools.
/// Call this when you need updated filter information.
/// </summary>
public void RefreshFilters()
{
if (!IsReady) return;
try
{
CachedSearchFilters.Clear();
CachedFilterItems.Clear();
ItemToFilters.Clear();
var filters = _getSearchFilters?.InvokeFunc();
if (filters == null) return;
foreach (var (key, name) in filters)
{
CachedSearchFilters[key] = name;
var items = _getFilterItems?.InvokeFunc(key);
if (items != null && items.Count > 0)
{
CachedFilterItems[key] = items;
// Build reverse lookup
foreach (var itemId in items.Keys)
{
if (!ItemToFilters.TryGetValue(itemId, out var filterList))
{
filterList = new List<string>(capacity: 4);
ItemToFilters[itemId] = filterList;
}
filterList.Add(key);
}
}
}
Services.Logger.Debug($"Refreshed {CachedSearchFilters.Count} Allagan Tools filters, {ItemToFilters.Count} unique items");
OnFiltersRefreshed?.Invoke();
}
catch (Exception ex)
{
Services.Logger.Warning($"Failed to refresh Allagan Tools filters: {ex.Message}");
}
}
/// <summary>
/// Checks if an item is in any Allagan Tools filter.
/// </summary>
public bool IsItemInAnyFilter(uint itemId)
=> ItemToFilters.ContainsKey(itemId);
/// <summary>
/// Gets all filter keys that contain this item.
/// </summary>
public IReadOnlyList<string>? GetFiltersForItem(uint itemId)
=> ItemToFilters.TryGetValue(itemId, out var list) ? list : null;
/// <summary>
/// Gets items from a specific filter. Returns ItemId -> Quantity.
/// </summary>
public Dictionary<uint, uint>? GetFilterItems(string filterKey)
{
// Try cache first
if (CachedFilterItems.TryGetValue(filterKey, out var cached))
return cached;
if (!IsReady) return null;
try
{
return _getFilterItems?.InvokeFunc(filterKey);
}
catch (Exception ex)
{
Services.Logger.Warning($"GetFilterItems failed: {ex.Message}");
return null;
}
}
/// <summary>
/// Gets all available search filters. Returns Key -> Name.
/// </summary>
public Dictionary<string, string>? GetSearchFilters()
{
if (CachedSearchFilters.Count > 0)
return CachedSearchFilters;
if (!IsReady) return null;
try
{
return _getSearchFilters?.InvokeFunc();
}
catch (Exception ex)
{
Services.Logger.Warning($"GetSearchFilters failed: {ex.Message}");
return null;
}
}
public void Dispose()
{
_initialized?.Unsubscribe(OnAllaganInitialized);
}
}
+23
View File
@@ -0,0 +1,23 @@
using System;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
namespace AetherBags.IPC;
public class IPCService : IDisposable
{
public AllaganToolsIPC AllaganTools { get; }
public WotsItIPC WotsIt { get; }
// Future: public BiSBuddyIPC BiSBuddy { get; }
public IPCService()
{
AllaganTools = new AllaganToolsIPC();
WotsIt = new WotsItIPC();
}
public void Dispose()
{
AllaganTools.Dispose();
}
}
+80
View File
@@ -0,0 +1,80 @@
using System;
using Dalamud.Plugin.Ipc;
namespace AetherBags.IPC;
public class WotsItIPC : IDisposable
{
private ICallGateSubscriber<string, string, string, uint, string>? _registerWithSearch;
private ICallGateSubscriber<string, bool>? _invoke;
private ICallGateSubscriber<string, bool>? _unregisterAll;
private string? _searchGuid;
public WotsItIPC()
{
try
{
_registerWithSearch = Services.PluginInterface.GetIpcSubscriber<string, string, string, uint, string>("FA.RegisterWithSearch");
_unregisterAll = Services.PluginInterface.GetIpcSubscriber<string, bool>("FA.UnregisterAll");
_invoke = Services.PluginInterface.GetIpcSubscriber<string, bool>("FA.Invoke");
_invoke.Subscribe(OnInvoke);
Register();
}
catch (Exception ex)
{
Services.Logger.Debug($"WotsIt not available: {ex.Message}");
}
}
private void Register()
{
try
{
UnregisterAll();
_searchGuid = _registerWithSearch?.InvokeFunc(
Services.PluginInterface.InternalName,
"AetherBags: Search Inventory",
"AetherBags Search",
66472 // Icon ID
);
}
catch (Exception ex)
{
Services.Logger.Debug($"Failed to register with WotsIt: {ex.Message}");
}
}
private void OnInvoke(string guid)
{
if (guid == _searchGuid)
{
if (! System.AddonInventoryWindow.IsOpen)
{
System.AddonInventoryWindow.Open();
}
}
}
private bool UnregisterAll()
{
try
{
_unregisterAll?.InvokeFunc(Services.PluginInterface.InternalName);
return true;
}
catch
{
return false;
}
}
public void Dispose()
{
_invoke?.Unsubscribe(OnInvoke);
UnregisterAll();
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using AetherBags.Configuration; using AetherBags.Configuration;
using AetherBags.Inventory.Items; using AetherBags.Inventory.Items;
using KamiToolKit.Classes;
namespace AetherBags.Inventory.Categories; namespace AetherBags.Inventory.Categories;
@@ -18,6 +19,15 @@ public static class CategoryBucketManager
public static bool IsUserCategoryKey(uint key) public static bool IsUserCategoryKey(uint key)
=> (key & UserCategoryKeyFlag) != 0; => (key & UserCategoryKeyFlag) != 0;
private const uint AllaganFilterKeyFlag = 0x4000_0000;
public static uint MakeAllaganFilterKey(int index)
=> AllaganFilterKeyFlag | (uint)(index & 0x3FFF_FFFF);
public static bool IsAllaganFilterKey(uint key)
=> (key & AllaganFilterKeyFlag) != 0 && (key & UserCategoryKeyFlag) == 0;
/// <summary> /// <summary>
/// Resets all buckets for a new refresh cycle. /// Resets all buckets for a new refresh cycle.
/// </summary> /// </summary>
@@ -148,6 +158,74 @@ public static class CategoryBucketManager
} }
} }
public static void BucketByAllaganFilters(
Dictionary<ulong, ItemInfo> itemInfoByKey,
Dictionary<uint, CategoryBucket> bucketsByKey,
HashSet<ulong> claimedKeys,
bool allaganCategoriesEnabled)
{
if (!allaganCategoriesEnabled) return;
if (! System.IPC.AllaganTools.IsReady) return;
var filters = System.IPC.AllaganTools.CachedSearchFilters;
var filterItems = System.IPC.AllaganTools.CachedFilterItems;
int index = 0;
foreach (var (filterKey, filterName) in filters)
{
if (!filterItems. TryGetValue(filterKey, out var itemIds))
{
index++;
continue;
}
uint bucketKey = MakeAllaganFilterKey(index);
if (!bucketsByKey.TryGetValue(bucketKey, out CategoryBucket? bucket))
{
bucket = new CategoryBucket
{
Key = bucketKey,
Category = new CategoryInfo
{
Name = $"[AT] {filterName}",
Description = $"Allagan Tools filter: {filterName}",
Color = ColorHelper.GetColor(32),
},
Items = new List<ItemInfo>(capacity: 16),
FilteredItems = new List<ItemInfo>(capacity: 16),
Used = true,
};
bucketsByKey. Add(bucketKey, bucket);
}
else
{
bucket.Used = true;
bucket.Category.Name = $"[AT] {filterName}";
}
foreach (var itemKvp in itemInfoByKey)
{
ulong itemKey = itemKvp.Key;
ItemInfo item = itemKvp.Value;
if (claimedKeys.Contains(itemKey))
continue;
if (itemIds.ContainsKey(item.Item.ItemId))
{
bucket.Items.Add(item);
claimedKeys.Add(itemKey);
}
}
if (bucket.Items. Count == 0)
bucket.Used = false;
index++;
}
}
public static void BucketUnclaimedToMisc( public static void BucketUnclaimedToMisc(
Dictionary<ulong, ItemInfo> itemInfoByKey, Dictionary<ulong, ItemInfo> itemInfoByKey,
Dictionary<uint, CategoryBucket> bucketsByKey, Dictionary<uint, CategoryBucket> bucketsByKey,
@@ -215,9 +293,13 @@ public static class CategoryBucketManager
sortedCategoryKeys.Sort((left, right) => sortedCategoryKeys.Sort((left, right) =>
{ {
bool leftCategory = IsUserCategoryKey(left); bool leftUser = IsUserCategoryKey(left);
bool rightCategory = IsUserCategoryKey(right); bool rightUser = IsUserCategoryKey(right);
if (leftCategory != rightCategory) return leftCategory ? -1 : 1; bool leftAllagan = IsAllaganFilterKey(left);
bool rightAllagan = IsAllaganFilterKey(right);
if (leftUser != rightUser) return leftUser ? -1 : 1;
if (leftAllagan != rightAllagan) return leftAllagan ? -1 : 1;
return left.CompareTo(right); return left.CompareTo(right);
}); });
} }
@@ -3,7 +3,6 @@ using System.Linq;
using AetherBags.Configuration; using AetherBags.Configuration;
using AetherBags.Currency; using AetherBags.Currency;
using AetherBags.Inventory.Categories; using AetherBags.Inventory.Categories;
using AetherBags.Inventory.Context;
using AetherBags.Inventory.Items; using AetherBags.Inventory.Items;
using AetherBags.Inventory.Scanning; using AetherBags.Inventory.Scanning;
using Dalamud.Game.Inventory; using Dalamud.Game.Inventory;
@@ -32,68 +31,6 @@ public static unsafe class InventoryState
public static bool Contains(this IReadOnlyCollection<InventoryType> inventoryTypes, GameInventoryType type) public static bool Contains(this IReadOnlyCollection<InventoryType> inventoryTypes, GameInventoryType type)
=> inventoryTypes.Contains((InventoryType)type); => inventoryTypes.Contains((InventoryType)type);
public static void RefreshFromGame()
{
FFXIVClientStructs.FFXIV.Client.Game.InventoryManager* inventoryManager = FFXIVClientStructs.FFXIV.Client.Game.InventoryManager.Instance();
if (inventoryManager == null)
{
ClearAll();
return;
}
var config = System.Config;
InventoryStackMode stackMode = config.General.StackMode;
bool userCategoriesEnabled = config.Categories.UserCategoriesEnabled;
bool gameCategoriesEnabled = config.Categories.GameCategoriesEnabled;
List<UserCategoryDefinition> userCategories = config.Categories.UserCategories.Where(category => category.Enabled).ToList();
Services.Logger.DebugOnly($"RefreshFromGame StackMode={stackMode}");
AggByKey.Clear();
ItemInfoByKey.Clear();
SortedCategoryKeys.Clear();
AllCategories.Clear();
FilteredCategories.Clear();
ClaimedKeys.Clear();
InventoryScanner.ScanBags(inventoryManager, stackMode, AggByKey);
CategoryBucketManager.ResetBuckets(BucketsByKey);
InventoryScanner.BuildItemInfos(AggByKey, ItemInfoByKey);
InventoryContextState.RefreshMaps();
InventoryContextState.RefreshBlockedSlots();
if (userCategoriesEnabled && userCategories.Count > 0)
{
CategoryBucketManager.BucketByUserCategories(
ItemInfoByKey,
userCategories,
BucketsByKey,
ClaimedKeys,
UserCategoriesSortedScratch);
}
if (gameCategoriesEnabled)
{
CategoryBucketManager.BucketByGameCategories(
ItemInfoByKey,
BucketsByKey,
ClaimedKeys,
userCategoriesEnabled);
}
else
{
CategoryBucketManager.BucketUnclaimedToMisc(
ItemInfoByKey,
BucketsByKey,
ClaimedKeys,
userCategoriesEnabled);
}
InventoryScanner.PruneStaleItemInfos(AggByKey, ItemInfoByKey, RemoveKeysScratch);
CategoryBucketManager.SortBucketsAndBuildKeyList(BucketsByKey, SortedCategoryKeys);
CategoryBucketManager.BuildCategorizedList(BucketsByKey, SortedCategoryKeys, AllCategories);
}
public static IReadOnlyList<CategorizedInventory> GetInventoryItemCategories(string filterString = "", bool invert = false) public static IReadOnlyList<CategorizedInventory> GetInventoryItemCategories(string filterString = "", bool invert = false)
{ {
return InventoryFilter.FilterCategories( return InventoryFilter.FilterCategories(
@@ -25,14 +25,14 @@ public abstract class InventoryStateBase
public virtual unsafe void RefreshFromGame() public virtual unsafe void RefreshFromGame()
{ {
FFXIVClientStructs.FFXIV.Client.Game.InventoryManager* inventoryManager = FFXIVClientStructs.FFXIV.Client.Game.InventoryManager.Instance(); InventoryManager* inventoryManager = InventoryManager.Instance();
if (inventoryManager == null) if (inventoryManager == null)
{ {
ClearAll(); ClearAll();
return; return;
} }
var config = AetherBags.System.Config; var config = System.Config;
InventoryStackMode stackMode = config.General.StackMode; InventoryStackMode stackMode = config.General.StackMode;
AggByKey.Clear(); AggByKey.Clear();
@@ -61,8 +61,10 @@ public abstract class InventoryStateBase
protected virtual void ApplyCategories(SystemConfiguration config) protected virtual void ApplyCategories(SystemConfiguration config)
{ {
bool userCategoriesEnabled = config.Categories.UserCategoriesEnabled; bool categoriesEnabled = config.Categories.CategoriesEnabled;
bool gameCategoriesEnabled = config.Categories.GameCategoriesEnabled; bool userCategoriesEnabled = config.Categories.UserCategoriesEnabled && categoriesEnabled;
bool gameCategoriesEnabled = config.Categories.GameCategoriesEnabled && categoriesEnabled;
bool allaganCategoriesEnabled = config.Categories.AllaganToolsCategoriesEnabled && categoriesEnabled;
var userCategories = config.Categories.UserCategories.Where(c => c.Enabled).ToList(); var userCategories = config.Categories.UserCategories.Where(c => c.Enabled).ToList();
if (userCategoriesEnabled && userCategories.Count > 0) if (userCategoriesEnabled && userCategories.Count > 0)
@@ -71,6 +73,12 @@ public abstract class InventoryStateBase
ItemInfoByKey, userCategories, BucketsByKey, ClaimedKeys, UserCategoriesSortedScratch); ItemInfoByKey, userCategories, BucketsByKey, ClaimedKeys, UserCategoriesSortedScratch);
} }
if (allaganCategoriesEnabled)
{
CategoryBucketManager.BucketByAllaganFilters(
ItemInfoByKey, BucketsByKey, ClaimedKeys, allaganCategoriesEnabled);
}
if (gameCategoriesEnabled) if (gameCategoriesEnabled)
{ {
CategoryBucketManager.BucketByGameCategories( CategoryBucketManager.BucketByGameCategories(
@@ -0,0 +1,99 @@
using System.Numerics;
using AetherBags.Configuration;
using AetherBags.Inventory;
using AetherBags.Nodes.Color;
using KamiToolKit.Classes;
using KamiToolKit.Nodes;
namespace AetherBags.Nodes.Configuration.Category;
public sealed class CategoryGeneralConfigurationNode : TabbedVerticalListNode
{
private readonly CheckboxNode _allaganToolsCheckbox;
public CategoryGeneralConfigurationNode()
{
CategorySettings config = System.Config.Categories;
LabelTextNode titleNode = new LabelTextNode
{
Size = Size with { Y = 18 },
String = "Category Configuration",
TextColor = ColorHelper.GetColor(2),
TextOutlineColor = ColorHelper.GetColor(0),
};
AddNode(titleNode);
AddTab(1);
CheckboxNode categoriesEnabled = new CheckboxNode
{
Size = Size with { Y = 18 },
IsVisible = true,
String = "Categories Enabled",
IsChecked = config.CategoriesEnabled,
OnClick = isChecked =>
{
config.CategoriesEnabled = isChecked;
RefreshInventory();
}
};
AddNode(categoriesEnabled);
AddTab(1);
CheckboxNode gameCategoriesEnabled = new CheckboxNode
{
Size = Size with { Y = 18 },
IsVisible = true,
String = "Game Categories",
IsChecked = config.GameCategoriesEnabled,
TextTooltip = "Use the game's built-in item categories (e.g., Arms, Tools, Armor).",
OnClick = isChecked =>
{
config.GameCategoriesEnabled = isChecked;
RefreshInventory();
}
};
AddNode(gameCategoriesEnabled);
CheckboxNode userCategoriesEnabled = new CheckboxNode
{
Size = Size with { Y = 18 },
IsVisible = true,
String = "User Categories",
IsChecked = config.UserCategoriesEnabled,
TextTooltip = "Use your custom-defined categories.",
OnClick = isChecked =>
{
config.UserCategoriesEnabled = isChecked;
RefreshInventory();
}
};
AddNode(userCategoriesEnabled);
bool allaganReady = System.IPC.AllaganTools?.IsReady ?? false;
_allaganToolsCheckbox = new CheckboxNode
{
Size = Size with { Y = 18 },
IsVisible = true,
String = allaganReady ? "Allagan Tools Filters" : "Allagan Tools Filters (Not Available)",
IsChecked = config.AllaganToolsCategoriesEnabled,
IsEnabled = allaganReady,
TextTooltip = allaganReady
? "Use search filters from Allagan Tools as categories. Items matching a filter will be grouped together."
: "Allagan Tools is not installed or not initialized.",
OnClick = isChecked =>
{
config.AllaganToolsCategoriesEnabled = isChecked;
if (isChecked)
{
System.IPC?.AllaganTools?.RefreshFilters();
}
RefreshInventory();
}
};
AddNode(_allaganToolsCheckbox);
}
private void RefreshInventory() => InventoryOrchestrator.RefreshAll(updateMaps: true);
}
@@ -4,7 +4,7 @@ using KamiToolKit.Nodes;
namespace AetherBags.Nodes.Configuration.Category; namespace AetherBags.Nodes.Configuration.Category;
public class CategoryScrollingAreaNode : ScrollingAreaNode<VerticalListNode> public sealed class CategoryScrollingAreaNode : ScrollingAreaNode<VerticalListNode>
{ {
private AddonCategoryConfigurationWindow? _categoryConfigurationAddon; private AddonCategoryConfigurationWindow? _categoryConfigurationAddon;
private readonly TextButtonNode _categoryConfigurationButtonNode; private readonly TextButtonNode _categoryConfigurationButtonNode;
@@ -13,13 +13,15 @@ public class CategoryScrollingAreaNode : ScrollingAreaNode<VerticalListNode>
{ {
InitializeCategoryAddon(); InitializeCategoryAddon();
ContentNode.AddNode(new CategoryGeneralConfigurationNode());
_categoryConfigurationButtonNode = new TextButtonNode _categoryConfigurationButtonNode = new TextButtonNode
{ {
Size = new Vector2(300, 28), Size = new Vector2(300, 28),
String = "Configure Categories", String = "Configure Categories",
OnClick = () => _categoryConfigurationAddon?.Toggle(), OnClick = () => _categoryConfigurationAddon?.Toggle(),
}; };
_categoryConfigurationButtonNode.AttachNode(this); ContentNode.AddNode(_categoryConfigurationButtonNode);
} }
private void InitializeCategoryAddon() { private void InitializeCategoryAddon() {
@@ -55,8 +55,9 @@ public sealed class CurrencyGeneralConfigurationNode : TabbedVerticalListNode
{ {
Size = Size with { Y = 18 }, Size = Size with { Y = 18 },
IsVisible = true, IsVisible = true,
String = "Color When Capped", String = "Color Weekly Cap",
IsChecked = config.ColorWhenCapped, IsChecked = config.ColorWhenCapped,
TextTooltip = "Changes the color of the currency display when you have reached the maximum amount earnable for the current week (e.g., 450/450).",
OnClick = isChecked => OnClick = isChecked =>
{ {
config.ColorWhenCapped = isChecked; config.ColorWhenCapped = isChecked;
@@ -69,7 +70,7 @@ public sealed class CurrencyGeneralConfigurationNode : TabbedVerticalListNode
ColorInputRow cappedCurrencyColorNode = new ColorInputRow ColorInputRow cappedCurrencyColorNode = new ColorInputRow
{ {
Label = "Capped Currency Color", Label = "Weekly Cap Color",
Size = new Vector2(300, 24), Size = new Vector2(300, 24),
CurrentColor = config.CappedColor, CurrentColor = config.CappedColor,
DefaultColor = new CurrencySettings().CappedColor, DefaultColor = new CurrencySettings().CappedColor,
@@ -87,8 +88,9 @@ public sealed class CurrencyGeneralConfigurationNode : TabbedVerticalListNode
{ {
Size = Size with { Y = 18 }, Size = Size with { Y = 18 },
IsVisible = true, IsVisible = true,
String = "Limited Currency Color", String = "Color Max Capacity",
IsChecked = config.ColorWhenLimited, IsChecked = config.ColorWhenLimited,
TextTooltip = "Changes the color of the currency display when your total held amount has reached its maximum capacity (e.g., 2000/2000).",
OnClick = isChecked => OnClick = isChecked =>
{ {
config.ColorWhenLimited = isChecked; config.ColorWhenLimited = isChecked;
@@ -101,7 +103,7 @@ public sealed class CurrencyGeneralConfigurationNode : TabbedVerticalListNode
ColorInputRow limitCurrencyColorNode = new ColorInputRow ColorInputRow limitCurrencyColorNode = new ColorInputRow
{ {
Label = "Color Weekly Limit", Label = "Max Capacity Color",
Size = new Vector2(300, 24), Size = new Vector2(300, 24),
CurrentColor = config.LimitColor, CurrentColor = config.LimitColor,
DefaultColor = new CurrencySettings().LimitColor, DefaultColor = new CurrencySettings().LimitColor,
+4 -1
View File
@@ -6,11 +6,11 @@ using AetherBags.Helpers;
using AetherBags.Hooks; using AetherBags.Hooks;
using AetherBags.Inventory; using AetherBags.Inventory;
using AetherBags.Inventory.State; using AetherBags.Inventory.State;
using AetherBags.IPC;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Plugin; using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using KamiToolKit; using KamiToolKit;
using NotImplementedException = System.NotImplementedException;
namespace AetherBags; namespace AetherBags;
@@ -31,6 +31,8 @@ public unsafe class Plugin : IDalamudPlugin
KamiToolKitLibrary.Initialize(pluginInterface); KamiToolKitLibrary.Initialize(pluginInterface);
System.Config = Util.LoadConfigOrDefault(); System.Config = Util.LoadConfigOrDefault();
System.IPC = new IPCService();
System.AddonInventoryWindow = new AddonInventoryWindow System.AddonInventoryWindow = new AddonInventoryWindow
{ {
InternalName = "AetherBags_MainBags", InternalName = "AetherBags_MainBags",
@@ -79,6 +81,7 @@ public unsafe class Plugin : IDalamudPlugin
public void Dispose() public void Dispose()
{ {
System.IPC.Dispose();
Util.SaveConfig(System.Config); Util.SaveConfig(System.Config);
Services.ClientState.Login -= OnLogin; Services.ClientState.Login -= OnLogin;
Services.ClientState.Logout -= OnLogout; Services.ClientState.Logout -= OnLogout;
+2
View File
@@ -1,5 +1,6 @@
using AetherBags.Addons; using AetherBags.Addons;
using AetherBags.Configuration; using AetherBags.Configuration;
using AetherBags.IPC;
namespace AetherBags; namespace AetherBags;
@@ -9,5 +10,6 @@ public static class System
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 IPCService IPC { get; set; } = null!;
public static SystemConfiguration Config { get; set; } = null!; public static SystemConfiguration Config { get; set; } = null!;
} }