From 577ced24a462d848375a20f2f977cadbcc7297b9 Mon Sep 17 00:00:00 2001 From: Camille M Date: Wed, 5 Jan 2022 15:46:15 +0100 Subject: [PATCH] refacto (#1) --- .../Attribute/DefaultThresholdAttribute.cs | 14 ++ SamplePlugin/Attribute/SlotAttribute.cs | 14 ++ SamplePlugin/Configuration.cs | 67 ++++---- SamplePlugin/CurrencyAlert.csproj | 4 +- SamplePlugin/Enum/Currency.cs | 32 ++++ SamplePlugin/Helper/EnumHelper.cs | 32 ++++ SamplePlugin/Plugin.cs | 49 ++++-- SamplePlugin/PluginUI.cs | 153 ++++++++++-------- SamplePlugin/currencyAlert.json | 4 +- UIDev/UIDev.csproj | 94 +++++------ 10 files changed, 304 insertions(+), 159 deletions(-) create mode 100644 SamplePlugin/Attribute/DefaultThresholdAttribute.cs create mode 100644 SamplePlugin/Attribute/SlotAttribute.cs create mode 100644 SamplePlugin/Enum/Currency.cs create mode 100644 SamplePlugin/Helper/EnumHelper.cs diff --git a/SamplePlugin/Attribute/DefaultThresholdAttribute.cs b/SamplePlugin/Attribute/DefaultThresholdAttribute.cs new file mode 100644 index 0000000..d3d4fad --- /dev/null +++ b/SamplePlugin/Attribute/DefaultThresholdAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace CurrencyAlert +{ + internal class DefaultThresholdAttribute : Attribute + { + public DefaultThresholdAttribute(int v) + { + Value = v; + } + + public int Value { get; } + } +} \ No newline at end of file diff --git a/SamplePlugin/Attribute/SlotAttribute.cs b/SamplePlugin/Attribute/SlotAttribute.cs new file mode 100644 index 0000000..22de5b9 --- /dev/null +++ b/SamplePlugin/Attribute/SlotAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace CurrencyAlert +{ + internal class SlotAttribute : Attribute + { + public SlotAttribute(int v) + { + Value = v; + } + + public int Value { get; } + } +} \ No newline at end of file diff --git a/SamplePlugin/Configuration.cs b/SamplePlugin/Configuration.cs index 0965943..55a9036 100644 --- a/SamplePlugin/Configuration.cs +++ b/SamplePlugin/Configuration.cs @@ -1,32 +1,37 @@ -using Dalamud.Configuration; -using Dalamud.Plugin; -using System; - -namespace CurrencyAlert -{ - [Serializable] - public class Configuration : IPluginConfiguration - { - public int Version { get; set; } = 1; +using CurrencyAlert.Enum; +using Dalamud.Configuration; +using Dalamud.Plugin; +using System; +using System.Collections.Generic; - public bool PoeticsThresholdEnabled { get; set; } = true; - public int PoeticsThreshold { get; set; } = 1500; - public bool StormSealsThresholdEnabled { get; set; } = true; - public int StormSealsThreshold { get; set; } = 40000; - - // the below exist just to make saving less cumbersome - - [NonSerialized] - private DalamudPluginInterface? pluginInterface; - - public void Initialize(DalamudPluginInterface pluginInterface) - { - this.pluginInterface = pluginInterface; - } - - public void Save() - { - this.pluginInterface!.SavePluginConfig(this); - } - } -} +namespace CurrencyAlert +{ + [Serializable] + public class Configuration : IPluginConfiguration + { + public int Version { get; set; } = 2; + + public Dictionary AlertEnabled { get; set; } = new Dictionary(); + public Dictionary Threshold { get; set; } = new Dictionary(); + + [NonSerialized] + private DalamudPluginInterface? pluginInterface; + + public void Initialize(DalamudPluginInterface pluginInterface) + { + this.pluginInterface = pluginInterface; + + EnumHelper.Each(currency => + { + this.AlertEnabled[currency] = true; + var defaultValue = EnumHelper.GetAttributeOfType(currency); + this.Threshold[currency] = defaultValue.Value; + }); + } + + public void Save() + { + this.pluginInterface!.SavePluginConfig(this); + } + } +} diff --git a/SamplePlugin/CurrencyAlert.csproj b/SamplePlugin/CurrencyAlert.csproj index ed5a11e..a9eeb5e 100644 --- a/SamplePlugin/CurrencyAlert.csproj +++ b/SamplePlugin/CurrencyAlert.csproj @@ -3,10 +3,10 @@ - 0.1.0.0 + 0.2.0.0 Currency Alert - https://github.com/goatcorp/SamplePlugin + https://github.com/Lharz/xiv-currency-alert diff --git a/SamplePlugin/Enum/Currency.cs b/SamplePlugin/Enum/Currency.cs new file mode 100644 index 0000000..1c59e07 --- /dev/null +++ b/SamplePlugin/Enum/Currency.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CurrencyAlert.Enum +{ + public enum Currency + { + [Slot(1), DefaultThreshold(75000)] + StormSeal, + + [Slot(2), DefaultThreshold(75000)] + SerpentSeal, + + [Slot(3), DefaultThreshold(75000)] + FlameSeal, + + [Slot(4), DefaultThreshold(18000)] + WolfMark, + + [Slot(6), DefaultThreshold(1500)] + TomestoneOfPoetics, + + [Slot(8), DefaultThreshold(3500)] + AlliedSeal, + + [Slot(10), DefaultThreshold(1500)] + TomestoneOfAstronomy + } +} diff --git a/SamplePlugin/Helper/EnumHelper.cs b/SamplePlugin/Helper/EnumHelper.cs new file mode 100644 index 0000000..71d48e4 --- /dev/null +++ b/SamplePlugin/Helper/EnumHelper.cs @@ -0,0 +1,32 @@ + using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CurrencyAlert +{ + public static class EnumHelper + { + /// + /// Gets an attribute on an enum field value + /// + /// The type of the attribute you want to retrieve + /// The enum value + /// The attribute of type T that exists on the enum value + /// ().Description;]]> + public static T GetAttributeOfType(this System.Enum enumVal) where T : System.Attribute + { + var type = enumVal.GetType(); + var memInfo = type.GetMember(enumVal.ToString()); + var attributes = memInfo[0].GetCustomAttributes(typeof(T), false); + return (attributes.Length > 0) ? (T)attributes[0] : null; + } + + public static void Each(Action action) + { + foreach (var item in System.Enum.GetValues(typeof(T))) + action((T)item); + } + } +} diff --git a/SamplePlugin/Plugin.cs b/SamplePlugin/Plugin.cs index e2c3c62..fba1b6f 100644 --- a/SamplePlugin/Plugin.cs +++ b/SamplePlugin/Plugin.cs @@ -1,6 +1,9 @@ -using Dalamud.Game.Command; +using CurrencyAlert.Enum; +using Dalamud.Game.Command; +using Dalamud.Game.Gui; using Dalamud.IoC; using Dalamud.Plugin; +using FFXIVClientStructs.FFXIV.Client.Game; using System.IO; using System.Reflection; @@ -15,7 +18,9 @@ namespace CurrencyAlert private DalamudPluginInterface PluginInterface { get; init; } private CommandManager CommandManager { get; init; } private Configuration Configuration { get; init; } - private PluginUI PluginUi { get; init; } + private PluginUI PluginUI { get; init; } + + [PluginService] public static ChatGui Chat { get; private set; } = null!; public Plugin( [RequiredVersion("1.0")] DalamudPluginInterface pluginInterface, @@ -29,20 +34,20 @@ namespace CurrencyAlert // you might normally want to embed resources and load them from the manifest stream var assemblyLocation = Assembly.GetExecutingAssembly().Location; - this.PluginUi = new PluginUI(this.Configuration); + this.PluginUI = new PluginUI(this.Configuration); this.CommandManager.AddHandler(commandName, new CommandInfo(OnCommand) { - HelpMessage = "A useful message to display in /xlhelp" - }); - + HelpMessage = "Lets you configure alert thresholds for various currencies" + }); + this.PluginInterface.UiBuilder.Draw += DrawUI; this.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI; - } - + } + public void Dispose() { - this.PluginUi.Dispose(); + this.PluginUI.Dispose(); this.CommandManager.RemoveHandler(commandName); } @@ -53,12 +58,34 @@ namespace CurrencyAlert private void DrawUI() { - this.PluginUi.Draw(); + // TODO: move this logic elsewhere + unsafe + { + InventoryManager* inventoryManager = InventoryManager.Instance(); + InventoryContainer* currencyContainer = inventoryManager->GetInventoryContainer(InventoryType.Currency); + + EnumHelper.Each(currency => + { + var slot = EnumHelper.GetAttributeOfType(currency).Value; + uint quantity = currencyContainer->GetInventorySlot((int)slot)->Quantity; + + if (this.Configuration.AlertEnabled[currency] && quantity >= this.Configuration.Threshold[currency]) + { + this.PluginUI.AlertVisible[currency] = true; + } + else + { + this.PluginUI.AlertVisible[currency] = false; + } + }); + } + + this.PluginUI.Draw(); } private void DrawConfigUI() { - this.PluginUi.SettingsVisible = true; + this.PluginUI.SettingsVisible = true; } } } diff --git a/SamplePlugin/PluginUI.cs b/SamplePlugin/PluginUI.cs index 6d65e78..adc4ed3 100644 --- a/SamplePlugin/PluginUI.cs +++ b/SamplePlugin/PluginUI.cs @@ -1,20 +1,14 @@ -using FFXIVClientStructs.FFXIV.Client.Game; +using CurrencyAlert.Enum; +using Dalamud.Game.Gui; +using Dalamud.IoC; +using FFXIVClientStructs.FFXIV.Client.Game; using ImGuiNET; using System; +using System.Collections.Generic; using System.Numerics; namespace CurrencyAlert { - public enum CurrencySlot - { - StormSeals = 1, - WolfMarks = 4, - Poetics = 6, - AlliedSeals = 8 - }; - - // It is good to have this be disposable in general, in case you ever need it - // to do any cleanup class PluginUI : IDisposable { private Configuration configuration; @@ -22,103 +16,126 @@ namespace CurrencyAlert private bool settingsVisible = false; public bool SettingsVisible { - get { return this.settingsVisible; } - set { this.settingsVisible = value; } + get { return settingsVisible; } + set { settingsVisible = value; } } - - private bool poeticsAlertVisible = false; - public bool PoeticsAlertVisible + private bool debugVisible = false; + public bool DebugVisible { - get { return this.poeticsAlertVisible; } - set { this.poeticsAlertVisible = value; } + get { return debugVisible; } + set { debugVisible = value; } } + public Dictionary AlertVisible { get; set; } = new Dictionary(); public PluginUI(Configuration configuration) { this.configuration = configuration; + + EnumHelper.Each(currency => this.AlertVisible[currency] = false); } public void Dispose() { } - + public void Draw() { - // This is our only draw handler attached to UIBuilder, so it needs to be - // able to draw any windows we might have open. - // Each method checks its own visibility/state to ensure it only draws when - // it actually makes sense. - // There are other ways to do this, but it is generally best to keep the number of - // draw delegates as low as possible. - DrawMainWindow(); - DrawSettingsWindow(); + + if (this.SettingsVisible) + DrawSettingsWindow(); + + if (this.DebugVisible) + DrawDebugWindow(); } public void DrawMainWindow() { - unsafe + EnumHelper.Each(currency => { - InventoryManager* inventoryManager = InventoryManager.Instance(); - InventoryContainer* currencyContainer = inventoryManager->GetInventoryContainer(InventoryType.Currency); - - // Poetics: 6 - // Wolf Marks: 4 - // Allied Seal: 8 - // Company Seals: 1,2,3 - - uint poetics = currencyContainer->GetInventorySlot((int) CurrencySlot.Poetics)->Quantity; - - bool poeticsThresholdEnabled = this.configuration.PoeticsThresholdEnabled; - uint poeticsThreshold = (uint) this.configuration.PoeticsThreshold; - - PoeticsAlertVisible = poeticsThresholdEnabled && poetics >= poeticsThreshold; - - if (!PoeticsAlertVisible) - { + if (!this.AlertVisible[currency]) return; - } - ImGui.SetNextWindowSize(new Vector2(375, 330), ImGuiCond.FirstUseEver); - ImGui.SetNextWindowSizeConstraints(new Vector2(375, 330), new Vector2(float.MaxValue, float.MaxValue)); + ImGui.SetNextWindowSize(new Vector2(375, 10), ImGuiCond.FirstUseEver); + ImGui.SetNextWindowSizeConstraints(new Vector2(375, 10), new Vector2(float.MaxValue, float.MaxValue)); - if (ImGui.Begin("DEPENSE TES POETICS MERDE", ref this.poeticsAlertVisible, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.AlwaysAutoResize)) + var isVisible = this.AlertVisible[currency]; + + if (ImGui.Begin("Currency Alert", ref isVisible, + ImGuiWindowFlags.NoScrollbar | + ImGuiWindowFlags.NoScrollWithMouse | + ImGuiWindowFlags.AlwaysAutoResize | + ImGuiWindowFlags.NoTitleBar | + ImGuiWindowFlags.NoFocusOnAppearing + )) { - ImGui.Text("DEPENSE TES POETICS MEEEEERDE"); + ImGui.Text($"You need to spend your {currency}"); } ImGui.End(); - } - } + }); + } public void DrawSettingsWindow() { - if (!SettingsVisible) - { - return; - } - - ImGui.SetNextWindowSize(new Vector2(330, 120), ImGuiCond.Always); + ImGui.SetNextWindowSize(new Vector2(400, 600), ImGuiCond.Always); if (ImGui.Begin("Currency Alert Configuration Window", ref this.settingsVisible, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) { - var poeticsThresholdEnabledConfig = this.configuration.PoeticsThresholdEnabled; - - if (ImGui.Checkbox("Poetics Threshold Enabled", ref poeticsThresholdEnabledConfig)) + EnumHelper.Each(currency => { - this.configuration.PoeticsThresholdEnabled = poeticsThresholdEnabledConfig; - this.configuration.Save(); - } + var alertEnabled = this.configuration.AlertEnabled[currency]; - var poeticsThresholdConfig = this.configuration.PoeticsThreshold; + if (ImGui.Checkbox($"{currency.ToString()} Alert Enabled", ref alertEnabled)) + { + this.configuration.AlertEnabled[currency] = alertEnabled; + this.configuration.Save(); + } - if (ImGui.InputInt("Poetics Threshold", ref poeticsThresholdConfig, 1, 1, this.configuration.PoeticsThresholdEnabled ? ImGuiInputTextFlags.None : ImGuiInputTextFlags.ReadOnly)) + var thresholdValue = this.configuration.Threshold[currency]; + + if (ImGui.InputInt($"{currency.ToString()} Threshold Value", ref thresholdValue, 1, 1, + this.configuration.AlertEnabled[currency] ? ImGuiInputTextFlags.None : ImGuiInputTextFlags.ReadOnly)) + { + this.configuration.Threshold[currency] = thresholdValue; + this.configuration.Save(); + } + }); + } + +#if DEBUG + if (ImGui.Button("Open Debug")) + this.DebugVisible = true; +#endif + + ImGui.End(); + } + + public void DrawDebugWindow() + { + ImGui.SetNextWindowSize(new Vector2(375, 330), ImGuiCond.FirstUseEver); + ImGui.SetNextWindowSizeConstraints(new Vector2(375, 330), new Vector2(float.MaxValue, float.MaxValue)); + + if (ImGui.Begin("Currency Alert Debug", ref this.debugVisible)) + { + unsafe { - this.configuration.PoeticsThreshold = poeticsThresholdConfig; - this.configuration.Save(); + InventoryManager* inventoryManager = InventoryManager.Instance(); + InventoryContainer* currencyContainer = inventoryManager->GetInventoryContainer(InventoryType.Currency); + + for (var i = 0; i < 100000; ++i) + { + var item = currencyContainer->GetInventorySlot(i); + + if (item == null) + continue; + + ImGui.Text($"Index: {i} Value: {item->Quantity}"); + } } } + ImGui.End(); } } diff --git a/SamplePlugin/currencyAlert.json b/SamplePlugin/currencyAlert.json index 21877f6..0162245 100644 --- a/SamplePlugin/currencyAlert.json +++ b/SamplePlugin/currencyAlert.json @@ -1,8 +1,8 @@ { "Author": "Lharz Zobby@Ragnarok", "Name": "Currency Alert", - "Punchline": "A short one-liner that shows up in /xlplugins.", - "Description": "A description that shows up in /xlplugins. List any major slash-command(s).", + "Punchline": "Configure alerts thresholds for various currencies.", + "Description": "/currencyalert: show the configuration panel.", "InternalName": "currencyAlert", "ApplicableVersion": "any", "Tags": [ diff --git a/UIDev/UIDev.csproj b/UIDev/UIDev.csproj index 260030e..218daaa 100644 --- a/UIDev/UIDev.csproj +++ b/UIDev/UIDev.csproj @@ -1,45 +1,49 @@ - - - - net5.0-windows - x64 - enable - WinExe - latest - true - - - - $(appdata)\XIVLauncher\addon\Hooks\dev\ - - - - - $(DalamudLibPath)Newtonsoft.Json.dll - - - $(DalamudLibPath)ImGui.NET.dll - - - $(DalamudLibPath)ImGuiScene.dll - - - $(DalamudLibPath)SDL2-CS.dll - - - - - - PreserveNewest - false - - - PreserveNewest - false - - - PreserveNewest - false - - - + + + + net5.0-windows + x64 + enable + WinExe + latest + true + + + + $(appdata)\XIVLauncher\addon\Hooks\dev\ + + + + + $(DalamudLibPath)Newtonsoft.Json.dll + + + $(DalamudLibPath)ImGui.NET.dll + + + $(DalamudLibPath)ImGuiScene.dll + + + $(DalamudLibPath)SDL2-CS.dll + + + + + + PreserveNewest + false + + + PreserveNewest + false + + + PreserveNewest + false + + + + + + +