PluginCommandManager.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using Dalamud.Game.Command;
  6. using HuntBuddy.Attributes;
  7. namespace HuntBuddy
  8. {
  9. public class PluginCommandManager<THost> : IDisposable
  10. {
  11. private readonly CommandManager _commandManager;
  12. private readonly (string, CommandInfo)[] _pluginCommands;
  13. private readonly THost _host;
  14. public PluginCommandManager(THost host, CommandManager commandManager)
  15. {
  16. this._commandManager = commandManager;
  17. this._host = host;
  18. this._pluginCommands = host!.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public |
  19. BindingFlags.Static | BindingFlags.Instance)
  20. .Where(method => method.GetCustomAttribute<CommandAttribute>() != null)
  21. .SelectMany(GetCommandInfoTuple)
  22. .ToArray();
  23. AddCommandHandlers();
  24. }
  25. // http://codebetter.com/patricksmacchia/2008/11/19/an-easy-and-efficient-way-to-improve-net-code-performances/
  26. // Benchmarking this myself gave similar results, so I'm doing this to somewhat counteract using reflection to access command attributes.
  27. // I like the convenience of attributes, but in principle it's a bit slower to use them as opposed to just initializing CommandInfos directly.
  28. // It's usually sub-1 millisecond anyways, though. It probably doesn't matter at all.
  29. private void AddCommandHandlers()
  30. {
  31. for (var i = 0; i < this._pluginCommands.Length; i++)
  32. {
  33. var (command, commandInfo) = this._pluginCommands[i];
  34. this._commandManager.AddHandler(command, commandInfo);
  35. }
  36. }
  37. private void RemoveCommandHandlers()
  38. {
  39. for (var i = 0; i < this._pluginCommands.Length; i++)
  40. {
  41. var (command, _) = this._pluginCommands[i];
  42. this._commandManager.RemoveHandler(command);
  43. }
  44. }
  45. private IEnumerable<(string, CommandInfo)> GetCommandInfoTuple(MethodInfo method)
  46. {
  47. var handlerDelegate = (CommandInfo.HandlerDelegate)Delegate.CreateDelegate(typeof(CommandInfo.HandlerDelegate), this._host, method);
  48. var command = handlerDelegate.Method.GetCustomAttribute<CommandAttribute>();
  49. var aliases = handlerDelegate.Method.GetCustomAttribute<AliasesAttribute>();
  50. var helpMessage = handlerDelegate.Method.GetCustomAttribute<HelpMessageAttribute>();
  51. var doNotShowInHelp = handlerDelegate.Method.GetCustomAttribute<DoNotShowInHelpAttribute>();
  52. var commandInfo = new CommandInfo(handlerDelegate)
  53. {
  54. HelpMessage = helpMessage?.HelpMessage ?? string.Empty,
  55. ShowInHelp = doNotShowInHelp == null,
  56. };
  57. // Create list of tuples that will be filled with one tuple per alias, in addition to the base command tuple.
  58. var commandInfoTuples = new List<(string, CommandInfo)> { (command!.Command, commandInfo) };
  59. if (aliases != null)
  60. {
  61. // ReSharper disable once LoopCanBeConvertedToQuery
  62. for (var i = 0; i < aliases.Aliases.Length; i++)
  63. {
  64. commandInfoTuples.Add((aliases.Aliases[i], commandInfo));
  65. }
  66. }
  67. return commandInfoTuples;
  68. }
  69. public void Dispose()
  70. {
  71. RemoveCommandHandlers();
  72. GC.SuppressFinalize(this);
  73. }
  74. }
  75. }