You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

commands.md 6.7 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. ---
  2. uid: FAQ.Commands
  3. title: Questions about Commands
  4. ---
  5. # Command-related Questions
  6. ## How can I restrict some of my commands so only specific users can execute them?
  7. Based on how you want to implement the restrictions, you can use the
  8. built-in [RequireUserPermission] precondition, which allows you to
  9. restrict the command based on the user's current permissions in the
  10. guild or channel (*e.g., `GuildPermission.Administrator`,
  11. `ChannelPermission.ManageMessages`*).
  12. If, however, you wish to restrict the commands based on the user's
  13. role, you can either create your custom precondition or use
  14. Joe4evr's [Preconditions Addons] that provides a few custom
  15. preconditions that aren't provided in the stock library.
  16. Its source can also be used as an example for creating your
  17. custom preconditions.
  18. [RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute
  19. [Preconditions Addons]: https://github.com/Joe4evr/Discord.Addons/tree/master/src/Discord.Addons.Preconditions
  20. ## Why am I getting an error about `Assembly.GetEntryAssembly`?
  21. You may be confusing @Discord.Commands.CommandService.AddModulesAsync*
  22. with @Discord.Commands.CommandService.AddModuleAsync*. The former
  23. is used to add modules via the assembly, while the latter is used to
  24. add a single module.
  25. ## What does [Remainder] do in the command signature?
  26. The [RemainderAttribute] leaves the string unparsed, meaning you
  27. do not have to add quotes around the text for the text to be
  28. recognized as a single object. Please note that if your method has
  29. multiple parameters, the remainder attribute can only be applied to
  30. the last parameter.
  31. [!code-csharp[Remainder](samples/Remainder.cs)]
  32. [RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
  33. ## What is a service? Why does my module not hold any data after execution?
  34. In Discord.Net, modules are created similarly to ASP.NET, meaning
  35. that they have a transient nature; modules are spawned whenever a
  36. request is received, and are killed from memory when the execution
  37. finishes. In other words, you cannot store persistent
  38. data inside a module. Consider using a service if you wish to
  39. workaround this.
  40. Service is often used to hold data externally so that they persist
  41. throughout execution. Think of it like a chest that holds
  42. whatever you throw at it that won't be affected by anything unless
  43. you want it to. Note that you should also learn Microsoft's
  44. implementation of [Dependency Injection] \([video]) before proceeding,
  45. as well as how it works in [Discord.Net](xref:Guides.Commands.DI#usage-in-modules).
  46. A brief example of service and dependency injection can be seen below.
  47. [!code-csharp[DI](samples/DI.cs)]
  48. [Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
  49. [video]: https://www.youtube.com/watch?v=QtDTfn8YxXg
  50. ## Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway, what should I do?
  51. By default, the library warns the user about any long-running event
  52. handler that persists for **more than 3 seconds**. Any event
  53. handlers that are run on the same thread as the gateway task, the task
  54. in charge of keeping the connection alive, may block the processing of
  55. heartbeat, and thus terminating the connection.
  56. In this case, the library detects that a `MessageReceived`
  57. event handler is blocking the gateway thread. This warning is
  58. typically associated with the command handler as it listens for that
  59. particular event. If the command handler is blocking the thread, then
  60. this **might** mean that you have a long-running command.
  61. > [!NOTE]
  62. > In rare cases, runtime errors can also cause blockage, usually
  63. > associated with Mono, which is not supported by this library.
  64. To prevent a long-running command from blocking the gateway
  65. thread, a flag called [RunMode] is explicitly designed to resolve
  66. this issue.
  67. There are 2 main `RunMode`s.
  68. 1. `RunMode.Sync`
  69. 2. `RunMode.Async`
  70. `Sync` is the default behavior and makes the command to be run on the
  71. same thread as the gateway one. `Async` will spin the task off to a
  72. different thread from the gateway one.
  73. > [!IMPORTANT]
  74. > While specifying `RunMode.Async` allows the command to be spun off
  75. > to a different thread, keep in mind that by doing so, there will be
  76. > **potentially unwanted consequences**. Before applying this flag,
  77. > please consider whether it is necessary to do so.
  78. >
  79. > Further details regarding `RunMode.Async` can be found below.
  80. You can set the `RunMode` either by specifying it individually via
  81. the `CommandAttribute` or by setting the global default with
  82. the [DefaultRunMode] flag under `CommandServiceConfig`.
  83. # [CommandAttribute](#tab/cmdattrib)
  84. [!code-csharp[Command Attribute](samples/runmode-cmdattrib.cs)]
  85. # [CommandServiceConfig](#tab/cmdconfig)
  86. [!code-csharp[Command Service Config](samples/runmode-cmdconfig.cs)]
  87. ***
  88. ***
  89. [RunMode]: xref:Discord.Commands.RunMode
  90. [CommandAttribute]: xref:Discord.Commands.CommandAttribute
  91. [DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode
  92. ## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default?
  93. `RunMode.Async` works by spawning a new `Task` with an unawaited
  94. [Task.Run], essentially making the task that is used to invoke the
  95. command task to be finished on a different thread. This design means
  96. that [ExecuteAsync] will be forced to return a successful
  97. [ExecuteResult] regardless of the actual execution result.
  98. The following are the known caveats with `RunMode.Async`,
  99. 1. You can potentially introduce a race condition.
  100. 2. Unnecessary overhead caused by the [async state machine].
  101. 3. [ExecuteAsync] will immediately return [ExecuteResult] instead of
  102. other result types (this is particularly important for those who wish
  103. to utilize [RuntimeResult] in 2.0).
  104. 4. Exceptions are swallowed.
  105. However, there are ways to remedy some of these.
  106. For #3, in Discord.Net 2.0, the library introduces a new event called
  107. [CommandExecuted], which is raised whenever the command is
  108. **successfully executed**. This event will be raised regardless of
  109. the `RunMode` type and will return the appropriate execution result.
  110. For #4, exceptions are caught in [CommandService.Log] event under
  111. [LogMessage.Exception] as [CommandException].
  112. [Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run
  113. [async state machine]: https://www.red-gate.com/simple-talk/dotnet/net-tools/c-async-what-is-it-and-how-does-it-work/
  114. [ExecuteAsync]: xref:Discord.Commands.CommandService.ExecuteAsync*
  115. [ExecuteResult]: xref:Discord.Commands.ExecuteResult
  116. [RuntimeResult]: xref:Discord.Commands.RuntimeResult
  117. [CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted
  118. [CommandService.Log]: xref:Discord.Commands.CommandService.Log
  119. [LogMessage.Exception]: xref:Discord.LogMessage.Exception*
  120. [CommandException]: xref:Discord.Commands.CommandException