Add docs for the Command Service
This commit is contained in:
File diff suppressed because one or more lines are too long
62
docs/guides/commands.md
Normal file
62
docs/guides/commands.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# 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)]
|
||||
|
||||
## Modules
|
||||
|
||||
Modules serve as a host for commands you create.
|
||||
|
||||
To create a module, create a class that you will place commands in. Flag this class with the `[Module]` attribute. You may optionally pass in a string to the `Module` attribute to set a prefix for all of the commands inside the module.
|
||||
|
||||
### Example:
|
||||
|
||||
[!code-csharp[Modules](samples/module.cs)]
|
||||
|
||||
### Loading Modules Automatically
|
||||
|
||||
The Command Service can automatically discover all classes in an Assembly that are flagged with the `Module` attribute, and load them.
|
||||
|
||||
To have a module opt-out of auto-loading, pass `autoload: false` in the Module attribute.
|
||||
|
||||
Invoke [CommandService.LoadAssembly](Discord.Commands.CommandService#Discord_Commands_CommandService_LoadAssembly) to discover modules and install them.
|
||||
|
||||
### Loading Modules Manually
|
||||
|
||||
To manually load a module, invoke [CommandService.Load](Discord.Commands.CommandService#Discord_Commands_CommandService_Load), and pass in an instance of your module.
|
||||
|
||||
### Module Constructors
|
||||
|
||||
When automatically loading modules, you are limited in your constructor. Using a constructor that accepts _no arguments_, or a constructor that accepts a @Discord.Commands.CommandService will always work.
|
||||
|
||||
Alternatively, you can use an @Discord.Commands.IDependencyMap, as shown below.
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
The Commands Service includes a very basic implementation of Dependency Injection that allows you to have completely custom constructors, within certain limitations.
|
||||
|
||||
## 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)]
|
||||
52
docs/guides/samples/command_handler.cs
Normal file
52
docs/guides/samples/command_handler.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
|
||||
public class Program
|
||||
{
|
||||
private CommandService commands;
|
||||
private DiscordSocketClient client;
|
||||
|
||||
static void Main(string[] args) => new Program().Start().GetAwaiter().GetResult();
|
||||
|
||||
public async Task Start()
|
||||
{
|
||||
client = new DiscordSocketClient();
|
||||
commands = new CommandService();
|
||||
|
||||
string token = "bot token here";
|
||||
|
||||
await InstallCommands();
|
||||
|
||||
await client.LoginAsync(TokenType.Bot, token);
|
||||
await client.ConnectAsync();
|
||||
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
|
||||
public async Task InstallCommands()
|
||||
{
|
||||
// Hook the MessageReceived Event into our Command Handler
|
||||
client.MessageReceived += HandleCommand;
|
||||
// Discover all of the commands in this assembly and load them.
|
||||
await commands.LoadAssembly(Assembly.GetEntryAssembly());
|
||||
}
|
||||
public async Task HandleCommand(IMessage msg)
|
||||
{
|
||||
// Internal integer, marks where the command begins
|
||||
int argPos = 0;
|
||||
// Get the current user (used for Mention parsing)
|
||||
var currentUser = await client.GetCurrentUserAsync();
|
||||
// Determine if the message is a command, based on if it starts with '!' or a mention prefix
|
||||
if (msg.HasCharPrefix('!', ref argPos) || msg.HasMentionPrefix(currentUser, ref argPos))
|
||||
{
|
||||
// Execute the command. (result does not indicate a return value,
|
||||
// rather an object stating if the command executed succesfully)
|
||||
var result = await _commands.Execute(msg, argPos);
|
||||
if (!result.IsSuccess)
|
||||
await msg.Channel.SendMessageAsync(result.ErrorReason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
16
docs/guides/samples/dependency_map_setup.cs
Normal file
16
docs/guides/samples/dependency_map_setup.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
|
||||
public class Commands
|
||||
{
|
||||
public async Task Install(DiscordSocketClient client)
|
||||
{
|
||||
var commands = new CommandService();
|
||||
var map = new DependencyMap();
|
||||
map.Add<IDiscordClient>(client);
|
||||
var self = await client.GetCurrentUserAsync();
|
||||
map.Add<ISelfUser>(self);
|
||||
await commands.LoadAssembly(Assembly.GetCurrentAssembly(), map);
|
||||
}
|
||||
// ...
|
||||
}
|
||||
28
docs/guides/samples/dependency_module.cs
Normal file
28
docs/guides/samples/dependency_module.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
|
||||
[Module]
|
||||
public class ModuleA
|
||||
{
|
||||
private DiscordSocketClient client;
|
||||
private ISelfUser self;
|
||||
|
||||
public ModuleA(IDiscordClient c, ISelfUser s)
|
||||
{
|
||||
if (!(c is DiscordSocketClient)) throw new InvalidOperationException("This module requires a DiscordSocketClient");
|
||||
client = c as DiscordSocketClient;
|
||||
self = s;
|
||||
}
|
||||
}
|
||||
|
||||
public class ModuleB
|
||||
{
|
||||
private IDiscordClient client;
|
||||
private CommandService commands;
|
||||
|
||||
public ModuleB(CommandService c, IDependencyMap m)
|
||||
{
|
||||
commands = c;
|
||||
client = m.Get<IDiscordClient>();
|
||||
}
|
||||
}
|
||||
40
docs/guides/samples/module.cs
Normal file
40
docs/guides/samples/module.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Discord.Commands;
|
||||
|
||||
// Create a module with no prefix
|
||||
[Module]
|
||||
public class Info
|
||||
{
|
||||
// ~say hello -> hello
|
||||
[Command("say"), Description("Echos a message.")]
|
||||
public async Task Say(IMessage msg,
|
||||
[Unparsed, Description("The text to echo")] string echo)
|
||||
{
|
||||
await msg.Channel.SendMessageAsync(echo);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a module with the 'sample' prefix
|
||||
[Module("sample")]
|
||||
public class Sample
|
||||
{
|
||||
// ~sample square 20 ->
|
||||
[Command("square"), Description("Squares a number.")]
|
||||
public async Task Square(IMessage msg,
|
||||
[Description("The number to square.")] int num)
|
||||
{
|
||||
await msg.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}");
|
||||
}
|
||||
|
||||
// ~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
|
||||
[Command("userinfo"), Description("Returns info about the current user, or the user parameter, if one passed.")]
|
||||
public async Task UserInfo(IMessage msg,
|
||||
[Description("The (optional) user to get info for")] IUser user = null)
|
||||
{
|
||||
var userInfo = user ?? await Program.Client.GetCurrentUserAsync();
|
||||
await msg.Channel.SendMessageAsync($"{userInfo.Username}#{userInfo.Discriminator}");
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,6 @@
|
||||
- name: Terminology
|
||||
href: terminology.md
|
||||
- name: Logging
|
||||
href: logging.md
|
||||
href: logging.md
|
||||
- name: Commands
|
||||
href: commands.md
|
||||
Reference in New Issue
Block a user