Improve library documentation (#826)

* 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.

* Update line breaks to comply with docs standard

* Change "you should..." to "instead, ..."

* Trim trailing spaces

* Change "inherits" to "inherit"

* Fix Context warning note and add ReplyAsync xref

* Fix broken xrefs

* Fix [Command Service] xref

* Fix consistency between TypeReaders and Preconditions returns

* Add missing semi-colons in ServiceProvider sample

* Change CommandContext to SocketCommandContext & change variable naming

* Cleanup TypeReader section

* Wrap [DontInject] in code block

* Fix commands docs linking in intro

* Improve Getting Started - Installation

- Fix character misalignment to comply with docs standard.
- Fix image numbering issues by moving the tooltips above some of the steps.
- Add codeblocks to search terms like `Discord.Net`.
- Remove broken `addons` reference.
- Specify `.NET 4.6.1` as `.NET Framework 4.6.1`.
- Minor cross-reference cleanup.

* Fix Getting Started - Intro

- Minor grammartical fixes.
- Wrap mentions of the methods, properties, and events in code block.
- Replace `Discord.Net` to `Discord.NET`.
- Fix steps numbering under `Creating a Discord Bot` and `Adding your bot to a server`.
- Change `Task-based Asynchronous Pattern ([TAP])` linking to mark the entire term instead.
- Change code block of `Pong!` to quotation mark instead.

* Fix cross references in Sending Voice

* Mention parameter precondition attribute

* Change `Discord.NET` to `Discord.Net` for consistency

* Wrap project names in code blocks & minor fixes in Terminology

* Change `add-ons` to `addons` for consistency

* Fix cross references in Logging

* Fix minor grammatical issues in "Working with Events"

* Missed a tilda

* Remove out-of-date warning in Commands

* Minor grammatical fixes for Entities

* Fix broken xref in Logging

* Adjust service collection sample

...according to f89aecb7bf (r141530227)

* Update Command Handler sample

- Update Main for C# 7.1.
- Inject CommandService and DiscordSocketClient into the service collection.
- Add Async suffix to asynchronous methods.

* Minor grammatical fixes in Events

* Revert 2 incorrect grammar corrections

* Revert async Main sample

* Add hardcode token notice in sample

* Fix missing method for Command Handler

* Modify module samples to use SocketCommandContext instead

* Emphasize CommandContext and SocketCommandContext

* Fix formatting for module sample

* Add SocketCommandContext for Groups sample

* Remove comma

* Fix DepMap sample formatting

* Replace [DontInject] with DontInjectAttribute with cross reference

* Remove connection logic note

There is no reason that this note should still be here since Ready event exists.

* Add a new warning message informing the users the existence of CommandService

* Make command handler private

excellent change
This commit is contained in:
Hsu Still
2017-10-04 04:48:05 +08:00
committed by Christopher F
parent e00f17fe55
commit 22d79c1004
14 changed files with 393 additions and 340 deletions

View File

@@ -1,24 +1,20 @@
# The Command Service
>[!WARNING]
>This article is out of date, and has not been rewritten yet.
Information is not guaranteed to be accurate.
[Discord.Commands](xref:Discord.Commands) provides an Attribute-based
Command Parser.
command parser.
## Setup
To use Commands, you must create a [Commands Service] and a
Command Handler.
To use Commands, you must create a [Command 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.
Included below is a very barebone Command Handler. You can extend your
Command Handler as much as you like; however, the below is the bare
minimum.
The CommandService optionally will accept a [CommandServiceConfig],
The `CommandService` will optionally 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
look over the properties in [CommandServiceConfig] and their default
values.
[!code-csharp[Command Handler](samples/command_handler.cs)]
@@ -28,32 +24,32 @@ values.
## With Attributes
In 1.0, Commands can be defined ahead of time, with attributes, or
at runtime, with builders.
In 1.0, Commands can be defined ahead of time with attributes, or at
runtime with builders.
For most bots, ahead-of-time commands should be all you need, and this
is the recommended method of defining commands.
For most bots, ahead-of-time Commands should be all you need, and this
is the recommended method of defining Commands.
### Modules
The first step to creating commands is to create a _module_.
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.
A Module is an organizational pattern that allows 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 invoked.
ASP.NET Core's Controller pattern. This means that the lifetime of a
module instance is only as long as the Command is being invoked.
**Avoid using long-running code** in your modules wherever possible.
You should **not** be implementing very much logic into your modules;
outsource to a service for that.
You should **not** be implementing very much logic into your modules,
instead, 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 begin, create a new class somewhere in your project, and
inherit the class from [ModuleBase]. This class **must** be `public`.
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
@@ -61,6 +57,7 @@ inherit the class from [ModuleBase]. This class **must** be `public`.
>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
@@ -69,72 +66,75 @@ By now, your module should look like this:
### Adding Commands
The next step to creating commands, is actually creating commands.
The next step to creating Commands is actually creating the Commands.
To create a command, add a method to your module of type `Task`.
Typically, you will want to mark this method as `async`, although it is
not required.
To create a Command, add a method to your module of type `Task`.
Typically, you will want to mark this method as `async`, although it
is not required.
Adding parameters to a command is done by adding parameters to the
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_.
For example, to take an integer as an argument from the user, add `int
arg`; to take a user as an argument from the user, 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
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,
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.
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).
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
You may add overloads to your Commands, and the Command parser will
automatically pick up on it.
If, for whatever reason, you have too commands which are ambiguous to
If for whatever reason, you have two 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.
The `Priority` attributes are sorted in ascending order; the higher
priority will be called first.
### CommandContext
### Command Context
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.
Every Command can access the execution context through the [Context]
property on [ModuleBase]. `ICommandContext` allows you to access the
message, channel, guild, and user that the Command was invoked from,
as well as the underlying Discord client that the Command was invoked
from.
Different types of Contexts may be specified using the generic variant
of [ModuleBase]. When using a [SocketCommandContext], for example,
the properties on this context will already be Socket entities. You
of [ModuleBase]. When using a [SocketCommandContext], for example, the
properties on this context will already be Socket entities, so you
will not need to cast them.
To reply to messages, you may also invoke [ReplyAsync], instead of
accessing the channel through the [Context] and sending a message.
> [!WARNING]
>Contexts should **NOT** be mixed! You cannot have one module that
>uses `CommandContext` and another that uses `SocketCommandContext`.
[Context]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_Context
[SocketCommandContext]: xref:Discord.Commands.SocketCommandContext
>![WARNING]
>Contexts should **NOT** be mixed! You cannot have one module that
>uses CommandContext, and another that uses SocketCommandContext.
[ReplyAsync]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_ReplyAsync_System_String_System_Boolean_Discord_Embed_Discord_RequestOptions_
### Example Module
@@ -144,50 +144,50 @@ At this point, your module should look comparable to this example:
#### Loading Modules Automatically
The Command Service can automatically discover all classes in an
Assembly that inherit [ModuleBase], and load them.
Assembly that inherit [ModuleBase] and load them.
To opt a module out of auto-loading, flag it with
[DontAutoLoadAttribute]
[DontAutoLoadAttribute].
Invoke [CommandService.AddModulesAsync] to discover modules and
install them.
[DontAutoLoadAttribute]: xref:Discord.Commands.DontAutoLoadAttribute
[CommandService.AddModulesAsync]: xref:Discord_Commands_CommandService#Discord_Commands_CommandService_AddModulesAsync_Assembly_
[CommandService.AddModulesAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModulesAsync_Assembly_
#### Loading Modules Manually
To manually load a module, invoke [CommandService.AddModuleAsync],
by passing in the generic type of your module, and optionally
a dependency map.
To manually load a module, invoke [CommandService.AddModuleAsync] by
passing in the generic type of your module and optionally, a
dependency map.
[CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModuleAsync__1
### Module Constructors
Modules are constructed using Dependency Injection. Any parameters
that are placed in the constructor must be injected into an
@System.IServiceProvider. Alternatively, you may accept an
IServiceProvider as an argument and extract services yourself.
that are placed in the Module's constructor must be injected into an
@System.IServiceProvider first. Alternatively, you may accept an
`IServiceProvider` as an argument and extract services yourself.
### Module Properties
Modules with public settable properties will have them injected after module
construction.
Modules with `public` settable properties will have the dependencies
injected after the construction of the Module.
### Module Groups
Module Groups allow you to create a module where commands are prefixed.
To create a group, flag a module 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.
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.
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.
### Submodules
Submodules are modules that reside within another module. Typically,
Submodules are Modules that reside within another one. Typically,
submodules are used to create nested groups (although not required to
create nested groups).
@@ -199,54 +199,62 @@ create nested groups).
## 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.
The Command Service is bundled with a very barebone Dependency
Injection service for your convenience. It is recommended that you use
DI when writing your modules.
### Setup
First, you need to create an @System.IServiceProvider
You may create your own IServiceProvider if you wish.
First, you need to create an @System.IServiceProvider; you may create
your own one if you wish.
Next, add the dependencies your modules will use to the map.
Next, add the dependencies that 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.
Finally, pass the map into the `LoadAssembly` method. Your modules
will be automatically loaded with this dependency map.
[!code-csharp[IServiceProvider Setup](samples/dependency_map_setup.cs)]
### Usage in Modules
In the constructor of your module, any parameters will be filled in by
the @System.IServiceProvider you pass into `LoadAssembly`.
In the constructor of your Module, any parameters will be filled in by
the @System.IServiceProvider that you've passed into `LoadAssembly`.
Any publicly settable properties will also be filled in the same manner.
Any publicly settable properties will also be filled in the same
manner.
>[!NOTE]
> Annotating a property with the [DontInject] attribute will prevent it from
being injected.
> Annotating a property with a [DontInjectAttribute] attribute will prevent the
property from being injected.
>[!NOTE]
>If you accept `CommandService` or `IServiceProvider` as a parameter in
your constructor or as an injectable property, these entries will be filled
by the CommandService the module was loaded from, and the ServiceProvider passed
into it, respectively.
>If you accept `CommandService` or `IServiceProvider` as a parameter
in your constructor or as an injectable property, these entries will
be filled by the `CommandService` that the Module is loaded from and
the `ServiceProvider` that is passed into it respectively.
[!code-csharp[ServiceProvider in Modules](samples/dependency_module.cs)]
[DontInjectAttribute]: xref:Discord.Commands.DontInjectAttribute
# 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.
Precondition 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.
>There are two types of Preconditions.
[PreconditionAttribute] can be applied to Modules, Groups, or Commands;
[ParameterPreconditionAttribute] can be applied to Parameters.
[PreconditionAttribute]: xref:Discord.Commands.PreconditionAttribute
[ParameterPreconditionAttribute]: xref:Discord.Commands.ParameterPreconditionAttribute
## Bundled Preconditions
Commands ships with four bundled preconditions; you may view their
usages on their API page.
Commands ship with four bundled Preconditions; you may view their
usages on their respective API pages.
- @Discord.Commands.RequireContextAttribute
- @Discord.Commands.RequireOwnerAttribute
@@ -255,21 +263,23 @@ usages on their API page.
## Custom Preconditions
To write your own preconditions, create a new class that inherits from
@Discord.Commands.PreconditionAttribute
To write your own Precondition, create a new class that inherits from
either [PreconditionAttribute] or [ParameterPreconditionAttribute]
depending on your use.
In order for your precondition to function, you will need to override
[CheckPermissions].
In order for your Precondition to function, you will need to override
the [CheckPermissions] method.
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.
If the context meets the required parameters, return
[PreconditionResult.FromSuccess], otherwise return
[PreconditionResult.FromError] and include an error message if
necessary.
[!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_
[CheckPermissions]: xref:Discord.Commands.PreconditionAttribute#Discord_Commands_PreconditionAttribute_CheckPermissions_Discord_Commands_ICommandContext_Discord_Commands_CommandInfo_IServiceProvider_
[PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromSuccess
[PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromError_System_String_
@@ -296,22 +306,28 @@ By default, the following Types are supported arguments:
### 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
To create a `TypeReader`, create a new class that imports @Discord and
@Discord.Commands and ensure the class inherits from
@Discord.Commands.TypeReader.
Next, satisfy the `TypeReader` class by overriding [Read].
Next, satisfy the `TypeReader` class by overriding the [Read] method.
>[!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.
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`.
If you are able to successfully parse the input, return
[TypeReaderResult.FromSuccess] with the parsed input, otherwise return
[TypeReaderResult.FromError] and include an error message if
necessary.
[Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_CommandContext_System_String_
[TypeReaderResult]: xref:Discord.Commands.TypeReaderResult
[TypeReaderResult.FromSuccess]: xref:Discord.Commands.TypeReaderResult#Discord_Commands_TypeReaderResult_FromSuccess_Discord_Commands_TypeReaderValue_
[TypeReaderResult.FromError]: xref:Discord.Commands.TypeReaderResult#Discord_Commands_TypeReaderResult_FromError_Discord_Commands_CommandError_System_String_
[Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_ICommandContext_System_String_IServiceProvider_
#### Sample
@@ -319,5 +335,9 @@ Otherwise, return `TypeReaderResult.FromError`.
### 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_).
TypeReaders are not automatically discovered by the Command Service
and must be explicitly added.
To install a TypeReader, invoke [CommandService.AddTypeReader].
[CommandService.AddTypeReader]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_

View File

@@ -8,39 +8,42 @@ using Microsoft.Extensions.DependencyInjection;
public class Program
{
private CommandService commands;
private DiscordSocketClient client;
private IServiceProvider services;
private CommandService _commands;
private DiscordSocketClient _client;
private IServiceProvider _services;
static void Main(string[] args) => new Program().Start().GetAwaiter().GetResult();
private static void Main(string[] args) => new Program().StartAsync().GetAwaiter().GetResult();
public async Task Start()
public async Task StartAsync()
{
client = new DiscordSocketClient();
commands = new CommandService();
_client = new DiscordSocketClient();
_commands = new CommandService();
// Avoid hard coding your token. Use an external source instead in your code.
string token = "bot token here";
services = new ServiceCollection()
.BuildServiceProvider();
_services = new ServiceCollection()
.AddSingleton(_client)
.AddSingleton(_commands)
.BuildServiceProvider();
await InstallCommands();
await InstallCommandsAsync();
await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync();
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
await Task.Delay(-1);
}
public async Task InstallCommands()
public async Task InstallCommandsAsync()
{
// Hook the MessageReceived Event into our Command Handler
client.MessageReceived += HandleCommand;
_client.MessageReceived += HandleCommandAsync;
// Discover all of the commands in this assembly and load them.
await commands.AddModulesAsync(Assembly.GetEntryAssembly());
await _commands.AddModulesAsync(Assembly.GetEntryAssembly());
}
public async Task HandleCommand(SocketMessage messageParam)
private async Task HandleCommandAsync(SocketMessage messageParam)
{
// Don't process the command if it was a System Message
var message = messageParam as SocketUserMessage;
@@ -48,13 +51,13 @@ public class Program
// Create a number to track where the prefix ends and the command begins
int argPos = 0;
// Determine if the message is a command, based on if it starts with '!' or a mention prefix
if (!(message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(client.CurrentUser, ref argPos))) return;
if (!(message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return;
// Create a Command Context
var context = new CommandContext(client, message);
var context = new SocketCommandContext(_client, message);
// Execute the command. (result does not indicate a return value,
// rather an object stating if the command executed successfully)
var result = await commands.ExecuteAsync(context, argPos, service);
var result = await _commands.ExecuteAsync(context, argPos, _services);
if (!result.IsSuccess)
await context.Channel.SendMessageAsync(result.ErrorReason);
}
}
}

View File

@@ -1,18 +1,18 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using foxboat.Services;
private IServiceProvider _services;
private CommandService _commands;
public class Commands
public async Task InstallAsync(DiscordSocketClient client)
{
public async Task Install(DiscordSocketClient client)
{
// Here, we will inject the ServiceProvider with
// all of the services our client will use.
_serviceCollection.AddSingleton(client)
_serviceCollection.AddSingleton(new NotificationService())
_serviceCollection.AddSingleton(new DatabaseService())
// ...
await _commands.AddModulesAsync(Assembly.GetEntryAssembly());
}
}
// Here, we will inject the ServiceProvider with
// all of the services our client will use.
_services = new ServiceCollection()
.AddSingleton(client)
.AddSingleton(_commands)
// You can pass in an instance of the desired type
.AddSingleton(new NotificationService())
// ...or by using the generic method.
.AddSingleton<DatabaseService>()
.BuildServiceProvider();
// ...
await _commands.AddModulesAsync(Assembly.GetEntryAssembly());
}

View File

@@ -1,6 +1,6 @@
using Discord.Commands;
public class InfoModule : ModuleBase
public class InfoModule : ModuleBase<SocketCommandContext>
{
}

View File

@@ -1,8 +1,8 @@
[Group("admin")]
public class AdminModule : ModuleBase
public class AdminModule : ModuleBase<SocketCommandContext>
{
[Group("clean")]
public class CleanModule : ModuleBase
public class CleanModule : ModuleBase<SocketCommandContext>
{
// ~admin clean 15
[Command]

View File

@@ -1,42 +1,41 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
// Create a module with no prefix
public class Info : ModuleBase
public class Info : ModuleBase<SocketCommandContext>
{
// ~say hello -> hello
[Command("say"), Summary("Echos a message.")]
public async Task Say([Remainder, Summary("The text to echo")] string echo)
{
// ReplyAsync is a method on ModuleBase
await ReplyAsync(echo);
}
// ~say hello -> hello
[Command("say")]
[Summary("Echos a message.")]
public async Task SayAsync([Remainder] [Summary("The text to echo")] string echo)
{
// ReplyAsync is a method on ModuleBase
await ReplyAsync(echo);
}
}
// Create a module with the 'sample' prefix
[Group("sample")]
public class Sample : ModuleBase
public class Sample : ModuleBase<SocketCommandContext>
{
// ~sample square 20 -> 400
[Command("square"), Summary("Squares a number.")]
public async Task Square([Summary("The number to square.")] int num)
{
// We can also access the channel from the Command Context.
await Context.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}");
}
// ~sample square 20 -> 400
[Command("square")]
[Summary("Squares a number.")]
public async Task SquareAsync([Summary("The number to square.")] int num)
{
// We can also access the channel from the Command Context.
await Context.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}");
}
// ~sample userinfo --> foxbot#0282
// ~sample userinfo --> foxbot#0282
// ~sample userinfo @Khionu --> Khionu#8708
// ~sample userinfo Khionu#8708 --> Khionu#8708
// ~sample userinfo Khionu --> Khionu#8708
// ~sample userinfo 96642168176807936 --> Khionu#8708
// ~sample whois 96642168176807936 --> Khionu#8708
[Command("userinfo"), Summary("Returns info about the current user, or the user parameter, if one passed.")]
[Alias("user", "whois")]
public async Task UserInfo([Summary("The (optional) user to get info for")] IUser user = null)
{
var userInfo = user ?? Context.Client.CurrentUser;
await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator}");
}
}
// ~sample whois 96642168176807936 --> Khionu#8708
[Command("userinfo")]
[Summary("Returns info about the current user, or the user parameter, if one passed.")]
[Alias("user", "whois")]
public async Task UserInfoAsync([Summary("The (optional) user to get info for")] SocketUser user = null)
{
var userInfo = user ?? Context.Client.CurrentUser;
await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator}");
}
}