|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- # The Command Service
-
- [Discord.Commands](xref:Discord.Commands) provides an Attribute-based
- Command Parser.
-
- ### Setup
-
- To use Commands, you must create a
- [Commands Service](xref:Discord.Commands.CommandService)
- and a Command Handler.
-
- Included below is a very bare-bones Command Handler. You can extend
- your Command Handler as much as you like, however the below is the
- bare minimum.
-
- [!code-csharp[Barebones Command Handler](samples/command_handler.cs)]
-
- ## Commands
-
- In 1.0, Commands are no longer implemented at runtime with a builder
- pattern. While a builder pattern may be provided later, commands are
- created primarily with attributes.
-
- ### Basic Structure
-
- All commands belong to a Module. (See the below section for creating
- modules).
-
- All commands in a module must be defined as a `Task`.
-
- To add parameters to your command, you simply need to add parameters
- to the Task that represents the command. You are _not_ required to
- accept all arguments as `String`, they will be automatically parsed
- into the type you specify for the arument. See the Example Module
- for an example of command parameters.
-
- ## Modules
-
- Modules are an organizational pattern that allow you to write your
- commands in different classes, and have them automatically loaded.
-
- Discord.Net's implementation of Modules is influenced heavily from
- ASP.Net Core's Controller pattern. This means that the lifetime of a
- module instance is only as long as the command being ran in it.
-
- **Avoid using long-running code** in your modules whereever possible.
- You should **not** be implementing very much logic into your modules;
- outsource to a service for that.
-
- If you are unfamiliar with Inversion of Control, it is recommended to
- read the MSDN article on [IoC] and [Dependency Injection].
-
- To create a module, create a class that inherits from
- @Discord.Commands.ModuleBase.
-
- [IoC]: https://msdn.microsoft.com/en-us/library/ff921087.aspx
- [Dependency Injection]: https://msdn.microsoft.com/en-us/library/ff921152.aspx
-
- ### Example Module
-
- [!code-csharp[Modules](samples/module.cs)]
-
- #### Loading Modules Automatically
-
- The Command Service can automatically discover all classes in an
- Assembly that inherit @Discord.Commands.ModuleBase, and load them.
-
- To have a module opt-out of auto-loading, pass `autoload: false` in
- the Module attribute.
-
- Invoke [CommandService.AddModules] to discover modules and install them.
-
- [CommandService.AddModules]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModules
-
- #### Loading Modules Manually
-
- To manually load a module, invoke [CommandService.AddModule],
- by passing in the generic type of your module, and optionally
- a dependency map.
-
- [CommandService.AddModule]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModule__1_Discord_Commands_IDependencyMap_
-
- ### Module Constructors
-
- Modules are constructed using Dependency Injection. Any parameters
- that are placed in the constructor must be injected into an
- @Discord.Commands.IDependencyMap. Alternatively, you may accept an
- IDependencyMap as an argument and extract services yourself.
-
- ### Command Groups
-
- Command Groups allow you to create a module where commands are prefixed.
- To create a group, create a new module and flag it with the
- @Discord.Commands.GroupAttribute.
-
- >[!NOTE]
- >Groups do not _need_ to be modules. Only classes with commands should
- >inherit from ModuleBase. If you plan on using a group for strictly
- >organizational purposes, there is no reason to make it a module.
-
- [!code-csharp[Groups Sample](samples/groups.cs)]
-
- ## Dependency Injection
-
- The commands service is bundled with a very barebones Dependency
- Injection service for your convienence. It is recommended that
- you use DI when writing your modules.
-
- ### Setup
-
- First, you need to create an @Discord.Commands.IDependencyMap.
- The library includes @Discord.Commands.DependencyMap to help with
- this, however you may create your own IDependencyMap if you wish.
-
- Next, add the dependencies your modules will use to the map.
-
- Finally, pass the map into the `LoadAssembly` method.
- Your modules will automatically be loaded with this dependency map.
-
- [!code-csharp[DependencyMap Setup](samples/dependency_map_setup.cs)]
-
- ### Usage in Modules
-
- In the constructor of your module, any parameters will be filled in by
- the @Discord.Commands.IDependencyMap you pass into `LoadAssembly`.
-
- >[!NOTE]
- >If you accept `CommandService` or `IDependencyMap` as a parameter in
- your constructor, these parameters will be filled by the
- CommandService the module was loaded from, and the DependencyMap passed
- into it, respectively.
-
- [!code-csharp[DependencyMap in Modules](samples/dependency_module.cs)]
-
- # Preconditions
-
- Preconditions serve as a permissions system for your commands. Keep in
- mind, however, that they are not limited to _just_ permissions, and
- can be as complex as you want them to be.
-
- >[!NOTE]
- >Preconditions can be applied to Modules, Groups, or Commands.
-
- ## Bundled Preconditions
-
- @Discord.Commands ships with two built-in preconditions,
- @Discord.Commands.RequireContextAttribute and
- @Discord.Commands.RequirePermissionAttribute.
-
- ### RequireContext
-
- @Discord.Commands.RequireContextAttribute is a precondition that
- requires your command to be executed in the specified context.
-
- You may require three different types of context:
- * Guild
- * DM
- * Group
-
- Since these are `Flags`, you may OR them together.
-
- [!code-csharp[RequireContext](samples/require_context.cs)]
-
- ### RequirePermission
-
- @Discord.Commands.RequirePermissionAttribute is a precondition that
- allows you to quickly specfiy that a user must poesess a permission
- to execute a command.
-
- You may require either a @Discord.GuildPermission or
- @Discord.ChannelPermission
-
- [!code-csharp[RequireContext](samples/require_permission.cs)]
-
- ## Custom Preconditions
-
- To write your own preconditions, create a new class that inherits from
- @Discord.Commands.PreconditionAttribute
-
- In order for your precondition to function, you will need to override
- `CheckPermissions`, which is a `Task<PreconditionResult>`.
- Your IDE should provide an option to fill this in for you.
-
- Return `PreconditionResult.FromSuccess()` if the context met the
- required parameters, otherwise return `PreconditionResult.FromError()`,
- optionally including an error message.
-
- [!code-csharp[Custom Precondition](samples/require_owner.cs)]
-
- # Type Readers
-
- Type Readers allow you to parse different types of arguments in
- your commands.
-
- By default, the following Types are supported arguments:
-
- - string
- - sbyte/byte
- - ushort/short
- - uint/int
- - ulong/long
- - float, double, decimal
- - DateTime/DateTimeOffset
- - IUser/IGuildUser
- - IChannel/IGuildChannel/ITextChannel/IVoiceChannel/IGroupChannel
- - IRole
- - IMessage/IUserMessage
-
- ### Creating a Type Readers
-
- To create a TypeReader, create a new class that imports @Discord and
- @Discord.Commands. Ensure your class inherits from @Discord.Commands.TypeReader
-
- Next, satisfy the `TypeReader` class by overriding `Task<TypeReaderResult> Read(CommandContext context, string input)`.
-
- >[!NOTE]
- >In many cases, Visual Studio can fill this in for you, using the
- >"Implement Abstract Class" IntelliSense hint.
-
- Inside this task, add whatever logic you need to parse the input string.
-
- Finally, return a `TypeReaderResult`. If you were able to successfully
- parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`.
- Otherwise, return `TypeReaderResult.FromError`.
-
- #### Sample
-
- [!code-csharp[TypeReaders](samples/typereader.cs)]
-
- ### Installing TypeReaders
-
- TypeReaders are not automatically discovered by the Command Service,
- and must be explicitly added. To install a TypeReader, invoke [CommandService.AddTypeReader](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_).
|