diff --git a/src/Discord.Net.Core/Discord.Net.Core.csproj b/src/Discord.Net.Core/Discord.Net.Core.csproj index a5fdbf230..7f494db1a 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.csproj +++ b/src/Discord.Net.Core/Discord.Net.Core.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 9ca871377..ece4d69d4 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -4508,37 +4508,42 @@ - The name of this option. + Gets or sets the name of this option. - The description of this option. + Gets or sets the description of this option. - The type of this option. + Gets or sets the type of this option. - The first required option for the user to complete. only one option can be default. + Gets or sets whether or not this options is the first required option for the user to complete. only one option can be default. - if this option is required for this command, otherwise . + Gets or sets if the option is required. + + + + + Gets or sets whether or not this option supports autocomplete - choices for string and int types for the user to pick from. + Gets or sets the choices for string and int types for the user to pick from. - If the option is a subcommand or subcommand group type, this nested options will be the parameters. + Gets or sets if this option is a subcommand or subcommand group type, these nested options will be the parameters. @@ -4649,6 +4654,68 @@ ApplicationCommandType.Message is Context Menu Message command type + + + Represents an autocomplete option. + + + + + Gets the type of this option + + + + + Gets the name of the option. + + + + + Gets the value of the option. + + + + + Gets whether or not this option is focused by the executing user. + + + + + Represents a result to an autocomplete interaction. + + + + + Gets or sets the name of the result. + + + Name cannot be null and has to be between 1-100 characters in length. + + + + + + + Gets or sets the value of the result. + + + Only , , and are allowed for a value. + + + + + + + Creates a new . + + + + + Creates a new with the passed in and . + + + + A class used to build Message commands. @@ -5029,12 +5096,17 @@ - for components: ACK an interaction and edit the original message later; the user does not see a loading state + For components: ACK an interaction and edit the original message later; the user does not see a loading state - for components: edit the message the component was attached to + For components: edit the message the component was attached to + + + + + Respond with a set of choices to a autocomplete interaction @@ -5057,6 +5129,11 @@ A sent from discord. + + + An autocomplete request sent from discord. + + Represents a Row for child components to live in. @@ -5934,7 +6011,7 @@ The default permission value to set. The current builder. - + Adds an option to the current slash command. @@ -5987,37 +6064,42 @@ - The name of this option. + Gets or sets the name of this option. - The description of this option. + Gets or sets the description of this option. - The type of this option. + Gets or sets the type of this option. - The first required option for the user to complete. only one option can be default. + Gets or sets whether or not this options is the first required option for the user to complete. only one option can be default. - if this option is required for this command, otherwise . + Gets or sets if the option is required. + + + + + Gets or sets whether or not this option supports autocomplete. - choices for string and int types for the user to pick from. + Gets or sets the choices for string and int types for the user to pick from. - If the option is a subcommand or subcommand group type, this nested options will be the parameters. + Gets or sets if this option is a subcommand or subcommand group type, these nested options will be the parameters. @@ -8876,14 +8958,24 @@ authentication when used on a guild that has server-wide 2FA enabled. + + + Allows for creating public threads. + + + + + Allows for creating private threads. + + - Allows for creating and participating in threads. + Allows for creating public threads. - Allows for creating and participating in private threads. + Allows for creating private threads. @@ -8891,6 +8983,16 @@ Allows the usage of custom stickers from other servers. + + + Allows for sending messages in threads. + + + + + Allows for launching activities (applications with the EMBEDDED flag) in a voice channel. + + Gets a blank that grants no permissions. @@ -9005,25 +9107,31 @@ If true, a user may manage threads in this guild. - + If true, a user may create public threads in this guild. - + If true, a user may create private threads in this guild. If true, a user may use external stickers in this guild. + + If true, a user may send messages in threads in this guild. + + + If true, a user launch application activites in voice channels in this guild. + Creates a new with the provided packed value. Creates a new with the provided packed value after converting to ulong. - + Creates a new structure with the provided permissions. - + Creates a new from this one, changing the provided non-null permissions. diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs index 8d6e22ec1..cca832874 100644 --- a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs @@ -16,7 +16,7 @@ namespace Discord private string _description; /// - /// The name of this option. + /// Gets or sets the name of this option. /// public string Name { @@ -37,7 +37,7 @@ namespace Discord } /// - /// The description of this option. + /// Gets or sets the description of this option. /// public string Description { @@ -53,27 +53,31 @@ namespace Discord } /// - /// The type of this option. + /// Gets or sets the type of this option. /// public ApplicationCommandOptionType Type { get; set; } /// - /// The first required option for the user to complete. only one option can be default. + /// Gets or sets whether or not this options is the first required option for the user to complete. only one option can be default. /// public bool? Default { get; set; } /// - /// if this option is required for this command, otherwise . + /// Gets or sets if the option is required. /// public bool? Required { get; set; } /// - /// choices for string and int types for the user to pick from. + /// Gets or sets whether or not this option supports autocomplete. + /// + public bool Autocomplete { get; set; } + /// + /// Gets or sets the choices for string and int types for the user to pick from. /// public List Choices { get; set; } /// - /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. + /// Gets or sets if this option is a subcommand or subcommand group type, these nested options will be the parameters. /// public List Options { get; set; } diff --git a/src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs b/src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs new file mode 100644 index 000000000..9fe461d6f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents an autocomplete option. + /// + public class AutocompleteOption + { + /// + /// Gets the type of this option + /// + public ApplicationCommandOptionType Type { get; } + + /// + /// Gets the name of the option. + /// + public string Name { get; } + + /// + /// Gets the value of the option. + /// + public object Value { get; } + + /// + /// Gets whether or not this option is focused by the executing user. + /// + public bool Focused { get; } + + internal AutocompleteOption(ApplicationCommandOptionType type, string name, object value, bool focused) + { + this.Type = type; + this.Name = name; + this.Value = value; + this.Focused = focused; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs b/src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs new file mode 100644 index 000000000..881eef80d --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a result to an autocomplete interaction. + /// + public class AutocompleteResult + { + private object _value { get; set; } + private string _name { get; set; } + + /// + /// Gets or sets the name of the result. + /// + /// + /// Name cannot be null and has to be between 1-100 characters in length. + /// + /// + /// + public string Name + { + get => _name; + set + { + if (value == null) + throw new ArgumentException("Name cannot be null!"); + if (value.Length > 100) + throw new ArgumentException("Name length must be less than or equal to 100 characters in length!"); + if (value.Length < 1) + throw new ArgumentException("Name length must at least 1 character in length!"); + _name = value; + } + } + + /// + /// Gets or sets the value of the result. + /// + /// + /// Only , , and are allowed for a value. + /// + /// + /// + public object Value + { + get => _value; + set + { + if (value == null) + throw new ArgumentNullException("Value cannot be null"); + + switch (value) + { + case string str: + _value = str; + break; + case int integer: + _value = integer; + break; + case double number: + _value = number; + break; + + default: + throw new ArgumentException($"Type {value.GetType().Name} cannot be set as a value! Only string, int, and double allowed!"); + } + } + } + + /// + /// Creates a new . + /// + public AutocompleteResult() { } + + /// + /// Creates a new with the passed in and . + /// + /// + /// + public AutocompleteResult(string name, object value) + { + this.Name = name; + this.Value = value; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs b/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs index d34c282ef..de30ad868 100644 --- a/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs +++ b/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs @@ -45,13 +45,18 @@ namespace Discord DeferredChannelMessageWithSource = 5, /// - /// for components: ACK an interaction and edit the original message later; the user does not see a loading state + /// For components: ACK an interaction and edit the original message later; the user does not see a loading state /// DeferredUpdateMessage = 6, /// - /// for components: edit the message the component was attached to + /// For components: edit the message the component was attached to /// - UpdateMessage = 7 + UpdateMessage = 7, + + /// + /// Respond with a set of choices to a autocomplete interaction + /// + ApplicationCommandAutocompleteResult = 8 } } diff --git a/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs b/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs index 4da39b58e..989114505 100644 --- a/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs +++ b/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs @@ -25,5 +25,10 @@ namespace Discord /// A sent from discord. /// MessageComponent = 3, + + /// + /// An autocomplete request sent from discord. + /// + ApplicationCommandAutocomplete = 4, } } diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandBuilder.cs similarity index 95% rename from src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs rename to src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandBuilder.cs index 0f3ae1d2d..1a152feb4 100644 --- a/src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandBuilder.cs @@ -165,7 +165,7 @@ namespace Discord /// The choices of this option. /// The current builder. public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type, - string description, bool required = true, bool isDefault = false, List options = null, params ApplicationCommandOptionChoiceProperties[] choices) + string description, bool required = true, bool isDefault = false, bool isAutocomplete = false, List options = null, params ApplicationCommandOptionChoiceProperties[] choices) { // Make sure the name matches the requirements from discord Preconditions.NotNullOrEmpty(name, nameof(name)); @@ -197,6 +197,7 @@ namespace Discord option.Default = isDefault; option.Options = options; option.Type = type; + option.Autocomplete = isAutocomplete; option.Choices = choices != null ? new List(choices) : null; return AddOption(option); @@ -288,7 +289,7 @@ namespace Discord private string _description; /// - /// The name of this option. + /// Gets or sets the name of this option. /// public string Name { @@ -309,7 +310,7 @@ namespace Discord } /// - /// The description of this option. + /// Gets or sets the description of this option. /// public string Description { @@ -326,27 +327,32 @@ namespace Discord } /// - /// The type of this option. + /// Gets or sets the type of this option. /// public ApplicationCommandOptionType Type { get; set; } /// - /// The first required option for the user to complete. only one option can be default. + /// Gets or sets whether or not this options is the first required option for the user to complete. only one option can be default. /// public bool? Default { get; set; } /// - /// if this option is required for this command, otherwise . + /// Gets or sets if the option is required. /// public bool Required { get; set; } /// - /// choices for string and int types for the user to pick from. + /// Gets or sets whether or not this option supports autocomplete. + /// + public bool Autocomplete { get; set; } + + /// + /// Gets or sets the choices for string and int types for the user to pick from. /// public List Choices { get; set; } /// - /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. + /// Gets or sets if this option is a subcommand or subcommand group type, these nested options will be the parameters. /// public List Options { get; set; } @@ -372,7 +378,8 @@ namespace Discord Required = this.Required, Type = this.Type, Options = this.Options?.Count > 0 ? new List(this.Options.Select(x => x.Build())) : null, - Choices = this.Choices + Choices = this.Choices, + Autocomplete = this.Autocomplete }; } diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommandProperties.cs b/src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandProperties.cs similarity index 100% rename from src/Discord.Net.Core/Entities/Interactions/SlashCommandProperties.cs rename to src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandProperties.cs diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs index 3a9411720..2169e601e 100644 --- a/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs @@ -30,6 +30,9 @@ namespace Discord.API [JsonProperty("options")] public Optional Options { get; set; } + [JsonProperty("autocomplete")] + public Optional Autocomplete { get; set; } + public ApplicationCommandOption() { } public ApplicationCommandOption(IApplicationCommandOption cmd) @@ -78,6 +81,7 @@ namespace Discord.API this.Name = option.Name; this.Type = option.Type; this.Description = option.Description; + this.Autocomplete = option.Autocomplete; } } } diff --git a/src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs new file mode 100644 index 000000000..ea2cd4fd9 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class AutocompleteInteractionData : IDiscordInteractionData + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public ApplicationCommandType Type { get; set; } + + [JsonProperty("version")] + public ulong Version { get; set; } + + [JsonProperty("options")] + public AutocompleteInteractionDataOption[] Options { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs new file mode 100644 index 000000000..a9d5b66f0 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class AutocompleteInteractionDataOption + { + [JsonProperty("type")] + public ApplicationCommandOptionType Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("value")] + public object Value { get; set; } + + [JsonProperty("focused")] + public bool Focused { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs b/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs index 2101f79f4..38b35c8ec 100644 --- a/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs +++ b/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs @@ -21,5 +21,8 @@ namespace Discord.API [JsonProperty("components")] public Optional Components { get; set; } + + [JsonProperty("choices")] + public Optional Choices { get; set; } } } diff --git a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs index ce7953e1e..52449a121 100644 --- a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs +++ b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs @@ -418,6 +418,28 @@ namespace Discord.Rest public static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null) => await client.ApiClient.DeleteInteractionFollowupMessageAsync(message.Id, message.Token, options); + + public static Task SendAutocompleteResult(BaseDiscordClient client, IEnumerable result, ulong interactionId, + string interactionToken, RequestOptions options) + { + if (result == null) + result = new AutocompleteResult[0]; + + Preconditions.AtMost(result.Count(), 20, nameof(result), "A maximum of 20 choices are allowed!"); + + var apiArgs = new InteractionResponse() + { + Type = InteractionResponseType.ApplicationCommandAutocompleteResult, + Data = new InteractionCallbackData() + { + Choices = result.Any() + ? result.Select(x => new API.ApplicationCommandOptionChoice() { Name = x.Name, Value = x.Value }).ToArray() + : new ApplicationCommandOptionChoice[0] + } + }; + + return client.ApiClient.CreateInteractionResponseAsync(apiArgs, interactionId, interactionToken, options); + } #endregion #region Guild permissions diff --git a/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs b/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs index cda3b1e24..8159165c9 100644 --- a/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs +++ b/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs @@ -53,6 +53,13 @@ namespace Discord.Net.Converters interaction.Data = messageComponent; } break; + case InteractionType.ApplicationCommandAutocomplete: + { + var autocompleteData = new API.AutocompleteInteractionData(); + serializer.Populate(result.CreateReader(), autocompleteData); + interaction.Data = autocompleteData; + } + break; } } else diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index dd0866f0c..c08906290 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -3961,6 +3961,98 @@ The value(s) of a interaction response. + + + Represents a received over the gateway. + + + + + The autocomplete data of this interaction. + + + + + Responds to this interaction with a set of choices. + + + The set of choices for the user to pick from. + + A max of 20 choices are allowed. Passing for this argument will show the executing user that + there is no choices for their autocompleted input. + + + The request options for this response. + + A task that represents the asynchronous operation of responding to this interaction. + + + + + Responds to this interaction with a set of choices. + + The request options for this response. + + The set of choices for the user to pick from. + + A max of 20 choices are allowed. Passing for this argument will show the executing user that + there is no choices for their autocompleted input. + + + + A task that represents the asynchronous operation of responding to this interaction. + + + + + + + + + + + + + + + + + + + + Represents data for a slash commands autocomplete interaction. + + + + + Gets the name of the invoked command. + + + + + Gets the id of the invoked command. + + + + + Gets the type of the invoked command. + + + + + Gets the version of the invoked command. + + + + + Gets the current autocomplete option that is activly being filled out. + + + + + Gets a collection of all the other options the executing users has filled out. + + Represents a Websocket-based slash command received over the gateway. @@ -4088,7 +4180,17 @@ - Base class for User, Message, and Slash command interactions + Base class for User, Message, and Slash command interactions. + + + + + Gets the name of the invoked command. + + + + + Gets the id of the invoked command. diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketAutocompleteInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketAutocompleteInteraction.cs new file mode 100644 index 000000000..fe6322392 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketAutocompleteInteraction.cs @@ -0,0 +1,97 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.AutocompleteInteractionData; + + +namespace Discord.WebSocket +{ + /// + /// Represents a received over the gateway. + /// + public class SocketAutocompleteInteraction : SocketInteraction + { + /// + /// The autocomplete data of this interaction. + /// + public new SocketAutocompleteInteractionData Data { get; } + + internal SocketAutocompleteInteraction(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model.Id, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + if (dataModel != null) + Data = new SocketAutocompleteInteractionData(dataModel); + } + + internal new static SocketAutocompleteInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketAutocompleteInteraction(client, model, channel); + entity.Update(model); + return entity; + } + + /// + /// Responds to this interaction with a set of choices. + /// + /// + /// The set of choices for the user to pick from. + /// + /// A max of 20 choices are allowed. Passing for this argument will show the executing user that + /// there is no choices for their autocompleted input. + /// + /// + /// The request options for this response. + /// + /// A task that represents the asynchronous operation of responding to this interaction. + /// + public Task RespondAsync(IEnumerable result, RequestOptions options = null) + => InteractionHelper.SendAutocompleteResult(Discord, result, this.Id, this.Token, options); + + /// + /// Responds to this interaction with a set of choices. + /// + /// The request options for this response. + /// + /// The set of choices for the user to pick from. + /// + /// A max of 20 choices are allowed. Passing for this argument will show the executing user that + /// there is no choices for their autocompleted input. + /// + /// + /// + /// A task that represents the asynchronous operation of responding to this interaction. + /// + public Task RespondAsync(RequestOptions options = null, params AutocompleteResult[] result) + => InteractionHelper.SendAutocompleteResult(Discord, result, this.Id, this.Token, options); + + + /// + [Obsolete("Autocomplete interactions cannot be defered!", true)] + public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) => throw new NotSupportedException(); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupWithFileAsync(string text = null, Stream fileStream = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupWithFileAsync(string text = null, string filePath = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + + /// + [Obsolete("Autocomplete interactions cannot have normal responses!", true)] + public override Task RespondAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketAutocompleteInteractionData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketAutocompleteInteractionData.cs new file mode 100644 index 000000000..34087116d --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketAutocompleteInteractionData.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel = Discord.API.AutocompleteInteractionData; + + +namespace Discord.WebSocket +{ + /// + /// Represents data for a slash commands autocomplete interaction. + /// + public class SocketAutocompleteInteractionData + { + /// + /// Gets the name of the invoked command. + /// + public string CommandName { get; } + + /// + /// Gets the id of the invoked command. + /// + public ulong CommandId { get; } + + /// + /// Gets the type of the invoked command. + /// + public ApplicationCommandType Type { get; } + + /// + /// Gets the version of the invoked command. + /// + public ulong Version { get; } + + /// + /// Gets the current autocomplete option that is activly being filled out. + /// + public AutocompleteOption Current { get; } + + /// + /// Gets a collection of all the other options the executing users has filled out. + /// + public IReadOnlyCollection Options { get; } + + internal SocketAutocompleteInteractionData(DataModel model) + { + var options = model.Options.Select(x => new AutocompleteOption(x.Type, x.Name, x.Value, x.Focused)); + + this.Current = options.FirstOrDefault(x => x.Focused); + this.Options = options.ToImmutableArray(); + + this.CommandName = model.Name; + this.CommandId = model.Id; + this.Type = model.Type; + this.Version = model.Version; + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs index c65048a34..d32abb610 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs @@ -12,10 +12,22 @@ using Model = Discord.API.Interaction; namespace Discord.WebSocket { /// - /// Base class for User, Message, and Slash command interactions + /// Base class for User, Message, and Slash command interactions. /// public class SocketCommandBase : SocketInteraction { + /// + /// Gets the name of the invoked command. + /// + public string CommandName + => Data.Name; + + /// + /// Gets the id of the invoked command. + /// + public ulong CommandId + => Data.Id; + /// /// The data associated with this interaction. /// diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs index 7baab2496..d88a7f004 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs @@ -65,23 +65,28 @@ namespace Discord.WebSocket { if (model.Type == InteractionType.ApplicationCommand) { - if (model.ApplicationId != null) - { - var dataModel = model.Data.IsSpecified ? + var dataModel = model.Data.IsSpecified ? (DataModel)model.Data.Value : null; - if (dataModel != null) - { - if (dataModel.Type.Equals(ApplicationCommandType.User)) - return SocketUserCommand.Create(client, model, channel); - if (dataModel.Type.Equals(ApplicationCommandType.Message)) - return SocketMessageCommand.Create(client, model, channel); - } + + if (dataModel == null) + return null; + + switch (dataModel.Type) + { + case ApplicationCommandType.Slash: + return SocketSlashCommand.Create(client, model, channel); + case ApplicationCommandType.Message: + return SocketMessageCommand.Create(client, model, channel); + case ApplicationCommandType.User: + return SocketUserCommand.Create(client, model, channel); + default: return null; } - return SocketSlashCommand.Create(client, model, channel); } - if (model.Type == InteractionType.MessageComponent) + else if (model.Type == InteractionType.MessageComponent) return SocketMessageComponent.Create(client, model, channel); + else if (model.Type == InteractionType.ApplicationCommandAutocomplete) + return SocketAutocompleteInteraction.Create(client, model, channel); else return null; }