Warning
Slash commands and interactions are still under development and are subject to change at any time. This doccument is temporary and is only here to help those who wish to use the interaction features in the development state.
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:
_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:
var commands = _client.Rest.GetGlobalApplicationCommands();
This returns a IReadOnlyCollection<RestGlobalCommand>
.
You can also fetch guild specific commands:
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
_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 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
_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
_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. Types of user, channel, and role return the snowflake id of that object.
// For this case we can just mention the user with the id
await arg.RespondAsync($"Hugged <@{user.Value}>");
break;
}
}
Wrapping up
These examples are soon to change as there is currently a command service being written that will support slash commands. These examples are written for #1717. You can see the progress of slash commands on pull #1733