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
|
- name: Terminology
|
||||||
href: terminology.md
|
href: terminology.md
|
||||||
- name: Logging
|
- name: Logging
|
||||||
href: logging.md
|
href: logging.md
|
||||||
|
- name: Commands
|
||||||
|
href: commands.md
|
||||||
Reference in New Issue
Block a user