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 11 KiB

8 years ago
8 years ago
8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 [Commands Service] and a
  9. Command Handler.
  10. Included below is a very bare-bones Command Handler. You can extend
  11. your Command Handler as much as you like, however the below is the
  12. bare minimum.
  13. The CommandService optionally will 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
  22. at 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. Modules are an organizational pattern that allow 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 being invoked.
  32. **Avoid using long-running code** in your modules whereever possible.
  33. You should **not** be implementing very much logic into your modules;
  34. 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
  38. inherit the 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 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 is
  52. 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, add `int arg`. To take
  56. a user as an argument, add `IUser user`. In 1.0, a command can accept
  57. nearly any type of argument; a full list of types that are parsed by
  58. default can be found in the below section on _Type Readers_.
  59. Parameters, by default, are always required. To make a parameter
  60. optional, give it a default value. To accept a comma-separated list,
  61. set the parameter to `params Type[]`.
  62. Should a parameter include spaces, it **must** be wrapped in quotes.
  63. For example, for a command with a parameter `string food`, you would
  64. execute it with `!favoritefood "Key Lime Pie"`.
  65. If you would like a parameter to parse until the end of a command,
  66. flag the parameter with the [RemainderAttribute]. This will allow a
  67. user to invoke a command without wrapping a parameter in quotes.
  68. Finally, flag your command with the [CommandAttribute]. (You must
  69. specify a name for this command, except for when it is part of a
  70. module group - see below).
  71. [RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
  72. [CommandAttribute]: xref:Discord.Commands.CommandAttribute
  73. ### Command Overloads
  74. You may add overloads of your commands, and the command parser will
  75. automatically pick up on it.
  76. If, for whatever reason, you have too commands which are ambiguous to
  77. each other, you may use the @Discord.Commands.PriorityAttribute to
  78. specify which should be tested before the other.
  79. Priority's are sorted in ascending order; the higher priority will be
  80. called first.
  81. ### CommandContext
  82. Every command can access the execution context through the [Context]
  83. property on [ModuleBase]. CommandContext allows you to access the
  84. message, channel, guild, and user that the command was invoked from,
  85. as well as the underlying discord client the command was invoked from.
  86. Different types of Contexts may be specified using the generic variant
  87. of [ModuleBase]. When using a [SocketCommandContext], for example,
  88. the properties on this context will already be Socket entities. You
  89. will not need to cast them.
  90. To reply to messages, you may also invoke [ReplyAsync], instead of
  91. accessing the channel through the [Context] and sending a message.
  92. [Context]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_Context
  93. [SocketCommandContext]: xref:Discord.Commands.SocketCommandContext
  94. >![WARNING]
  95. >Contexts should **NOT** be mixed! You cannot have one module that
  96. >uses CommandContext, and another that uses SocketCommandContext.
  97. ### Example Module
  98. At this point, your module should look comparable to this example:
  99. [!code-csharp[Example Module](samples/module.cs)]
  100. #### Loading Modules Automatically
  101. The Command Service can automatically discover all classes in an
  102. Assembly that inherit [ModuleBase], and load them.
  103. To opt a module out of auto-loading, flag it with
  104. [DontAutoLoadAttribute]
  105. Invoke [CommandService.AddModulesAsync] to discover modules and
  106. install them.
  107. [DontAutoLoadAttribute]: xref:Discord.Commands.DontAutoLoadAttribute
  108. [CommandService.AddModulesAsync]: xref:Discord_Commands_CommandService#Discord_Commands_CommandService_AddModulesAsync_Assembly_
  109. #### Loading Modules Manually
  110. To manually load a module, invoke [CommandService.AddModuleAsync],
  111. by passing in the generic type of your module, and optionally
  112. a dependency map.
  113. [CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModuleAsync__1
  114. ### Module Constructors
  115. Modules are constructed using Dependency Injection. Any parameters
  116. that are placed in the constructor must be injected into an
  117. @Discord.Commands.IDependencyMap. Alternatively, you may accept an
  118. IDependencyMap as an argument and extract services yourself.
  119. ### Module Properties
  120. Modules with public settable properties will have them injected after module
  121. construction.
  122. ### Module Groups
  123. Module Groups allow you to create a module where commands are prefixed.
  124. To create a group, flag a module with the
  125. @Discord.Commands.GroupAttribute
  126. Module groups also allow you to create **nameless commands**, where the
  127. [CommandAttribute] is configured with no name. In this case, the
  128. command will inherit the name of the group it belongs to.
  129. ### Submodules
  130. Submodules are modules that reside within another module. Typically,
  131. submodules are used to create nested groups (although not required to
  132. create nested groups).
  133. [!code-csharp[Groups and Submodules](samples/groups.cs)]
  134. ## With Builders
  135. **TODO**
  136. ## Dependency Injection
  137. The commands service is bundled with a very barebones Dependency
  138. Injection service for your convienence. It is recommended that
  139. you use DI when writing your modules.
  140. ### Setup
  141. First, you need to create an @Discord.Commands.IDependencyMap.
  142. The library includes @Discord.Commands.DependencyMap to help with
  143. this, however you may create your own IDependencyMap if you wish.
  144. Next, add the dependencies your modules will use to the map.
  145. Finally, pass the map into the `LoadAssembly` method.
  146. Your modules will automatically be loaded with this dependency map.
  147. [!code-csharp[DependencyMap Setup](samples/dependency_map_setup.cs)]
  148. ### Usage in Modules
  149. In the constructor of your module, any parameters will be filled in by
  150. the @Discord.Commands.IDependencyMap you pass into `LoadAssembly`.
  151. Any publicly settable properties will also be filled in the same manner.
  152. >[!NOTE]
  153. > Annotating a property with the [DontInject] attribute will prevent it from
  154. being injected.
  155. >[!NOTE]
  156. >If you accept `CommandService` or `IDependencyMap` as a parameter in
  157. your constructor or as an injectable property, these entries will be filled
  158. by the CommandService the module was loaded from, and the DependencyMap passed
  159. into it, respectively.
  160. [!code-csharp[DependencyMap in Modules](samples/dependency_module.cs)]
  161. # Preconditions
  162. Preconditions serve as a permissions system for your commands. Keep in
  163. mind, however, that they are not limited to _just_ permissions, and
  164. can be as complex as you want them to be.
  165. >[!NOTE]
  166. >Preconditions can be applied to Modules, Groups, or Commands.
  167. ## Bundled Preconditions
  168. Commands ships with four bundled preconditions; you may view their
  169. usages on their API page.
  170. - @Discord.Commands.RequireContextAttribute
  171. - @Discord.Commands.RequireOwnerAttribute
  172. - @Discord.Commands.RequireBotPermissionAttribute
  173. - @Discord.Commands.RequireUserPermissionAttribute
  174. ## Custom Preconditions
  175. To write your own preconditions, create a new class that inherits from
  176. @Discord.Commands.PreconditionAttribute
  177. In order for your precondition to function, you will need to override
  178. [CheckPermissions].
  179. Your IDE should provide an option to fill this in for you.
  180. Return [PreconditionResult.FromSuccess] if the context met the
  181. required parameters, otherwise return [PreconditionResult.FromError],
  182. optionally including an error message.
  183. [!code-csharp[Custom Precondition](samples/require_owner.cs)]
  184. [CheckPermissions]: xref:Discord.Commands.PreconditionAttribute#Discord_Commands_PreconditionAttribute_CheckPermissions_Discord_Commands_CommandContext_Discord_Commands_CommandInfo_Discord_Commands_IDependencyMap_
  185. [PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromSuccess
  186. [PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromError_System_String_
  187. # Type Readers
  188. Type Readers allow you to parse different types of arguments in
  189. your commands.
  190. By default, the following Types are supported arguments:
  191. - bool
  192. - char
  193. - sbyte/byte
  194. - ushort/short
  195. - uint/int
  196. - ulong/long
  197. - float, double, decimal
  198. - string
  199. - DateTime/DateTimeOffset/TimeSpan
  200. - IMessage/IUserMessage
  201. - IChannel/IGuildChannel/ITextChannel/IVoiceChannel/IGroupChannel
  202. - IUser/IGuildUser/IGroupUser
  203. - IRole
  204. ### Creating a Type Readers
  205. To create a TypeReader, create a new class that imports @Discord and
  206. @Discord.Commands. Ensure your class inherits from @Discord.Commands.TypeReader
  207. Next, satisfy the `TypeReader` class by overriding [Read].
  208. >[!NOTE]
  209. >In many cases, Visual Studio can fill this in for you, using the
  210. >"Implement Abstract Class" IntelliSense hint.
  211. Inside this task, add whatever logic you need to parse the input string.
  212. Finally, return a `TypeReaderResult`. If you were able to successfully
  213. parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`.
  214. Otherwise, return `TypeReaderResult.FromError`.
  215. [Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_CommandContext_System_String_
  216. #### Sample
  217. [!code-csharp[TypeReaders](samples/typereader.cs)]
  218. ### Installing TypeReaders
  219. TypeReaders are not automatically discovered by the Command Service,
  220. and must be explicitly added. To install a TypeReader, invoke [CommandService.AddTypeReader](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_).