PluginCommandManager.cs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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(
  19. BindingFlags.NonPublic | BindingFlags.Public |
  20. BindingFlags.Static | BindingFlags.Instance)
  21. .Where(method => method.GetCustomAttribute<CommandAttribute>() != null)
  22. .SelectMany(this.GetCommandInfoTuple)
  23. .ToArray();
  24. this.AddCommandHandlers();
  25. }
  26. // http://codebetter.com/patricksmacchia/2008/11/19/an-easy-and-efficient-way-to-improve-net-code-performances/
  27. // Benchmarking this myself gave similar results, so I'm doing this to somewhat counteract using reflection to access command attributes.
  28. // I like the convenience of attributes, but in principle it's a bit slower to use them as opposed to just initializing CommandInfos directly.
  29. // It's usually sub-1 millisecond anyways, though. It probably doesn't matter at all.
  30. private void AddCommandHandlers()
  31. {
  32. foreach (var t in this.pluginCommands)
  33. {
  34. var (command, commandInfo) = t;
  35. this.commandManager.AddHandler(command, commandInfo);
  36. }
  37. }
  38. private void RemoveCommandHandlers()
  39. {
  40. foreach (var t in this.pluginCommands)
  41. {
  42. var (command, _) = t;
  43. this.commandManager.RemoveHandler(command);
  44. }
  45. }
  46. private IEnumerable<(string, CommandInfo)> GetCommandInfoTuple(MethodInfo method)
  47. {
  48. var handlerDelegate = (CommandInfo.HandlerDelegate)Delegate.CreateDelegate(
  49. typeof(CommandInfo.HandlerDelegate),
  50. this.host,
  51. method);
  52. var command = handlerDelegate.Method.GetCustomAttribute<CommandAttribute>();
  53. var aliases = handlerDelegate.Method.GetCustomAttribute<AliasesAttribute>();
  54. var helpMessage = handlerDelegate.Method.GetCustomAttribute<HelpMessageAttribute>();
  55. var doNotShowInHelp = handlerDelegate.Method.GetCustomAttribute<DoNotShowInHelpAttribute>();
  56. var commandInfo = new CommandInfo(handlerDelegate)
  57. {
  58. HelpMessage = helpMessage?.HelpMessage ?? string.Empty,
  59. ShowInHelp = doNotShowInHelp == null,
  60. };
  61. // Create list of tuples that will be filled with one tuple per alias, in addition to the base command tuple.
  62. var commandInfoTuples = new List<(string, CommandInfo)> { (command!.Command, commandInfo) };
  63. if (aliases == null)
  64. {
  65. return commandInfoTuples;
  66. }
  67. // ReSharper disable once LoopCanBeConvertedToQuery
  68. foreach (var t in aliases.Aliases)
  69. {
  70. commandInfoTuples.Add((t, commandInfo));
  71. }
  72. return commandInfoTuples;
  73. }
  74. public void Dispose()
  75. {
  76. this.RemoveCommandHandlers();
  77. GC.SuppressFinalize(this);
  78. }
  79. }
  80. }