Add attribute-based command management

This commit is contained in:
Asriel Camora
2024-06-19 16:28:06 -07:00
parent 1bfbf6f20e
commit 192c5d4201
2 changed files with 84 additions and 29 deletions
+7 -29
View File
@@ -37,6 +37,7 @@ public sealed class Plugin : IDalamudPlugin
public Chat Chat { get; } public Chat Chat { get; }
public IconManager IconManager { get; } public IconManager IconManager { get; }
public CommunityMacros CommunityMacros { get; } public CommunityMacros CommunityMacros { get; }
public AttributeCommandManager AttributeCommandManager { get; }
public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface) public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface)
{ {
@@ -48,6 +49,7 @@ public sealed class Plugin : IDalamudPlugin
Chat = new(); Chat = new();
IconManager = new(); IconManager = new();
CommunityMacros = new(); CommunityMacros = new();
AttributeCommandManager = new();
var assembly = Assembly.GetExecutingAssembly(); var assembly = Assembly.GetExecutingAssembly();
Version = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion.Split('+')[0]; Version = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion.Split('+')[0];
@@ -72,31 +74,6 @@ public sealed class Plugin : IDalamudPlugin
Service.PluginInterface.UiBuilder.Draw += WindowSystem.Draw; Service.PluginInterface.UiBuilder.Draw += WindowSystem.Draw;
Service.PluginInterface.UiBuilder.OpenConfigUi += OpenSettingsWindow; Service.PluginInterface.UiBuilder.OpenConfigUi += OpenSettingsWindow;
Service.PluginInterface.UiBuilder.OpenMainUi += OpenCraftingLog; 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() 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() public void OpenEmptyMacroEditor()
{ {
var stats = GetDefaultStats(); var stats = GetDefaultStats();
@@ -141,9 +119,11 @@ public sealed class Plugin : IDalamudPlugin
EditorWindow = new(characterStats, recipeData, buffs, actions, setter); 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() => public void ExecuteSuggestedSynthHelperAction() =>
SynthHelperWindow.QueueSuggestedActionExecution(); SynthHelperWindow.QueueSuggestedActionExecution();
[Command(name: "/craftimizer", description: "Open the settings window.")]
public void OpenSettingsWindow() public void OpenSettingsWindow()
{ {
if (SettingsWindow.IsOpen ^= true) if (SettingsWindow.IsOpen ^= true)
@@ -156,6 +136,7 @@ public sealed class Plugin : IDalamudPlugin
SettingsWindow.SelectTab(selectedTabLabel); SettingsWindow.SelectTab(selectedTabLabel);
} }
[Command(name: "/craftmacros", aliases: "/macrolist", description: "Open the crafting macros window.")]
public void OpenMacroListWindow() public void OpenMacroListWindow()
{ {
ListWindow.IsOpen = true; ListWindow.IsOpen = true;
@@ -187,10 +168,7 @@ public sealed class Plugin : IDalamudPlugin
public void Dispose() public void Dispose()
{ {
Service.CommandManager.RemoveHandler("/craftimizer"); AttributeCommandManager.Dispose();
Service.CommandManager.RemoveHandler("/craftmacros");
Service.CommandManager.RemoveHandler("/crafteditor");
Service.CommandManager.RemoveHandler("/craftaction");
SettingsWindow.Dispose(); SettingsWindow.Dispose();
RecipeNoteWindow.Dispose(); RecipeNoteWindow.Dispose();
SynthHelperWindow.Dispose(); SynthHelperWindow.Dispose();
@@ -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<string> RegisteredCommands { get; } = [];
public AttributeCommandManager()
{
var target = Service.Plugin;
foreach (var method in target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
if (method.GetCustomAttribute<CommandAttribute>() is not { } command)
continue;
var takesParams = method.GetParameters().Length != 0;
CommandInfo.HandlerDelegate handler;
if (takesParams)
handler = method.CreateDelegate<CommandInfo.HandlerDelegate>(target);
else
{
var invoker = method.CreateDelegate<Action>(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);
}
}