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.3 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 certain 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` etc.*).
  12. If, however, you wish to restrict the commands based on the user's
  13. role, you can either create your own 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 own
  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. ## I'm getting an error about `Assembly#GetEntryAssembly`.
  21. You may be confusing [CommandService#AddModulesAsync] with
  22. [CommandService#AddModuleAsync]. The former is used to add modules
  23. via the assembly, while the latter is used to add a single module.
  24. [CommandService#AddModulesAsync]: xref:Discord.Commands.CommandService.AddModulesAsync*
  25. [CommandService#AddModuleAsync]: xref:Discord.Commands.CommandService.AddModuleAsync*
  26. ## What does [Remainder] do in the command signature?
  27. The [RemainderAttribute] leaves the string unparsed, meaning you
  28. don't have to add quotes around the text for the text to be
  29. recognized as a single object. Please note that if your method has
  30. multiple parameters, the remainder attribute can only be applied to
  31. the last parameter.
  32. [!code-csharp[Remainder](samples/Remainder.cs)]
  33. [RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
  34. ## What is a service? Why does my module not hold any data after execution?
  35. In Discord.Net, modules are created similarly to ASP.NET, meaning
  36. that they have a transient nature. This means that they are spawned
  37. every time when a request is received, and are killed from memory
  38. when the execution finishes. This is why you cannot store persistent
  39. data inside a module. To workaround this, consider using a service.
  40. Service is often used to hold data externally, so that they will
  41. persist 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. ## I have a long-running Task in my command, and Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway. What gives?
  51. By default, all commands are executed on the same thread as the
  52. gateway task, which is responsible for keeping the connection from
  53. your client to Discord alive. When you execute a command,
  54. this blocks the gateway from communicating for as long as the command
  55. task is being executed. The library will warn you about any long
  56. running event handler (in this case, the command handler) that
  57. persists for **more than 3 seconds**.
  58. To resolve this, the library has designed a flag called [RunMode].
  59. There are 2 main `RunMode`s.
  60. 1. `RunMode.Sync` (default)
  61. 2. `RunMode.Async`
  62. You can set the `RunMode` either by specifying it individually via
  63. the `CommandAttribute`, or by setting the global default with
  64. the [DefaultRunMode] flag under `CommandServiceConfig`.
  65. # [CommandAttribute](#tab/cmdattrib)
  66. [!code-csharp[Command Attribute](samples/runmode-cmdattrib.cs)]
  67. # [CommandServiceConfig](#tab/cmdconfig)
  68. [!code-csharp[Command Service Config](samples/runmode-cmdconfig.cs)]
  69. ***
  70. ***
  71. > [!IMPORTANT]
  72. > While specifying `RunMode.Async` allows the command to be spun off
  73. > to a different thread instead of the gateway thread,
  74. > keep in mind that there will be **potential consequences**
  75. > by doing so. Before applying this flag, please
  76. > consider whether it is necessary to do so.
  77. >
  78. > Further details regarding `RunMode.Async` can be found below.
  79. [RunMode]: xref:Discord.Commands.RunMode
  80. [CommandAttribute]: xref:Discord.Commands.CommandAttribute
  81. [DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode
  82. ## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default?
  83. `RunMode.Async` works by spawning a new `Task` with an unawaited
  84. [Task.Run], essentially making `ExecuteAsyncInternalAsync`, the task
  85. that is used to invoke the command task, to be finished on a
  86. different thread. This means that [ExecuteAsync] will be forced to
  87. return a successful [ExecuteResult] regardless of the actual
  88. execution result.
  89. The following are the known caveats with `RunMode.Async`,
  90. 1. You can potentially introduce race condition.
  91. 2. Unnecessary overhead caused by [async state machine].
  92. 3. [ExecuteAsync] will immediately return [ExecuteResult] instead of
  93. other result types (this is particularly important for those who wish
  94. to utilize [RuntimeResult] in 2.0).
  95. 4. Exceptions are swallowed.
  96. However, there are ways to remedy some of these.
  97. For #3, in Discord.Net 2.0, the library introduces a new event called
  98. [CommandExecuted], which is raised whenever the command is
  99. **successfully executed**. This event will be raised regardless of
  100. the `RunMode` type and will return the appropriate execution result.
  101. For #4, exceptions are caught in [CommandService#Log] event under
  102. [LogMessage.Exception] as [CommandException].
  103. [Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run
  104. [async state machine]: https://www.red-gate.com/simple-talk/dotnet/net-tools/c-async-what-is-it-and-how-does-it-work/
  105. [ExecuteAsync]: xref:Discord.Commands.CommandService.ExecuteAsync*
  106. [ExecuteResult]: xref:Discord.Commands.ExecuteResult
  107. [RuntimeResult]: xref:Discord.Commands.RuntimeResult
  108. [CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted
  109. [CommandService#Log]: xref:Discord.Commands.CommandService.Log
  110. [LogMessage.Exception]: xref:Discord.LogMessage.Exception*
  111. [CommandException]: xref:Discord.Commands.CommandException