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 13 kB

Improve the Command Service documentation The following changes have been added to this PR: • Fix minor grammatical errors. • Capitalize terms such as Commands, Modules and such, as the context is specific to the lib. • Wrap methods and properties in code blocks. The docs page currently has several issues that remains to be fixed. 1. ```md >[!WARNING] >This article is out of date and has not been rewritten yet. Information is not guaranteed to be accurate. ``` The docs doesn't necessarily seem "out of date" as the warning claims. The basics seem pretty relevant to the latest version of the lib. 2. >“To manually load a module, invoke [CommandService.AddModuleAsync], by passing in the generic type of your module and optionally, a dependency map.” The latter part of the sentence seems off. Where should the user pass the dependency map to? It seems to suggest that `AddModuleAsync` has an argument to pass the dependency to. If it is referring to `AddModuleAsync(Type type)`, then I feel like it should be clarified here - or perhaps change the wording of the sentence. 3. >“First, you need to create an @System.IServiceProvider You may create your own IServiceProvider if you wish.” Any mention of @System.IServiceProvider is currently broken on the docs. 4. >“Submodules are Modules that reside within another one. Typically, submodules are used to create nested groups (although not required to create nested groups).” Clarification on the part after "although?" 5. >“Finally, pass the map into the LoadAssembly method. Your modules will automatically be loaded with this dependency map.” Where is this `LoadAssembly` method? 6. ```md >[!NOTE] >Preconditions can be applied to Modules, Groups, or Commands. ``` The docs should mention `ParameterPreconditionAttribute`'s existence.
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. # The Command Service
  2. >[!WARNING]
  3. >This article is out of date and has not been rewritten yet.
  4. Information is not guaranteed to be accurate.
  5. [Discord.Commands](xref:Discord.Commands) provides an Attribute-based
  6. command parser.
  7. ## Setup
  8. To use Commands, you must create a [Command Service] and a Command
  9. Handler.
  10. Included below is a very barebone Command Handler. You can extend your
  11. Command Handler as much as you like; however, the below is the bare
  12. minimum.
  13. The `CommandService` will optionally accept a [CommandServiceConfig],
  14. which _does_ set a few default values for you. It is recommended to
  15. look over the properties in [CommandServiceConfig] and their default
  16. values.
  17. [!code-csharp[Command Handler](samples/command_handler.cs)]
  18. [Command Service]: xref:Discord.Commands.CommandService
  19. [CommandServiceConfig]: xref:Discord.Commands.CommandServiceConfig
  20. ## With Attributes
  21. In 1.0, Commands can be defined ahead of time with attributes, or at
  22. runtime with builders.
  23. For most bots, ahead-of-time Commands should be all you need, and this
  24. is the recommended method of defining Commands.
  25. ### Modules
  26. The first step to creating Commands is to create a _module_.
  27. A Module is an organizational pattern that allows you to write your
  28. Commands in different classes and have them automatically loaded.
  29. Discord.Net's implementation of Modules is influenced heavily from
  30. ASP.NET Core's Controller pattern. This means that the lifetime of a
  31. module instance is only as long as the Command is being invoked.
  32. **Avoid using long-running code** in your modules wherever possible.
  33. You should **not** be implementing very much logic into your modules,
  34. instead, outsource to a service for that.
  35. If you are unfamiliar with Inversion of Control, it is recommended to
  36. read the MSDN article on [IoC] and [Dependency Injection].
  37. To begin, create a new class somewhere in your project and inherit the
  38. class from [ModuleBase]. This class **must** be `public`.
  39. >[!NOTE]
  40. >[ModuleBase] is an _abstract_ class, meaning that you may extend it
  41. >or override it as you see fit. Your module may inherit from any
  42. >extension of ModuleBase.
  43. By now, your module should look like this:
  44. [!code-csharp[Empty Module](samples/empty-module.cs)]
  45. [IoC]: https://msdn.microsoft.com/en-us/library/ff921087.aspx
  46. [Dependency Injection]: https://msdn.microsoft.com/en-us/library/ff921152.aspx
  47. [ModuleBase]: xref:Discord.Commands.ModuleBase`1
  48. ### Adding Commands
  49. The next step to creating Commands is actually creating the Commands.
  50. To create a Command, add a method to your module of type `Task`.
  51. Typically, you will want to mark this method as `async`, although it
  52. is not required.
  53. Adding parameters to a Command is done by adding parameters to the
  54. parent Task.
  55. For example, to take an integer as an argument from the user, add `int
  56. arg`; to take a user as an argument from the user, add `IUser user`.
  57. In 1.0, a Command can accept nearly any type of argument; a full list
  58. of types that are parsed by default can be found in the below section
  59. on _Type Readers_.
  60. Parameters, by default, are always required. To make a parameter
  61. optional, give it a default value. To accept a comma-separated list,
  62. set the parameter to `params Type[]`.
  63. Should a parameter include spaces, it **must** be wrapped in quotes.
  64. For example, for a Command with a parameter `string food`, you would
  65. execute it with `!favoritefood "Key Lime Pie"`.
  66. If you would like a parameter to parse until the end of a Command,
  67. flag the parameter with the [RemainderAttribute]. This will allow a
  68. user to invoke a Command without wrapping a parameter in quotes.
  69. Finally, flag your Command with the [CommandAttribute] (you must
  70. specify a name for this Command, except for when it is part of a
  71. Module Group - see below).
  72. [RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
  73. [CommandAttribute]: xref:Discord.Commands.CommandAttribute
  74. ### Command Overloads
  75. You may add overloads to your Commands, and the Command parser will
  76. automatically pick up on it.
  77. If for whatever reason, you have two Commands which are ambiguous to
  78. each other, you may use the @Discord.Commands.PriorityAttribute to
  79. specify which should be tested before the other.
  80. The `Priority` attributes are sorted in ascending order; the higher
  81. priority will be called first.
  82. ### Command Context
  83. Every Command can access the execution context through the [Context]
  84. property on [ModuleBase]. `ICommandContext` allows you to access the
  85. message, channel, guild, and user that the Command was invoked from,
  86. as well as the underlying Discord client that the Command was invoked
  87. from.
  88. Different types of Contexts may be specified using the generic variant
  89. of [ModuleBase]. When using a [SocketCommandContext], for example, the
  90. properties on this context will already be Socket entities, so you
  91. will not need to cast them.
  92. To reply to messages, you may also invoke [ReplyAsync], instead of
  93. accessing the channel through the [Context] and sending a message.
  94. > [!WARNING]
  95. >Contexts should **NOT** be mixed! You cannot have one module that
  96. >uses CommandContext and another that uses SocketCommandContext.
  97. [Context]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_Context
  98. [SocketCommandContext]: xref:Discord.Commands.SocketCommandContext
  99. [ReplyAsync]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_ReplyAsync_System_String_System_Boolean_Discord_Embed_Discord_RequestOptions_
  100. ### Example Module
  101. At this point, your module should look comparable to this example:
  102. [!code-csharp[Example Module](samples/module.cs)]
  103. #### Loading Modules Automatically
  104. The Command Service can automatically discover all classes in an
  105. Assembly that inherit [ModuleBase] and load them.
  106. To opt a module out of auto-loading, flag it with
  107. [DontAutoLoadAttribute].
  108. Invoke [CommandService.AddModulesAsync] to discover modules and
  109. install them.
  110. [DontAutoLoadAttribute]: xref:Discord.Commands.DontAutoLoadAttribute
  111. [CommandService.AddModulesAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModulesAsync_Assembly_
  112. #### Loading Modules Manually
  113. To manually load a module, invoke [CommandService.AddModuleAsync], by
  114. passing in the generic type of your module and optionally, a
  115. dependency map.
  116. [CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModuleAsync__1
  117. ### Module Constructors
  118. Modules are constructed using Dependency Injection. Any parameters
  119. that are placed in the Module's constructor must be injected into an
  120. @System.IServiceProvider first. Alternatively, you may accept an
  121. `IServiceProvider` as an argument and extract services yourself.
  122. ### Module Properties
  123. Modules with `public` settable properties will have the dependencies
  124. injected after the construction of the Module.
  125. ### Module Groups
  126. Module Groups allow you to create a module where Commands are
  127. prefixed. To create a group, flag a module with the
  128. @Discord.Commands.GroupAttribute.
  129. Module groups also allow you to create **nameless Commands**, where
  130. the [CommandAttribute] is configured with no name. In this case, the
  131. Command will inherit the name of the group it belongs to.
  132. ### Submodules
  133. Submodules are Modules that reside within another one. Typically,
  134. submodules are used to create nested groups (although not required to
  135. create nested groups).
  136. [!code-csharp[Groups and Submodules](samples/groups.cs)]
  137. ## With Builders
  138. **TODO**
  139. ## Dependency Injection
  140. The Command Service is bundled with a very barebone Dependency
  141. Injection service for your convenience. It is recommended that you use
  142. DI when writing your modules.
  143. ### Setup
  144. First, you need to create an @System.IServiceProvider; you may create
  145. your own one if you wish.
  146. Next, add the dependencies that your modules will use to the map.
  147. Finally, pass the map into the `LoadAssembly` method. Your modules
  148. will be automatically loaded with this dependency map.
  149. [!code-csharp[IServiceProvider Setup](samples/dependency_map_setup.cs)]
  150. ### Usage in Modules
  151. In the constructor of your Module, any parameters will be filled in by
  152. the @System.IServiceProvider that you've passed into `LoadAssembly`.
  153. Any publicly settable properties will also be filled in the same
  154. manner.
  155. >[!NOTE]
  156. > Annotating a property with a `[DontInject]` attribute will prevent the
  157. property from being injected.
  158. >[!NOTE]
  159. >If you accept `CommandService` or `IServiceProvider` as a parameter
  160. in your constructor or as an injectable property, these entries will
  161. be filled by the `CommandService` that the Module is loaded from and
  162. the `ServiceProvider` that is passed into it respectively.
  163. [!code-csharp[ServiceProvider in Modules](samples/dependency_module.cs)]
  164. # Preconditions
  165. Precondition serve as a permissions system for your Commands. Keep in
  166. mind, however, that they are not limited to _just_ permissions and can
  167. be as complex as you want them to be.
  168. >[!NOTE]
  169. >There are two types of Preconditions.
  170. [PreconditionAttribute] can be applied to Modules, Groups, or Commands;
  171. [ParameterPreconditionAttribute] can be applied to Parameters.
  172. [PreconditionAttribute]: xref:Discord.Commands.PreconditionAttribute
  173. [ParameterPreconditionAttribute]: xref:Discord.Commands.ParameterPreconditionAttribute
  174. ## Bundled Preconditions
  175. Commands ship with four bundled Preconditions; you may view their
  176. usages on their respective API pages.
  177. - @Discord.Commands.RequireContextAttribute
  178. - @Discord.Commands.RequireOwnerAttribute
  179. - @Discord.Commands.RequireBotPermissionAttribute
  180. - @Discord.Commands.RequireUserPermissionAttribute
  181. ## Custom Preconditions
  182. To write your own Precondition, create a new class that inherits from
  183. either [PreconditionAttribute] or [ParameterPreconditionAttribute]
  184. depending on your use.
  185. In order for your Precondition to function, you will need to override
  186. the [CheckPermissions] method.
  187. Your IDE should provide an option to fill this in for you.
  188. If the context meets the required parameters, return
  189. [PreconditionResult.FromSuccess], otherwise return
  190. [PreconditionResult.FromError] and include an error message if
  191. necessary.
  192. [!code-csharp[Custom Precondition](samples/require_owner.cs)]
  193. [CheckPermissions]: xref:Discord.Commands.PreconditionAttribute#Discord_Commands_PreconditionAttribute_CheckPermissions_Discord_Commands_ICommandContext_Discord_Commands_CommandInfo_IServiceProvider_
  194. [PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromSuccess
  195. [PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromError_System_String_
  196. # Type Readers
  197. Type Readers allow you to parse different types of arguments in
  198. your commands.
  199. By default, the following Types are supported arguments:
  200. - bool
  201. - char
  202. - sbyte/byte
  203. - ushort/short
  204. - uint/int
  205. - ulong/long
  206. - float, double, decimal
  207. - string
  208. - DateTime/DateTimeOffset/TimeSpan
  209. - IMessage/IUserMessage
  210. - IChannel/IGuildChannel/ITextChannel/IVoiceChannel/IGroupChannel
  211. - IUser/IGuildUser/IGroupUser
  212. - IRole
  213. ### Creating a Type Readers
  214. To create a `TypeReader`, create a new class that imports @Discord and
  215. @Discord.Commands and ensure the class inherits from
  216. @Discord.Commands.TypeReader.
  217. Next, satisfy the `TypeReader` class by overriding the [Read] method.
  218. >[!NOTE]
  219. >In many cases, Visual Studio can fill this in for you, using the
  220. >"Implement Abstract Class" IntelliSense hint.
  221. Inside this task, add whatever logic you need to parse the input
  222. string.
  223. If you are able to successfully parse the input, return
  224. [TypeReaderResult.FromSuccess] with the parsed input, otherwise return
  225. [TypeReaderResult.FromError] and include an error message if
  226. necessary.
  227. [TypeReaderResult]: xref:Discord.Commands.TypeReaderResult
  228. [TypeReaderResult.FromSuccess]: xref:Discord.Commands.TypeReaderResult#Discord_Commands_TypeReaderResult_FromSuccess_Discord_Commands_TypeReaderValue_
  229. [TypeReaderResult.FromError]: xref:Discord.Commands.TypeReaderResult#Discord_Commands_TypeReaderResult_FromError_Discord_Commands_CommandError_System_String_
  230. [Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_ICommandContext_System_String_IServiceProvider_
  231. #### Sample
  232. [!code-csharp[TypeReaders](samples/typereader.cs)]
  233. ### Installing TypeReaders
  234. TypeReaders are not automatically discovered by the Command Service
  235. and must be explicitly added.
  236. To install a TypeReader, invoke [CommandService.AddTypeReader].
  237. [CommandService.AddTypeReader]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_