|
|
@@ -0,0 +1,216 @@ |
|
|
|
# Application commands |
|
|
|
|
|
|
|
Application commands are a new feature thats still a work in progress, this guide will show you how to make the best of em. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Getting started |
|
|
|
|
|
|
|
### Configuring |
|
|
|
|
|
|
|
There is a new configuration setting for your DiscordSocketClient called `AlwaysAcknowledgeInteractions`, It's default value is true. |
|
|
|
Interactions work off of the Recieve -> Respond pipeline, meaning if you dont acknowledge the interaction within 3 seconds its gone forever. |
|
|
|
With `AlwaysAcknowledgeInteractions` set to true, the client will automatically acknowledge the interaction as its recieved, |
|
|
|
letting you wait up to 15 minutes before responding with a message. |
|
|
|
|
|
|
|
With `AlwaysAcknowledgeInteractions` set to false you will have to acknowledge the interaction yourself via the `InteractionCreated` event |
|
|
|
|
|
|
|
### Registering commands |
|
|
|
|
|
|
|
While there is no "easy" way to register command right now, in the future I plan to write a command service to help with that, but right now you have to use the rest |
|
|
|
client to create your command: |
|
|
|
|
|
|
|
```cs |
|
|
|
_client.Ready += RegisterCommands |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
private async Task RegisterCommands() |
|
|
|
{ |
|
|
|
// Creating a global command |
|
|
|
var myGlobalCommand = await _client.Rest.CreateGlobalCommand(new Discord.SlashCommandCreationProperties() |
|
|
|
{ |
|
|
|
Name = "example", |
|
|
|
Description = "Runs the example command", |
|
|
|
Options = new List<Discord.ApplicationCommandOptionProperties>() |
|
|
|
{ |
|
|
|
new ApplicationCommandOptionProperties() |
|
|
|
{ |
|
|
|
Name = "Example option", |
|
|
|
Required = false, |
|
|
|
Description = "Option Description", |
|
|
|
Type = Discord.ApplicationCommandOptionType.String, |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// Creating a guild command |
|
|
|
var myGuildCommand = await _client.Rest.CreateGuildCommand(new Discord.SlashCommandCreationProperties() |
|
|
|
{ |
|
|
|
Name = "guildExample", |
|
|
|
Description = "Runs the guild example command", |
|
|
|
Options = new List<Discord.ApplicationCommandOptionProperties>() |
|
|
|
{ |
|
|
|
new ApplicationCommandOptionProperties() |
|
|
|
{ |
|
|
|
Name = "Guild example option", |
|
|
|
Required = false, |
|
|
|
Description = "Guild option description", |
|
|
|
Type = Discord.ApplicationCommandOptionType.String, |
|
|
|
} |
|
|
|
} |
|
|
|
}, 1234567890); // <- the guild id |
|
|
|
} |
|
|
|
``` |
|
|
|
CreateGuildCommand returns a `RestGuildCommand` class which can be used to modify/delete your command on the fly, it also contains details about your command. |
|
|
|
CreateGlobalCOmmand returns a `RestGlobalCommand` class which can be used to modify/delete your command on the fly, it also contains details about your command. |
|
|
|
|
|
|
|
### Getting a list of all your commands |
|
|
|
You can fetch a list of all your global commands via rest: |
|
|
|
```cs |
|
|
|
var commands = _client.Rest.GetGlobalApplicationCommands(); |
|
|
|
``` |
|
|
|
This returns a `IReadOnlyCollection<RestGlobalCommand>`. |
|
|
|
|
|
|
|
You can also fetch guild specific commands: |
|
|
|
```cs |
|
|
|
var commands = _client.Rest.GetGuildApplicationCommands(1234567890) |
|
|
|
``` |
|
|
|
This returns all the application commands in that guild. |
|
|
|
|
|
|
|
### Responding |
|
|
|
|
|
|
|
First thing we want to do is listen to the `InteractionCreated` event. This event is fired when a socket interaction is recieved via the gateway, It looks somthing like this |
|
|
|
```cs |
|
|
|
_client.InteractionCreated += MyEventHandler; |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
private async Task MyEventHandler(SocketInteraction arg) |
|
|
|
{ |
|
|
|
// handle the interaction here |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
A socket interaction is made up of these properties and methods: |
|
|
|
|
|
|
|
| Name | Description | |
|
|
|
|--------|--------------| |
|
|
|
| Guild | The `SocketGuild` this interaction was used in | |
|
|
|
| Channel | The `SocketTextChannel` this interaction was used in | |
|
|
|
| Member | The `SocketGuildUser` that executed the interaction | |
|
|
|
| Type | The [InteractionType](https://discord.com/developers/docs/interactions/slash-commands#interaction-interactiontype) of this interaction | |
|
|
|
| Data | The `SocketInteractionData` associated with this interaction | |
|
|
|
| Token | The token used to respond to this interaction | |
|
|
|
| Version | The version of this interaction | |
|
|
|
| CreatedAt | The time this interaction was created | |
|
|
|
| IsValidToken | Whether or not the token to respond to this interaction is still valid | |
|
|
|
| RespondAsync | Responds to the interaction | |
|
|
|
| FollowupAsync | Sends a followup message to the interaction | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Whats the difference between `FollowupAsync` and `RespondAsync`? |
|
|
|
RespondAsync is the initial responce to the interaction, its used to "capture" the interaction, while followup is used to send more messages to the interaction. |
|
|
|
Basically, you want to first use `RespondAsync` to acknowledge the interaction, then if you need to send anything else regarding that interaction you would use `FollowupAsync` |
|
|
|
If you have `AlwaysAcknowledgeInteractions` set to true in your client config then it will automatically acknowledge the interaction without sending a message, |
|
|
|
in this case you can use either or to respond. |
|
|
|
|
|
|
|
#### Example ping pong command |
|
|
|
```cs |
|
|
|
_client.InteractionCreated += MyEventHandler; |
|
|
|
_client.Ready += CreateCommands |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
private async Task CreateCommands() |
|
|
|
{ |
|
|
|
await _client.Rest.CreateGlobalCommand(new Discord.SlashCommandCreationProperties() |
|
|
|
{ |
|
|
|
Name = "ping", |
|
|
|
Description = "ping for a pong!", |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task MyEventHandler(SocketInteraction arg) |
|
|
|
{ |
|
|
|
switch(arg.Type) // We want to check the type of this interaction |
|
|
|
{ |
|
|
|
case InteractionType.ApplicationCommand: // If it is a command |
|
|
|
await MySlashCommandHandler(arg); // Handle the command somewhere |
|
|
|
break; |
|
|
|
default: // We dont support it |
|
|
|
Console.WriteLine("Unsupported interaction type: " + arg.Type); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private async Task MySlashCommandHandler(SocketInteraction arg) |
|
|
|
{ |
|
|
|
switch(arg.Name) |
|
|
|
{ |
|
|
|
case "ping": |
|
|
|
await arg.RespondAsync("Pong!"); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
#### Example hug command |
|
|
|
```cs |
|
|
|
_client.InteractionCreated += MyEventHandler; |
|
|
|
_client.Ready += CreateCommands; |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
private async Task CreateCommands() |
|
|
|
{ |
|
|
|
await _client.Rest.CreateGlobalCommand(new Discord.SlashCommandCreationProperties() |
|
|
|
{ |
|
|
|
Name = "hug", |
|
|
|
Description = "Hugs a user!", |
|
|
|
Options = new List<Discord.ApplicationCommandOptionProperties>() |
|
|
|
{ |
|
|
|
new ApplicationCommandOptionProperties() |
|
|
|
{ |
|
|
|
Name = "User", |
|
|
|
Required = true, |
|
|
|
Description = "The user to hug", |
|
|
|
Type = Discord.ApplicationCommandOptionType.User, |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task MyEventHandler(SocketInteraction arg) |
|
|
|
{ |
|
|
|
switch(arg.Type) // We want to check the type of this interaction |
|
|
|
{ |
|
|
|
case InteractionType.ApplicationCommand: // If it is a command |
|
|
|
await MySlashCommandHandler(arg); // Handle the command somewhere |
|
|
|
break; |
|
|
|
default: // We dont support it |
|
|
|
Console.WriteLine("Unsupported interaction type: " + arg.Type); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private async Task MySlashCommandHandler(SocketInteraction arg) |
|
|
|
{ |
|
|
|
switch(arg.Name) |
|
|
|
{ |
|
|
|
case "hug": |
|
|
|
// Get the user argument |
|
|
|
var option = arg.Data.Options.First(x => x.Name == "user"); |
|
|
|
// We know that the options value must be a user |
|
|
|
if(option.Value is SocketGuildUser user) |
|
|
|
{ |
|
|
|
await arg.RespondAsync($"Hugged {user.Mention}"); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
|