[docs] rewrite commands, update samples
This commit is contained in:
@@ -3,82 +3,152 @@
|
||||
[Discord.Commands](xref:Discord.Commands) provides an Attribute-based
|
||||
Command Parser.
|
||||
|
||||
### Setup
|
||||
## Setup
|
||||
|
||||
To use Commands, you must create a
|
||||
[Commands Service](xref:Discord.Commands.CommandService)
|
||||
and a Command Handler.
|
||||
To use Commands, you must create a [Commands Service] 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)]
|
||||
The CommandService optionally will accept a [CommandServiceConfig],
|
||||
which _does_ set a few default values for you. It is recommended to
|
||||
look over the properties in [CommandServiceConfig], and their default
|
||||
values.
|
||||
|
||||
## Commands
|
||||
[!code-csharp[Command Handler](samples/command_handler.cs)]
|
||||
|
||||
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.
|
||||
[Command Service]: xref:Discord.Commands.CommandService
|
||||
[CommandServiceConfig]: xref:Discord.Commands.CommandServiceConfig
|
||||
|
||||
### Basic Structure
|
||||
## With Attributes
|
||||
|
||||
All commands belong to a Module. (See the below section for creating
|
||||
modules).
|
||||
In 1.0, Commands can be defined ahead of time, with attributes, or
|
||||
at runtime, with builders.
|
||||
|
||||
All commands in a module must be defined as a `Task`.
|
||||
For most bots, ahead-of-time commands should be all you need, and this
|
||||
is the recommended method of defining commands.
|
||||
|
||||
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
|
||||
The first step to creating commands is to create a _module_.
|
||||
|
||||
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.
|
||||
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 invoked.
|
||||
|
||||
**Avoid using long-running code** in your modules whereever possible.
|
||||
You should **not** be implementing very much logic into your modules;
|
||||
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.
|
||||
To begin, create a new class somewhere in your project, and
|
||||
inherit the class from [ModuleBase]. This class **must** be `public`.
|
||||
|
||||
>[!NOTE]
|
||||
>[ModuleBase] is an _abstract_ class, meaning that you may extend it
|
||||
>or override it as you see fit. Your module may inherit from any
|
||||
>extension of ModuleBase.
|
||||
|
||||
By now, your module should look like this:
|
||||
[!code-csharp[Empty Module](samples/empty-module.cs)]
|
||||
|
||||
[IoC]: https://msdn.microsoft.com/en-us/library/ff921087.aspx
|
||||
[Dependency Injection]: https://msdn.microsoft.com/en-us/library/ff921152.aspx
|
||||
[ModuleBase]: xref:Discord.Commands.ModuleBase
|
||||
|
||||
### Example Module
|
||||
### Adding Commands
|
||||
|
||||
[!code-csharp[Modules](samples/module.cs)]
|
||||
The next step to creating commands, is actually creating commands.
|
||||
|
||||
To create a command, add a method to your module of type `Task`.
|
||||
Typically, you will want to mark his method as `async`, although it is
|
||||
not required.
|
||||
|
||||
Adding parameters to a command is done by adding parameters to the
|
||||
parent Task.
|
||||
|
||||
For example, to take an integer as an argument, add `int arg`. To take
|
||||
a user as an argument, add `IUser user`. In 1.0, a command can accept
|
||||
nearly any type of argument; a full list of types that are parsed by
|
||||
default can be found in the below section on _Type Readers_.
|
||||
|
||||
Parameters, by default, are always required. To make a parameter
|
||||
optional, give it a default value. To accept a comma-separated list,
|
||||
set the parameter to `params Type[]`.
|
||||
|
||||
Should a parameter include spaces, it **must** be wrapped in quotes.
|
||||
For example, for a command with a parameter `string food`, you would
|
||||
execute it with `!favoritefood "Key Lime Pie"`.
|
||||
|
||||
If you would like a parameter to parse until the end of a command,
|
||||
flag the parameter with the [RemainderAttribute]. This will allow a
|
||||
user to invoke a command without wrapping a parameter in quotes.
|
||||
|
||||
Finally, flag your command with the [CommandAttribute]. (You must
|
||||
specify a name for this command, except for when it is part of a
|
||||
module group - see below).
|
||||
|
||||
[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
|
||||
[CommandAttribute]: xref:Discord.Commands.CommandAttribute
|
||||
|
||||
### Command Overloads
|
||||
|
||||
You may add overloads of your commands, and the command parser will
|
||||
automatically pick up on it.
|
||||
|
||||
If, for whatever reason, you have too commands which are ambiguous to
|
||||
each other, you may use the @Discord.Commands.PriorityAttribute to
|
||||
specify which should be tested before the other.
|
||||
|
||||
Priority's are sorted in ascending order; the higher priority will be
|
||||
called first.
|
||||
|
||||
### CommandContext
|
||||
|
||||
Every command can access the execution context through the [Context]
|
||||
property on [ModuleBase]. CommandContext allows you to access the
|
||||
message, channel, guild, and user that the command was invoked from,
|
||||
as well as the underlying discord client the command was invoked from.
|
||||
|
||||
You may need to cast these objects to their Socket counterparts (see
|
||||
the terminology section).
|
||||
|
||||
To reply to messages, you may also invoke [ReplyAsync], instead of
|
||||
accessing the channel through the [Context] and sending a message.
|
||||
|
||||
### Example Module
|
||||
|
||||
At this point, your module should look comparable to this example:
|
||||
[!code-csharp[Example Module](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.
|
||||
Assembly that inherit [ModuleBase], and load them.
|
||||
|
||||
To have a module opt-out of auto-loading, pass `autoload: false` in
|
||||
the Module attribute.
|
||||
To opt a module out of auto-loading, flag it with
|
||||
[DontAutoLoadAttribute]
|
||||
|
||||
Invoke [CommandService.AddModules] to discover modules and install them.
|
||||
Invoke [CommandService.AddModulesAsync] to discover modules and
|
||||
install them.
|
||||
|
||||
[CommandService.AddModules]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModules
|
||||
[DontAutoLoadAttribute]: Discord.Commands.DontAutoLoadAttribute
|
||||
[CommandService.AddModulesAsync]: xref:Discord_Commands_CommandService#AddModulesAsync_System_Reflection_Assembly_
|
||||
|
||||
#### Loading Modules Manually
|
||||
|
||||
To manually load a module, invoke [CommandService.AddModule],
|
||||
To manually load a module, invoke [CommandService.AddModuleAsync],
|
||||
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_
|
||||
[CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModuleAsync__1
|
||||
|
||||
### Module Constructors
|
||||
|
||||
@@ -87,18 +157,27 @@ 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
|
||||
### Module 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.
|
||||
Module Groups allow you to create a module where commands are prefixed.
|
||||
To create a group, flag a module 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.
|
||||
Module groups also allow you to create **nameless commands**, where the
|
||||
[CommandAttribute] is configured with no name. In this case, the
|
||||
command will inherit the name of the group it belongs to.
|
||||
|
||||
[!code-csharp[Groups Sample](samples/groups.cs)]
|
||||
### Submodules
|
||||
|
||||
Submodules are modules that reside within another module. Typically,
|
||||
submodules are used to create nested groups (although not required to
|
||||
create nested groups).
|
||||
|
||||
[!code-csharp[Groups and Submodules](samples/groups.cs)]
|
||||
|
||||
## With Builders
|
||||
|
||||
**TODO**
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
@@ -143,34 +222,13 @@ can be as complex as you want them to be.
|
||||
|
||||
## Bundled Preconditions
|
||||
|
||||
@Discord.Commands ships with two built-in preconditions,
|
||||
@Discord.Commands.RequireContextAttribute and
|
||||
@Discord.Commands.RequirePermissionAttribute.
|
||||
Commands ships with four bundled preconditions; you may view their
|
||||
usages on their API page.
|
||||
|
||||
### 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)]
|
||||
- @Discord.Commands.RequireContextAttribute
|
||||
- @Discord.Commands.RequireOwnerAttribute
|
||||
- @Discord.Commands.RequireBotPermissionAttribute
|
||||
- @Discord.Commands.RequireUserPermissionAttribute
|
||||
|
||||
## Custom Preconditions
|
||||
|
||||
@@ -178,15 +236,20 @@ 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>`.
|
||||
[CheckPermissions].
|
||||
|
||||
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()`,
|
||||
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)]
|
||||
|
||||
[CheckPermissions]: xref:Discord.Commands.PreconditionAttribute#Discord_Commands_PreconditionAttribute_CheckPermissions_Discord_Commands_CommandContext_Discord_Commands_CommandInfo_Discord_Commands_IDependencyMap_
|
||||
[PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromSuccess
|
||||
[PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromError_System_String_
|
||||
|
||||
# Type Readers
|
||||
|
||||
Type Readers allow you to parse different types of arguments in
|
||||
@@ -194,24 +257,26 @@ your commands.
|
||||
|
||||
By default, the following Types are supported arguments:
|
||||
|
||||
- string
|
||||
- bool
|
||||
- char
|
||||
- sbyte/byte
|
||||
- ushort/short
|
||||
- uint/int
|
||||
- ulong/long
|
||||
- float, double, decimal
|
||||
- DateTime/DateTimeOffset
|
||||
- IUser/IGuildUser
|
||||
- IChannel/IGuildChannel/ITextChannel/IVoiceChannel/IGroupChannel
|
||||
- IRole
|
||||
- string
|
||||
- DateTime/DateTimeOffset/TimeSpan
|
||||
- IMessage/IUserMessage
|
||||
- IChannel/IGuildChannel/ITextChannel/IVoiceChannel/IGroupChannel
|
||||
- IUser/IGuildUser/IGroupUser
|
||||
- IRole
|
||||
|
||||
### 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)`.
|
||||
Next, satisfy the `TypeReader` class by overriding [Read].
|
||||
|
||||
>[!NOTE]
|
||||
>In many cases, Visual Studio can fill this in for you, using the
|
||||
@@ -223,6 +288,8 @@ Finally, return a `TypeReaderResult`. If you were able to successfully
|
||||
parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`.
|
||||
Otherwise, return `TypeReaderResult.FromError`.
|
||||
|
||||
[Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_CommandContext_System_String_
|
||||
|
||||
#### Sample
|
||||
|
||||
[!code-csharp[TypeReaders](samples/typereader.cs)]
|
||||
|
||||
Reference in New Issue
Block a user