| @@ -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; | |||||
| } | |||||
| } | |||||
| ``` | |||||