From 192c5d42012f813e0cf1ed5865d665b4f808335e Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Wed, 19 Jun 2024 16:28:06 -0700 Subject: [PATCH] Add attribute-based command management --- Craftimizer/Plugin.cs | 36 ++------- Craftimizer/Utils/AttributeCommandManager.cs | 77 ++++++++++++++++++++ 2 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 Craftimizer/Utils/AttributeCommandManager.cs diff --git a/Craftimizer/Plugin.cs b/Craftimizer/Plugin.cs index 1742bd6..b17dddd 100644 --- a/Craftimizer/Plugin.cs +++ b/Craftimizer/Plugin.cs @@ -37,6 +37,7 @@ public sealed class Plugin : IDalamudPlugin public Chat Chat { get; } public IconManager IconManager { get; } public CommunityMacros CommunityMacros { get; } + public AttributeCommandManager AttributeCommandManager { get; } public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface) { @@ -48,6 +49,7 @@ public sealed class Plugin : IDalamudPlugin Chat = new(); IconManager = new(); CommunityMacros = new(); + AttributeCommandManager = new(); var assembly = Assembly.GetExecutingAssembly(); Version = assembly.GetCustomAttribute()!.InformationalVersion.Split('+')[0]; @@ -72,31 +74,6 @@ public sealed class Plugin : IDalamudPlugin Service.PluginInterface.UiBuilder.Draw += WindowSystem.Draw; Service.PluginInterface.UiBuilder.OpenConfigUi += OpenSettingsWindow; Service.PluginInterface.UiBuilder.OpenMainUi += OpenCraftingLog; - - Service.CommandManager.AddHandler("/craftimizer", new CommandInfo((_, _) => OpenSettingsWindow()) - { - HelpMessage = "Open the settings window.", - }); - Service.CommandManager.AddHandler("/craftmacros", new CommandInfo((_, _) => OpenMacroListWindow()) - { - HelpMessage = "Open the crafting macros window.", - }); - Service.CommandManager.AddHandler("/macrolist", new CommandInfo((_, _) => OpenMacroListWindow()) - { - HelpMessage = "Open the crafting macros window.", - }); - Service.CommandManager.AddHandler("/crafteditor", new CommandInfo((_, _) => OpenEmptyMacroEditor()) - { - HelpMessage = "Open the crafting macro editor.", - }); - Service.CommandManager.AddHandler("/macroeditor", new CommandInfo((_, _) => OpenEmptyMacroEditor()) - { - HelpMessage = "Open the crafting macro editor.", - }); - Service.CommandManager.AddHandler("/craftaction", new CommandInfo((_, _) => ExecuteSuggestedSynthHelperAction()) - { - HelpMessage = "Execute the suggested action in the synthesis helper. Can also be run inside a macro. This command is useful for controller players.", - }); } public (CharacterStats? Character, RecipeData? Recipe, MacroEditor.CrafterBuffs? Buffs) GetOpenedStats() @@ -129,6 +106,7 @@ public sealed class Plugin : IDalamudPlugin ); } + [Command(name: "/crafteditor", aliases: "/macroeditor", description: "Open the crafting macro editor.")] public void OpenEmptyMacroEditor() { var stats = GetDefaultStats(); @@ -141,9 +119,11 @@ public sealed class Plugin : IDalamudPlugin EditorWindow = new(characterStats, recipeData, buffs, actions, setter); } + [Command(name: "/craftaction", description: "Execute the suggested action in the synthesis helper. Can also be run inside a macro. This command is useful for controller players.")] public void ExecuteSuggestedSynthHelperAction() => SynthHelperWindow.QueueSuggestedActionExecution(); + [Command(name: "/craftimizer", description: "Open the settings window.")] public void OpenSettingsWindow() { if (SettingsWindow.IsOpen ^= true) @@ -156,6 +136,7 @@ public sealed class Plugin : IDalamudPlugin SettingsWindow.SelectTab(selectedTabLabel); } + [Command(name: "/craftmacros", aliases: "/macrolist", description: "Open the crafting macros window.")] public void OpenMacroListWindow() { ListWindow.IsOpen = true; @@ -187,10 +168,7 @@ public sealed class Plugin : IDalamudPlugin public void Dispose() { - Service.CommandManager.RemoveHandler("/craftimizer"); - Service.CommandManager.RemoveHandler("/craftmacros"); - Service.CommandManager.RemoveHandler("/crafteditor"); - Service.CommandManager.RemoveHandler("/craftaction"); + AttributeCommandManager.Dispose(); SettingsWindow.Dispose(); RecipeNoteWindow.Dispose(); SynthHelperWindow.Dispose(); diff --git a/Craftimizer/Utils/AttributeCommandManager.cs b/Craftimizer/Utils/AttributeCommandManager.cs new file mode 100644 index 0000000..6710293 --- /dev/null +++ b/Craftimizer/Utils/AttributeCommandManager.cs @@ -0,0 +1,77 @@ +using Craftimizer.Plugin; +using Dalamud.Game.Command; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Craftimizer.Utils; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class CommandAttribute(string name, string description, bool hidden = false, params string[] aliases) : Attribute +{ + public string Name { get; } = name; + public string Description { get; } = description; + public bool Hidden { get; } = hidden; + public string[] Aliases { get; } = aliases; +} + +public sealed class AttributeCommandManager : IDisposable +{ + private HashSet RegisteredCommands { get; } = []; + + public AttributeCommandManager() + { + var target = Service.Plugin; + foreach (var method in target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.GetCustomAttribute() is not { } command) + continue; + + var takesParams = method.GetParameters().Length != 0; + + CommandInfo.HandlerDelegate handler; + if (takesParams) + handler = method.CreateDelegate(target); + else + { + var invoker = method.CreateDelegate(target); + handler = (_, _) => invoker(); + } + + var info = new CommandInfo(handler) + { + HelpMessage = command.Description, + ShowInHelp = !command.Hidden, + }; + + var aliasInfo = new CommandInfo(handler) + { + HelpMessage = $"An alias for {command.Name}", + ShowInHelp = !command.Hidden, + }; + + if (!RegisteredCommands.Add(command.Name)) + throw new InvalidOperationException($"Command '{command.Name}' is already registered."); + + if (!Service.CommandManager.AddHandler(command.Name, info)) + throw new InvalidOperationException($"Failed to register command '{command.Name}'."); + + foreach (var alias in command.Aliases) + { + if (!RegisteredCommands.Add(alias)) + throw new InvalidOperationException($"Command '{alias}' is already registered."); + + if (!Service.CommandManager.AddHandler(alias, aliasInfo)) + throw new InvalidOperationException($"Failed to register command '{alias}'."); + } + } + Log.Debug($"Initalized {RegisteredCommands.Count} commands"); + } + + public void Dispose() + { + foreach (var command in RegisteredCommands) + Service.CommandManager.RemoveHandler(command); + } +}