using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Dalamud.Game.Command; using HuntBuddy.Attributes; namespace HuntBuddy { public class PluginCommandManager : IDisposable { private readonly CommandManager _commandManager; private readonly (string, CommandInfo)[] _pluginCommands; private readonly THost _host; public PluginCommandManager(THost host, CommandManager commandManager) { this._commandManager = commandManager; this._host = host; this._pluginCommands = host!.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance) .Where(method => method.GetCustomAttribute() != null) .SelectMany(GetCommandInfoTuple) .ToArray(); AddCommandHandlers(); } // http://codebetter.com/patricksmacchia/2008/11/19/an-easy-and-efficient-way-to-improve-net-code-performances/ // Benchmarking this myself gave similar results, so I'm doing this to somewhat counteract using reflection to access command attributes. // I like the convenience of attributes, but in principle it's a bit slower to use them as opposed to just initializing CommandInfos directly. // It's usually sub-1 millisecond anyways, though. It probably doesn't matter at all. private void AddCommandHandlers() { for (var i = 0; i < this._pluginCommands.Length; i++) { var (command, commandInfo) = this._pluginCommands[i]; this._commandManager.AddHandler(command, commandInfo); } } private void RemoveCommandHandlers() { for (var i = 0; i < this._pluginCommands.Length; i++) { var (command, _) = this._pluginCommands[i]; this._commandManager.RemoveHandler(command); } } private IEnumerable<(string, CommandInfo)> GetCommandInfoTuple(MethodInfo method) { var handlerDelegate = (CommandInfo.HandlerDelegate)Delegate.CreateDelegate(typeof(CommandInfo.HandlerDelegate), this._host, method); var command = handlerDelegate.Method.GetCustomAttribute(); var aliases = handlerDelegate.Method.GetCustomAttribute(); var helpMessage = handlerDelegate.Method.GetCustomAttribute(); var doNotShowInHelp = handlerDelegate.Method.GetCustomAttribute(); var commandInfo = new CommandInfo(handlerDelegate) { HelpMessage = helpMessage?.HelpMessage ?? string.Empty, ShowInHelp = doNotShowInHelp == null, }; // Create list of tuples that will be filled with one tuple per alias, in addition to the base command tuple. var commandInfoTuples = new List<(string, CommandInfo)> { (command!.Command, commandInfo) }; if (aliases != null) { // ReSharper disable once LoopCanBeConvertedToQuery for (var i = 0; i < aliases.Aliases.Length; i++) { commandInfoTuples.Add((aliases.Aliases[i], commandInfo)); } } return commandInfoTuples; } public void Dispose() { RemoveCommandHandlers(); GC.SuppressFinalize(this); } } }