| @@ -8,7 +8,7 @@ | |||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <PackageId>Discord.Net.Labs.Core</PackageId> | |||
| <Version>2.3.8</Version> | |||
| <Version>2.3.9-pre</Version> | |||
| <Product>Discord.Net.Labs.Core</Product> | |||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | |||
| <PackageIcon>Temporary.png</PackageIcon> | |||
| @@ -3932,6 +3932,11 @@ | |||
| A <see cref="T:Discord.IRole"/>. | |||
| </summary> | |||
| </member> | |||
| <member name="F:Discord.ApplicationCommandOptionType.Mentionable"> | |||
| <summary> | |||
| </summary> | |||
| </member> | |||
| <member name="T:Discord.ApplicationCommandProperties"> | |||
| <summary> | |||
| Provides properties that are used to modify a <see cref="T:Discord.IApplicationCommand" /> with the specified changes. | |||
| @@ -4032,6 +4037,11 @@ | |||
| </note> | |||
| </summary> | |||
| </member> | |||
| <member name="P:Discord.IApplicationCommandInteractionDataOption.Type"> | |||
| <summary> | |||
| The type of this data's option. | |||
| </summary> | |||
| </member> | |||
| <member name="P:Discord.IApplicationCommandInteractionDataOption.Options"> | |||
| <summary> | |||
| Present if this option is a group or subcommand. | |||
| @@ -49,6 +49,11 @@ namespace Discord | |||
| /// <summary> | |||
| /// A <see cref="IRole"/>. | |||
| /// </summary> | |||
| Role = 8 | |||
| Role = 8, | |||
| /// <summary> | |||
| /// | |||
| /// </summary> | |||
| Mentionable = 9 | |||
| } | |||
| } | |||
| @@ -24,6 +24,11 @@ namespace Discord | |||
| /// </summary> | |||
| object Value { get; } | |||
| /// <summary> | |||
| /// The type of this data's option. | |||
| /// </summary> | |||
| ApplicationCommandOptionType Type { get; } | |||
| /// <summary> | |||
| /// Present if this option is a group or subcommand. | |||
| /// </summary> | |||
| @@ -341,7 +341,7 @@ namespace Discord | |||
| Default = this.Default, | |||
| Required = this.Required, | |||
| Type = this.Type, | |||
| Options = new List<ApplicationCommandOptionProperties>(this.Options.Select(x => x.Build())), | |||
| Options = this.Options?.Count > 0 ? new List<ApplicationCommandOptionProperties>(this.Options.Select(x => x.Build())) : null, | |||
| Choices = this.Choices | |||
| }; | |||
| } | |||
| @@ -12,6 +12,10 @@ namespace Discord.API | |||
| public string Name { get; set; } | |||
| [JsonProperty("options")] | |||
| public List<ApplicationCommandInteractionDataOption> Options { get; set; } = new(); | |||
| public List<ApplicationCommandInteractionDataOption> Options { get; set; } | |||
| [JsonProperty("resolved")] | |||
| public Optional<ApplicationCommandInteractionDataResolved> Resolved { get; set; } | |||
| } | |||
| } | |||
| @@ -6,15 +6,15 @@ namespace Discord.API | |||
| internal class ApplicationCommandInteractionDataResolved | |||
| { | |||
| [JsonProperty("users")] | |||
| public Optional<Dictionary<ulong, User>> Users { get; set; } | |||
| public Optional<Dictionary<string, User>> Users { get; set; } | |||
| [JsonProperty("members")] | |||
| public Optional<Dictionary<ulong, GuildMember>> Members { get; set; } | |||
| public Optional<Dictionary<string, GuildMember>> Members { get; set; } | |||
| [JsonProperty("channels")] | |||
| public Optional<Dictionary<ulong, Channel>> Channels { get; set; } | |||
| public Optional<Dictionary<string, Channel>> Channels { get; set; } | |||
| [JsonProperty("roles")] | |||
| public Optional<Dictionary<ulong, Role>> Roles { get; set; } | |||
| public Optional<Dictionary<string, Role>> Roles { get; set; } | |||
| } | |||
| } | |||
| @@ -9,7 +9,7 @@ | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <PackageIcon>Temporary.png</PackageIcon> | |||
| <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | |||
| <Version>2.3.8</Version> | |||
| <Version>2.3.9-pre</Version> | |||
| <PackageId>Discord.Net.Labs.Rest</PackageId> | |||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | |||
| <AssemblyVersion>2.3.4</AssemblyVersion> | |||
| @@ -10,20 +10,20 @@ namespace Discord.Rest | |||
| { | |||
| internal static class InteractionHelper | |||
| { | |||
| internal static async Task<RestInteractionMessage> SendInteractionResponse(BaseDiscordClient client, IMessageChannel channel, InteractionResponse response, | |||
| internal static Task SendInteractionResponse(BaseDiscordClient client, IMessageChannel channel, InteractionResponse response, | |||
| ulong interactionId, string interactionToken, RequestOptions options = null) | |||
| { | |||
| await client.ApiClient.CreateInteractionResponse(response, interactionId, interactionToken, options).ConfigureAwait(false); | |||
| // get the original message | |||
| var msg = await client.ApiClient.GetInteractionResponse(interactionToken).ConfigureAwait(false); | |||
| var entity = RestInteractionMessage.Create(client, msg, interactionToken, channel); | |||
| return client.ApiClient.CreateInteractionResponse(response, interactionId, interactionToken, options); | |||
| } | |||
| return entity; | |||
| internal static async Task<RestInteractionMessage> GetOriginalResponseAsync(BaseDiscordClient client, IMessageChannel channel, | |||
| IDiscordInteraction interaction, RequestOptions options = null) | |||
| { | |||
| var model = await client.ApiClient.GetInteractionResponse(interaction.Token, options).ConfigureAwait(false); | |||
| return RestInteractionMessage.Create(client, model, interaction.Token, channel); | |||
| } | |||
| internal static async Task<RestFollowupMessage> SendFollowupAsync(BaseDiscordClient client, API.Rest.CreateWebhookMessageParams args, | |||
| internal static async Task<RestFollowupMessage> SendFollowupAsync(BaseDiscordClient client, CreateWebhookMessageParams args, | |||
| string token, IMessageChannel channel, RequestOptions options = null) | |||
| { | |||
| var model = await client.ApiClient.CreateInteractionFollowupMessage(args, token, options).ConfigureAwait(false); | |||
| @@ -8,7 +8,7 @@ | |||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |||
| <Version>2.3.8</Version> | |||
| <Version>2.3.9-pre</Version> | |||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | |||
| <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | |||
| <PackageIcon>Temporary.png</PackageIcon> | |||
| @@ -3299,41 +3299,17 @@ | |||
| The data associated with this interaction. | |||
| </summary> | |||
| </member> | |||
| <member name="M:Discord.WebSocket.SocketSlashCommand.RespondAsync(System.String,System.Boolean,Discord.Embed,Discord.InteractionResponseType,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||
| <member name="M:Discord.WebSocket.SocketSlashCommand.GetOriginalResponse"> | |||
| <summary> | |||
| Responds to an Interaction. | |||
| <para> | |||
| If you have <see cref="P:Discord.WebSocket.DiscordSocketConfig.AlwaysAcknowledgeInteractions"/> set to <see langword="true"/>, You should use | |||
| <see cref="!:FollowupAsync(string, bool, Embed, InteractionResponseType, AllowedMentions, RequestOptions)"/> instead. | |||
| </para> | |||
| Gets the original response to this slash command. | |||
| </summary> | |||
| <param name="text">The text of the message to be sent.</param> | |||
| <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param> | |||
| <param name="embed">A <see cref="T:Discord.Embed"/> to send with this response.</param> | |||
| <param name="type">The type of response to this Interaction.</param> | |||
| <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param> | |||
| <param name="allowedMentions">The allowed mentions for this response.</param> | |||
| <param name="options">The request options for this response.</param> | |||
| <returns> | |||
| The <see cref="T:Discord.IMessage"/> sent as the response. If this is the first acknowledgement, it will return null. | |||
| </returns> | |||
| <exception cref="T:System.ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="F:Discord.DiscordConfig.MaxMessageSize"/>.</exception> | |||
| <exception cref="T:System.InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | |||
| <returns>A <see cref="T:Discord.Rest.RestInteractionMessage"/> that represents the initial response to this interaction.</returns> | |||
| </member> | |||
| <member name="M:Discord.WebSocket.SocketSlashCommand.RespondAsync(System.String,System.Boolean,Discord.Embed,Discord.InteractionResponseType,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||
| <inheritdoc/> | |||
| </member> | |||
| <member name="M:Discord.WebSocket.SocketSlashCommand.FollowupAsync(System.String,System.Boolean,Discord.Embed,System.Boolean,Discord.InteractionResponseType,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||
| <summary> | |||
| Sends a followup message for this interaction. | |||
| </summary> | |||
| <param name="text">The text of the message to be sent</param> | |||
| <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param> | |||
| <param name="embed">A <see cref="T:Discord.Embed"/> to send with this response.</param> | |||
| <param name="type">The type of response to this Interaction.</param> | |||
| /// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param> | |||
| <param name="allowedMentions">The allowed mentions for this response.</param> | |||
| <param name="options">The request options for this response.</param> | |||
| <returns> | |||
| The sent message. | |||
| </returns> | |||
| <inheritdoc/> | |||
| </member> | |||
| <member name="T:Discord.WebSocket.SocketSlashCommandData"> | |||
| <summary> | |||
| @@ -3359,6 +3335,9 @@ | |||
| <member name="P:Discord.WebSocket.SocketSlashCommandDataOption.Value"> | |||
| <inheritdoc/> | |||
| </member> | |||
| <member name="P:Discord.WebSocket.SocketSlashCommandDataOption.Type"> | |||
| <inheritdoc/> | |||
| </member> | |||
| <member name="P:Discord.WebSocket.SocketSlashCommandDataOption.Options"> | |||
| <summary> | |||
| The sub command options received for this sub command group. | |||
| @@ -3420,9 +3399,6 @@ | |||
| <param name="allowedMentions">The allowed mentions for this response.</param> | |||
| <param name="options">The request options for this response.</param> | |||
| <param name="component">A <see cref="T:Discord.MessageComponent"/> to be sent with this response</param> | |||
| <returns> | |||
| The <see cref="T:Discord.IMessage"/> sent as the response. If this is the first acknowledgement, it will return null. | |||
| </returns> | |||
| <exception cref="T:System.ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="F:Discord.DiscordConfig.MaxMessageSize"/>.</exception> | |||
| <exception cref="T:System.InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | |||
| </member> | |||
| @@ -3442,6 +3418,13 @@ | |||
| The sent message. | |||
| </returns> | |||
| </member> | |||
| <member name="M:Discord.WebSocket.SocketInteraction.GetOriginalResponseAsync(Discord.RequestOptions)"> | |||
| <summary> | |||
| Gets the original response for this interaction. | |||
| </summary> | |||
| <param name="options">The request options for this async request.</param> | |||
| <returns>A <see cref="T:Discord.Rest.RestInteractionMessage"/> that represents the intitial response, or <see langword="null"/> if there is no response.</returns> | |||
| </member> | |||
| <member name="M:Discord.WebSocket.SocketInteraction.AcknowledgeAsync(Discord.RequestOptions)"> | |||
| <summary> | |||
| Acknowledges this interaction with the <see cref="F:Discord.InteractionResponseType.DeferredChannelMessageWithSource"/>. | |||
| @@ -25,7 +25,7 @@ namespace Discord.WebSocket | |||
| public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient | |||
| { | |||
| private readonly ConcurrentQueue<ulong> _largeGuilds; | |||
| private readonly JsonSerializer _serializer; | |||
| internal readonly JsonSerializer _serializer; | |||
| private readonly DiscordShardedClient _shardedClient; | |||
| private readonly DiscordSocketClient _parentClient; | |||
| private readonly ConcurrentQueue<long> _heartbeatTimes; | |||
| @@ -794,6 +794,16 @@ namespace Discord.WebSocket | |||
| return null; | |||
| } | |||
| internal SocketRole AddOrUpdateRole(RoleModel model) | |||
| { | |||
| if (_roles.TryGetValue(model.Id, out SocketRole role)) | |||
| _roles[model.Id].Update(this.Discord.State, model); | |||
| else | |||
| role = AddRole(model); | |||
| return role; | |||
| } | |||
| //Users | |||
| /// <inheritdoc /> | |||
| public Task<RestGuildUser> AddGuildUserAsync(ulong id, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null) | |||
| @@ -92,7 +92,7 @@ namespace Discord.WebSocket | |||
| /// </returns> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | |||
| public override async Task<RestUserMessage> RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| public override async Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null) | |||
| { | |||
| if (type == InteractionResponseType.Pong) | |||
| @@ -102,7 +102,10 @@ namespace Discord.WebSocket | |||
| throw new InvalidOperationException("Interaction token is no longer valid"); | |||
| if (Discord.AlwaysAcknowledgeInteractions) | |||
| return await FollowupAsync(text, isTTS, embed, ephemeral, type, allowedMentions, options); | |||
| { | |||
| await FollowupAsync(text, isTTS, embed, ephemeral, type, allowedMentions, options); | |||
| return; | |||
| } | |||
| Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | |||
| Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | |||
| @@ -141,7 +144,7 @@ namespace Discord.WebSocket | |||
| if (ephemeral) | |||
| response.Data.Value.Flags = 64; | |||
| return await InteractionHelper.SendInteractionResponse(this.Discord, this.Channel, response, this.Id, Token, options); | |||
| await InteractionHelper.SendInteractionResponse(this.Discord, this.Channel, response, this.Id, Token, options); | |||
| } | |||
| /// <summary> | |||
| @@ -22,10 +22,14 @@ namespace Discord.WebSocket | |||
| : base(client, model.Id, channel) | |||
| { | |||
| var dataModel = model.Data.IsSpecified ? | |||
| (model.Data.Value as JToken).ToObject<DataModel>() | |||
| (model.Data.Value as JToken).ToObject<DataModel>(client._serializer) | |||
| : null; | |||
| Data = SocketSlashCommandData.Create(client, dataModel, model.Id); | |||
| ulong? guildId = null; | |||
| if (this.Channel is SocketGuildChannel guildChannel) | |||
| guildId = guildChannel.Guild.Id; | |||
| Data = SocketSlashCommandData.Create(client, dataModel, model.Id, guildId); | |||
| } | |||
| new internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | |||
| @@ -38,7 +42,7 @@ namespace Discord.WebSocket | |||
| internal override void Update(Model model) | |||
| { | |||
| var data = model.Data.IsSpecified ? | |||
| (model.Data.Value as JToken).ToObject<DataModel>() | |||
| (model.Data.Value as JToken).ToObject<DataModel>(Discord._serializer) | |||
| : null; | |||
| this.Data.Update(data); | |||
| @@ -47,26 +51,21 @@ namespace Discord.WebSocket | |||
| } | |||
| /// <summary> | |||
| /// Responds to an Interaction. | |||
| /// <para> | |||
| /// If you have <see cref="DiscordSocketConfig.AlwaysAcknowledgeInteractions"/> set to <see langword="true"/>, You should use | |||
| /// <see cref="FollowupAsync(string, bool, Embed, InteractionResponseType, AllowedMentions, RequestOptions)"/> instead. | |||
| /// </para> | |||
| /// Gets the original response to this slash command. | |||
| /// </summary> | |||
| /// <param name="text">The text of the message to be sent.</param> | |||
| /// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param> | |||
| /// <param name="embed">A <see cref="Embed"/> to send with this response.</param> | |||
| /// <param name="type">The type of response to this Interaction.</param> | |||
| /// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param> | |||
| /// <param name="allowedMentions">The allowed mentions for this response.</param> | |||
| /// <param name="options">The request options for this response.</param> | |||
| /// <returns> | |||
| /// The <see cref="IMessage"/> sent as the response. If this is the first acknowledgement, it will return null. | |||
| /// </returns> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | |||
| public override async Task<RestUserMessage> RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| /// <returns>A <see cref="RestInteractionMessage"/> that represents the initial response to this interaction.</returns> | |||
| public async Task<RestInteractionMessage> GetOriginalResponse() | |||
| { | |||
| // get the original message | |||
| var msg = await Discord.ApiClient.GetInteractionResponse(this.Token).ConfigureAwait(false); | |||
| var entity = RestInteractionMessage.Create(Discord, msg, this.Token, this.Channel); | |||
| return entity; | |||
| } | |||
| /// <inheritdoc/> | |||
| public override async Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null) | |||
| { | |||
| if (type == InteractionResponseType.Pong) | |||
| @@ -79,7 +78,10 @@ namespace Discord.WebSocket | |||
| throw new InvalidOperationException("Interaction token is no longer valid"); | |||
| if (Discord.AlwaysAcknowledgeInteractions) | |||
| return await FollowupAsync(text, isTTS, embed, ephemeral, type, allowedMentions, options); // The arguments should be passed? What was i thinking... | |||
| { | |||
| await FollowupAsync(text, isTTS, embed, ephemeral, type, allowedMentions, options); | |||
| return; | |||
| } | |||
| Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | |||
| Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | |||
| @@ -118,22 +120,10 @@ namespace Discord.WebSocket | |||
| if (ephemeral) | |||
| response.Data.Value.Flags = 64; | |||
| return await InteractionHelper.SendInteractionResponse(this.Discord, this.Channel, response, this.Id, Token, options); | |||
| await InteractionHelper.SendInteractionResponse(this.Discord, this.Channel, response, this.Id, Token, options); | |||
| } | |||
| /// <summary> | |||
| /// Sends a followup message for this interaction. | |||
| /// </summary> | |||
| /// <param name="text">The text of the message to be sent</param> | |||
| /// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param> | |||
| /// <param name="embed">A <see cref="Embed"/> to send with this response.</param> | |||
| /// <param name="type">The type of response to this Interaction.</param> | |||
| /// /// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param> | |||
| /// <param name="allowedMentions">The allowed mentions for this response.</param> | |||
| /// <param name="options">The request options for this response.</param> | |||
| /// <returns> | |||
| /// The sent message. | |||
| /// </returns> | |||
| /// <inheritdoc/> | |||
| public override async Task<RestFollowupMessage> FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, bool ephemeral = false, | |||
| InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null) | |||
| @@ -18,15 +18,71 @@ namespace Discord.WebSocket | |||
| /// </summary> | |||
| public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | |||
| internal SocketSlashCommandData(DiscordSocketClient client, ulong id) | |||
| : base(client, id) | |||
| internal Dictionary<ulong, SocketGuildUser> guildMembers { get; private set; } = new(); | |||
| internal Dictionary<ulong, SocketGlobalUser> users { get; private set; } = new(); | |||
| internal Dictionary<ulong, SocketChannel> channels { get; private set; } = new(); | |||
| internal Dictionary<ulong, SocketRole> roles { get; private set; } = new(); | |||
| private ulong? guildId; | |||
| internal SocketSlashCommandData(DiscordSocketClient client, Model model, ulong? guildId) | |||
| : base(client, model.Id) | |||
| { | |||
| this.guildId = guildId; | |||
| if (model.Resolved.IsSpecified) | |||
| { | |||
| var guild = this.guildId.HasValue ? Discord.GetGuild(this.guildId.Value) : null; | |||
| var resolved = model.Resolved.Value; | |||
| if (resolved.Users.IsSpecified) | |||
| { | |||
| foreach (var user in resolved.Users.Value) | |||
| { | |||
| var socketUser = Discord.GetOrCreateUser(this.Discord.State, user.Value); | |||
| this.users.Add(ulong.Parse(user.Key), socketUser); | |||
| } | |||
| } | |||
| if (resolved.Channels.IsSpecified) | |||
| { | |||
| foreach (var channel in resolved.Channels.Value) | |||
| { | |||
| SocketChannel socketChannel = channel.Value.GuildId.IsSpecified | |||
| ? SocketGuildChannel.Create(Discord.GetGuild(channel.Value.GuildId.Value), Discord.State, channel.Value) | |||
| : SocketDMChannel.Create(Discord, Discord.State, channel.Value); | |||
| Discord.State.AddChannel(socketChannel); | |||
| this.channels.Add(ulong.Parse(channel.Key), socketChannel); | |||
| } | |||
| } | |||
| if (resolved.Members.IsSpecified) | |||
| { | |||
| foreach (var member in resolved.Members.Value) | |||
| { | |||
| member.Value.User = resolved.Users.Value[member.Key]; | |||
| var user = guild.AddOrUpdateUser(member.Value); | |||
| this.guildMembers.Add(ulong.Parse(member.Key), user); | |||
| } | |||
| } | |||
| if (resolved.Roles.IsSpecified) | |||
| { | |||
| foreach (var role in resolved.Roles.Value) | |||
| { | |||
| var socketRole = guild.AddOrUpdateRole(role.Value); | |||
| this.roles.Add(ulong.Parse(role.Key), socketRole); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong id) | |||
| internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) | |||
| { | |||
| var entity = new SocketSlashCommandData(client, model.Id); | |||
| var entity = new SocketSlashCommandData(client, model, guildId); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| @@ -35,7 +91,7 @@ namespace Discord.WebSocket | |||
| this.Name = model.Name; | |||
| this.Options = model.Options.Any() | |||
| ? model.Options.Select(x => new SocketSlashCommandDataOption(x, this.Discord)).ToImmutableArray() | |||
| ? model.Options.Select(x => new SocketSlashCommandDataOption(this, x)).ToImmutableArray() | |||
| : null; | |||
| } | |||
| @@ -16,22 +16,25 @@ namespace Discord.WebSocket | |||
| /// <inheritdoc/> | |||
| public object Value { get; private set; } | |||
| /// <inheritdoc/> | |||
| public ApplicationCommandOptionType Type { get; private set; } | |||
| /// <summary> | |||
| /// The sub command options received for this sub command group. | |||
| /// </summary> | |||
| public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | |||
| private DiscordSocketClient discord; | |||
| private SocketSlashCommandData data; | |||
| internal SocketSlashCommandDataOption() { } | |||
| internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord) | |||
| internal SocketSlashCommandDataOption(SocketSlashCommandData data, Model model) | |||
| { | |||
| this.Name = model.Name; | |||
| this.Value = model.Value.IsSpecified ? model.Value.Value : null; | |||
| this.discord = discord; | |||
| this.Options = model.Options.Any() | |||
| ? model.Options.Select(x => new SocketSlashCommandDataOption(x, discord)).ToImmutableArray() | |||
| ? model.Options.Select(x => new SocketSlashCommandDataOption(data, x)).ToImmutableArray() | |||
| : null; | |||
| } | |||
| @@ -43,16 +46,12 @@ namespace Discord.WebSocket | |||
| public static explicit operator string(SocketSlashCommandDataOption option) | |||
| => option.Value.ToString(); | |||
| public static explicit operator SocketGuildChannel(SocketSlashCommandDataOption option) | |||
| public static explicit operator SocketChannel(SocketSlashCommandDataOption option) | |||
| { | |||
| if (option.Value is ulong id) | |||
| if(ulong.TryParse(option.Value.ToString(), out ulong id)) | |||
| { | |||
| var guild = option.discord.GetGuild(id); | |||
| if (guild == null) | |||
| return null; | |||
| return guild.GetChannel(id); | |||
| if (option.data.channels.TryGetValue(id, out var channel)) | |||
| return channel; | |||
| } | |||
| return null; | |||
| @@ -60,34 +59,35 @@ namespace Discord.WebSocket | |||
| public static explicit operator SocketRole(SocketSlashCommandDataOption option) | |||
| { | |||
| if (option.Value is ulong id) | |||
| if (ulong.TryParse(option.Value.ToString(), out ulong id)) | |||
| { | |||
| var guild = option.discord.GetGuild(id); | |||
| if (guild == null) | |||
| return null; | |||
| return guild.GetRole(id); | |||
| if (option.data.roles.TryGetValue(id, out var role)) | |||
| return role; | |||
| } | |||
| return null; | |||
| } | |||
| public static explicit operator SocketGuildUser(SocketSlashCommandDataOption option) | |||
| public static explicit operator SocketUser(SocketSlashCommandDataOption option) | |||
| { | |||
| if(option.Value is ulong id) | |||
| if (ulong.TryParse(option.Value.ToString(), out ulong id)) | |||
| { | |||
| var guild = option.discord.GetGuild(id); | |||
| if (option.data.users.TryGetValue(id, out var user)) | |||
| return user; | |||
| } | |||
| if (guild == null) | |||
| return null; | |||
| return null; | |||
| } | |||
| return guild.GetUser(id); | |||
| } | |||
| public static explicit operator SocketGuildUser(SocketSlashCommandDataOption option) | |||
| { | |||
| if (option.Value as SocketUser is SocketGuildUser guildUser) | |||
| return guildUser; | |||
| return null; | |||
| } | |||
| IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionDataOption.Options => this.Options; | |||
| } | |||
| } | |||
| @@ -110,13 +110,10 @@ namespace Discord.WebSocket | |||
| /// <param name="allowedMentions">The allowed mentions for this response.</param> | |||
| /// <param name="options">The request options for this response.</param> | |||
| /// <param name="component">A <see cref="MessageComponent"/> to be sent with this response</param> | |||
| /// <returns> | |||
| /// The <see cref="IMessage"/> sent as the response. If this is the first acknowledgement, it will return null. | |||
| /// </returns> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | |||
| public abstract Task<RestUserMessage> RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| public abstract Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null); | |||
| /// <summary> | |||
| @@ -137,6 +134,16 @@ namespace Discord.WebSocket | |||
| InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, | |||
| AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null); | |||
| /// <summary> | |||
| /// Gets the original response for this interaction. | |||
| /// </summary> | |||
| /// <param name="options">The request options for this async request.</param> | |||
| /// <returns>A <see cref="RestInteractionMessage"/> that represents the intitial response, or <see langword="null"/> if there is no response.</returns> | |||
| public Task<RestInteractionMessage> GetOriginalResponseAsync(RequestOptions options = null) | |||
| { | |||
| return InteractionHelper.GetOriginalResponseAsync(this.Discord, this.Channel, this, options); | |||
| } | |||
| /// <summary> | |||
| /// Acknowledges this interaction with the <see cref="InteractionResponseType.DeferredChannelMessageWithSource"/>. | |||
| /// </summary> | |||