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

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