Browse Source

Merge branch 'dev' into feature/modals

pull/2087/head
Quin Lynch 3 years ago
parent
commit
c56e5c16f0
17 changed files with 253 additions and 62 deletions
  1. +77
    -0
      .github/ISSUE_TEMPLATE/bugreport.yml
  2. +1
    -1
      src/Discord.Net.Core/Entities/Guilds/GuildFeature.cs
  3. +6
    -1
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs
  4. +3
    -2
      src/Discord.Net.Core/Extensions/MessageExtensions.cs
  5. +52
    -1
      src/Discord.Net.Interactions/InteractionModuleBase.cs
  6. +1
    -0
      src/Discord.Net.Interactions/InteractionService.cs
  7. +5
    -0
      src/Discord.Net.Interactions/TypeConverters/DefaultEntityTypeConverter.cs
  8. +2
    -0
      src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataResolved.cs
  9. +6
    -0
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  10. +13
    -0
      src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs
  11. +23
    -8
      src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs
  12. +6
    -1
      src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs
  13. +4
    -0
      src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandDataOption.cs
  14. +33
    -48
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  15. +4
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandDataOption.cs
  16. +13
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketResolvableData.cs
  17. +4
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs

+ 77
- 0
.github/ISSUE_TEMPLATE/bugreport.yml View File

@@ -0,0 +1,77 @@
name: 🐞 Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: Thanks for taking the time to fill out this bug report!
- type: checkboxes
attributes:
label: Check The Docs
description: Please refer to our [FAQs](https://discordnet.dev/faq/basics/getting-started.html), [Documentation](https://discordnet.dev/api/index.html),
and [Migration Guide](https://discordnet.dev/guides/v2_v3_guide/v2_to_v3_guide.html) before reporting issues.
options:
- label: "I double checked the docs and couldn't find any useful information."
required: true
- type: checkboxes
attributes:
label: Verify Issue Source
description: If your issue is related to an exception make sure the error was thrown by Discord.Net, and not your code or another library.
If you get an `HttpException` with the error code `401`, then the error is caused by your bot's permissions, not dnet.
options:
- label: I verified the issue was caused by Discord.Net.
required: true
- type: checkboxes
attributes:
label: Check your intents
description: If your issue is related to not receiving expected events, you may have setup your gateway intents incorrectly.
Newer versions of Discord.Net use a more modern version of Discord's API that requires you tell it what events
you want to receive. Discord.Net defaults to all non-privleged intents, but if your bot requires privileged intents
you need specify them in your clients config. You can see what intents you need for your events
[here](https://discord.com/developers/docs/topics/gateway#list-of-intents).
options:
- label: I double checked that I have the required intents.
required: true
- type: textarea
id: description
attributes:
label: Description
description: A brief explination of the bug.
placeholder: When I start a DiscordSocketClient without stopping it, the gateway thread gets blocked.
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: What version of Discord.Net are you using?
placeholder: ex. 3.1.0
validations:
required: true
- type: input
id: working-version
attributes:
label: Working Version
description: If this worked on an older version of Discord.Net put that version here.
placeholder: ex. 2.4.0
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs
description: Add applicable logs and/or a stacktrace here.
validations:
required: true
- type: textarea
id: sample
attributes:
label: Sample
description: Include a (short) code sample that reproduces your issue 100% of time (comments would be great).
placeholder: |
```cs
My.Code();
```
validations:
required: false

+ 1
- 1
src/Discord.Net.Core/Entities/Guilds/GuildFeature.cs View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace Discord
{
[Flags]
public enum GuildFeature
public enum GuildFeature : long
{
/// <summary>
/// The guild has no features.


+ 6
- 1
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs View File

@@ -53,6 +53,11 @@ namespace Discord
/// <summary>
/// A <see cref="double"/>.
/// </summary>
Number = 10
Number = 10,

/// <summary>
/// A <see cref="Discord.Attachment"/>.
/// </summary>
Attachment = 11
}
}

+ 3
- 2
src/Discord.Net.Core/Extensions/MessageExtensions.cs View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Discord
@@ -41,7 +42,7 @@ namespace Discord
/// </returns>
/// <seealso cref="IMessage.AddReactionAsync(IEmote, RequestOptions)"/>
/// <seealso cref="IEmote"/>
public static async Task AddReactionsAsync(this IUserMessage msg, IEmote[] reactions, RequestOptions options = null)
public static async Task AddReactionsAsync(this IUserMessage msg, IEnumerable<IEmote> reactions, RequestOptions options = null)
{
foreach (var rxn in reactions)
await msg.AddReactionAsync(rxn, options).ConfigureAwait(false);
@@ -67,7 +68,7 @@ namespace Discord
/// </returns>
/// <seealso cref="IMessage.RemoveReactionAsync(IEmote, IUser, RequestOptions)"/>
/// <seealso cref="IEmote"/>
public static async Task RemoveReactionsAsync(this IUserMessage msg, IUser user, IEmote[] reactions, RequestOptions options = null)
public static async Task RemoveReactionsAsync(this IUserMessage msg, IUser user, IEnumerable<IEmote> reactions, RequestOptions options = null)
{
foreach (var rxn in reactions)
await msg.RemoveReactionAsync(rxn, user, options).ConfigureAwait(false);


+ 52
- 1
src/Discord.Net.Interactions/InteractionModuleBase.cs View File

@@ -1,4 +1,7 @@
using Discord.Rest;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace Discord.Interactions
@@ -47,18 +50,66 @@ namespace Discord.Interactions
AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, Embed embed = null) =>
await Context.Interaction.RespondAsync(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false);

/// <inheritdoc cref="IDiscordInteraction.RespondWithFileAsync(Stream, string, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task RespondWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.RespondWithFileAsync(fileStream, fileName, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.RespondWithFileAsync(string, string, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task RespondWithFileAsync(string filePath, string fileName = null, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.RespondWithFileAsync(filePath, fileName, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.RespondWithFileAsync(FileAttachment, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task RespondWithFileAsync(FileAttachment attachment, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.RespondWithFileAsync(attachment, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.RespondWithFilesAsync(IEnumerable{FileAttachment}, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task RespondWithFilesAsync(IEnumerable<FileAttachment> attachments, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.RespondWithFilesAsync(attachments, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.FollowupAsync(string, Embed[], bool, bool, AllowedMentions, RequestOptions, MessageComponent, Embed)"/>
protected virtual async Task<IUserMessage> FollowupAsync (string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, Embed embed = null) =>
await Context.Interaction.FollowupAsync(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false);

/// <inheritdoc cref="IDiscordInteraction.FollowupWithFileAsync(Stream, string, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task<IUserMessage> FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.FollowupWithFileAsync(fileStream, fileName, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.FollowupWithFileAsync(string, string, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task<IUserMessage> FollowupWithFileAsync(string filePath, string fileName = null, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.FollowupWithFileAsync(filePath, fileName, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.FollowupWithFileAsync(FileAttachment, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task<IUserMessage> FollowupWithFileAsync(FileAttachment attachment, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.FollowupWithFileAsync(attachment, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IDiscordInteraction.FollowupWithFilesAsync(IEnumerable{FileAttachment}, string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/>
protected virtual Task<IUserMessage> FollowupWithFilesAsync(IEnumerable<FileAttachment> attachments, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
=> Context.Interaction.FollowupWithFilesAsync(attachments, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);

/// <inheritdoc cref="IMessageChannel.SendMessageAsync(string, bool, Embed, RequestOptions, AllowedMentions, MessageReference, MessageComponent, ISticker[], Embed[])"/>
protected virtual async Task<IUserMessage> ReplyAsync (string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null,
AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null) =>
await Context.Channel.SendMessageAsync(text, false, embed, options, allowedMentions, messageReference, components).ConfigureAwait(false);

/// <inheritdoc cref="IDiscordInteraction.GetOriginalResponseAsync(RequestOptions)"/>
protected virtual Task<IUserMessage> GetOriginalResponseAsync(RequestOptions options = null)
=> Context.Interaction.GetOriginalResponseAsync(options);

/// <inheritdoc cref="IDiscordInteraction.ModifyOriginalResponseAsync(Action{MessageProperties}, RequestOptions)"/>
protected virtual Task<IUserMessage> ModifyOriginalResponseAsync(Action<MessageProperties> func, RequestOptions options = null)
=> Context.Interaction.ModifyOriginalResponseAsync(func, options);

/// <inheritdoc cref="IDeletable.DeleteAsync(RequestOptions)"/>
protected virtual async Task DeleteOriginalResponseAsync ( )
protected virtual async Task DeleteOriginalResponseAsync()
{
var response = await Context.Interaction.GetOriginalResponseAsync().ConfigureAwait(false);
await response.DeleteAsync().ConfigureAwait(false);


+ 1
- 0
src/Discord.Net.Interactions/InteractionService.cs View File

@@ -183,6 +183,7 @@ namespace Discord.Interactions
{
[typeof(IChannel)] = typeof(DefaultChannelConverter<>),
[typeof(IRole)] = typeof(DefaultRoleConverter<>),
[typeof(IAttachment)] = typeof(DefaultAttachmentConverter<>),
[typeof(IUser)] = typeof(DefaultUserConverter<>),
[typeof(IMentionable)] = typeof(DefaultMentionableConverter<>),
[typeof(IConvertible)] = typeof(DefaultValueConverter<>),


+ 5
- 0
src/Discord.Net.Interactions/TypeConverters/DefaultEntityTypeConverter.cs View File

@@ -20,6 +20,11 @@ namespace Discord.Interactions
}
}

internal class DefaultAttachmentConverter<T> : DefaultEntityTypeConverter<T> where T : class, IAttachment
{
public override ApplicationCommandOptionType GetDiscordType() => ApplicationCommandOptionType.Attachment;
}

internal class DefaultRoleConverter<T> : DefaultEntityTypeConverter<T> where T : class, IRole
{
public override ApplicationCommandOptionType GetDiscordType ( ) => ApplicationCommandOptionType.Role;


+ 2
- 0
src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataResolved.cs View File

@@ -18,5 +18,7 @@ namespace Discord.API
public Optional<Dictionary<string, Role>> Roles { get; set; }
[JsonProperty("messages")]
public Optional<Dictionary<string, Message>> Messages { get; set; }
[JsonProperty("attachments")]
public Optional<Dictionary<string, Attachment>> Attachments { get; set; }
}
}

+ 6
- 0
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -1362,6 +1362,12 @@ namespace Discord.API

return await SendJsonAsync<Message>("PATCH", () => $"webhooks/{CurrentApplicationId}/{interactionToken}/messages/@original", args, new BucketIds(), options: options);
}
public async Task<Message> ModifyInteractionResponseAsync(UploadWebhookFileParams args, string interactionToken, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

return await SendMultipartAsync<Message>("PATCH", () => $"webhooks/{CurrentApplicationId}/{interactionToken}/messages/@original", args.ToDictionary(), new BucketIds(), options: options);
}
public async Task DeleteInteractionResponseAsync(string interactionToken, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);


+ 13
- 0
src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs View File

@@ -19,6 +19,9 @@ namespace Discord.Rest
internal readonly Dictionary<ulong, RestMessage> Messages
= new Dictionary<ulong, RestMessage>();

internal readonly Dictionary<ulong, Attachment> Attachments
= new Dictionary<ulong, Attachment>();

internal async Task PopulateAsync(DiscordRestClient discord, RestGuild guild, IRestMessageChannel channel, T model)
{
var resolved = model.Resolved.Value;
@@ -91,6 +94,16 @@ namespace Discord.Rest
Messages.Add(message.Id, message);
}
}
if (resolved.Attachments.IsSpecified)
{
foreach (var attachment in resolved.Attachments.Value)
{
var discordAttachment = Attachment.Create(attachment.Value);

Attachments.Add(ulong.Parse(attachment.Key), discordAttachment);
}
}
}
}
}

+ 23
- 8
src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs View File

@@ -424,16 +424,31 @@ namespace Discord.Rest

Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed.");

var apiArgs = new ModifyInteractionResponseParams
if (!args.Attachments.IsSpecified)
{
Content = args.Content,
Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified,
AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified,
Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified,
Flags = args.Flags
};
var apiArgs = new ModifyInteractionResponseParams
{
Content = args.Content,
Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified,
AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified,
Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified,
Flags = args.Flags
};

return await client.ApiClient.ModifyInteractionResponseAsync(apiArgs, token, options).ConfigureAwait(false);
return await client.ApiClient.ModifyInteractionResponseAsync(apiArgs, token, options).ConfigureAwait(false);
}
else
{
var apiArgs = new UploadWebhookFileParams(args.Attachments.Value.ToArray())
{
Content = args.Content,
Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified,
AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified,
MessageComponents = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified,
};

return await client.ApiClient.ModifyInteractionResponseAsync(apiArgs, token, options).ConfigureAwait(false);
}
}

public static async Task DeleteInteractionResponseAsync(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null)


+ 6
- 1
src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs View File

@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Model = Discord.API.Interaction;
using DataModel = Discord.API.ApplicationCommandInteractionData;
using Newtonsoft.Json;
using Discord.Net;

namespace Discord.Rest
{
@@ -133,7 +134,11 @@ namespace Discord.Rest

if(Channel == null && model.ChannelId.IsSpecified)
{
Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value);
try
{
Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value);
}
catch(HttpException x) when(x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore
}

UserLocale = model.UserLocale.IsSpecified


+ 4
- 0
src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandDataOption.cs View File

@@ -43,6 +43,7 @@ namespace Discord.Rest
case ApplicationCommandOptionType.Role:
case ApplicationCommandOptionType.Channel:
case ApplicationCommandOptionType.Mentionable:
case ApplicationCommandOptionType.Attachment:
if (ulong.TryParse($"{model.Value.Value}", out var valueId))
{
switch (Type)
@@ -80,6 +81,9 @@ namespace Discord.Rest
}
}
break;
case ApplicationCommandOptionType.Attachment:
Value = data.ResolvableData.Attachments.FirstOrDefault(x => x.Key == valueId).Value;
break;
default:
Value = model.Value.Value;
break;


+ 33
- 48
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -46,6 +46,7 @@ namespace Discord.WebSocket
private bool _isDisposed;
private GatewayIntents _gatewayIntents;
private ImmutableArray<StickerPack<SocketSticker>> _defaultStickers;
private SocketSelfUser _previousSessionUser;

/// <summary>
/// Provides access to a REST-only client with a shared state from this client.
@@ -888,6 +889,7 @@ namespace Discord.WebSocket
_sessionId = data.SessionId;
_unavailableGuildCount = unavailableGuilds;
CurrentUser = currentUser;
_previousSessionUser = CurrentUser;
State = state;
}
catch (Exception ex)
@@ -930,6 +932,9 @@ namespace Discord.WebSocket
await GuildAvailableAsync(guild).ConfigureAwait(false);
}

// Restore the previous sessions current user
CurrentUser = _previousSessionUser;

await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false);
}
break;
@@ -2238,60 +2243,40 @@ namespace Discord.WebSocket
channel = State.GetDMChannel(data.User.Value.Id);
}

if (channel == null)
var guild = (channel as SocketGuildChannel)?.Guild;
if (guild != null && !guild.IsSynced)
{
var channelModel = await Rest.ApiClient.GetChannelAsync(data.ChannelId.Value);

if (data.GuildId.IsSpecified)
channel = SocketTextChannel.Create(State.GetGuild(data.GuildId.Value), State, channelModel);
else
channel = (SocketChannel)SocketChannel.CreatePrivate(this, State, channelModel);

State.AddChannel(channel);
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

if (channel is ISocketMessageChannel textChannel)
{
var guild = (channel as SocketGuildChannel)?.Guild;
if (guild != null && !guild.IsSynced)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

var interaction = SocketInteraction.Create(this, data, channel as ISocketMessageChannel);
var interaction = SocketInteraction.Create(this, data, channel as ISocketMessageChannel);

await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false);
await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false);

switch (interaction)
{
case SocketSlashCommand slashCommand:
await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false);
break;
case SocketMessageComponent messageComponent:
if(messageComponent.Data.Type == ComponentType.SelectMenu)
await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false);
if(messageComponent.Data.Type == ComponentType.Button)
await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false);
break;
case SocketUserCommand userCommand:
await TimedInvokeAsync(_userCommandExecuted, nameof(UserCommandExecuted), userCommand).ConfigureAwait(false);
break;
case SocketMessageCommand messageCommand:
await TimedInvokeAsync(_messageCommandExecuted, nameof(MessageCommandExecuted), messageCommand).ConfigureAwait(false);
break;
case SocketAutocompleteInteraction autocomplete:
await TimedInvokeAsync(_autocompleteExecuted, nameof(AutocompleteExecuted), autocomplete).ConfigureAwait(false);
break;
case SocketModal modal:
await TimedInvokeAsync(_modalSubmitted, nameof(ModalSubmitted), modal).ConfigureAwait(false);
break;
}
}
else
switch (interaction)
{
await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false);
return;
case SocketSlashCommand slashCommand:
await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false);
break;
case SocketMessageComponent messageComponent:
if (messageComponent.Data.Type == ComponentType.SelectMenu)
await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false);
if (messageComponent.Data.Type == ComponentType.Button)
await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false);
break;
case SocketUserCommand userCommand:
await TimedInvokeAsync(_userCommandExecuted, nameof(UserCommandExecuted), userCommand).ConfigureAwait(false);
break;
case SocketMessageCommand messageCommand:
await TimedInvokeAsync(_messageCommandExecuted, nameof(MessageCommandExecuted), messageCommand).ConfigureAwait(false);
break;
case SocketAutocompleteInteraction autocomplete:
await TimedInvokeAsync(_autocompleteExecuted, nameof(AutocompleteExecuted), autocomplete).ConfigureAwait(false);
break;
case SocketModal modal:
await TimedInvokeAsync(_modalSubmitted, nameof(ModalSubmitted), modal).ConfigureAwait(false);
break;
}
}
break;


+ 4
- 0
src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandDataOption.cs View File

@@ -39,6 +39,7 @@ namespace Discord.WebSocket
case ApplicationCommandOptionType.Role:
case ApplicationCommandOptionType.Channel:
case ApplicationCommandOptionType.Mentionable:
case ApplicationCommandOptionType.Attachment:
if (ulong.TryParse($"{model.Value.Value}", out var valueId))
{
switch (Type)
@@ -76,6 +77,9 @@ namespace Discord.WebSocket
}
}
break;
case ApplicationCommandOptionType.Attachment:
Value = data.ResolvableData.Attachments.FirstOrDefault(x => x.Key == valueId).Value;
break;
default:
Value = model.Value.Value;
break;


+ 13
- 0
src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketResolvableData.cs View File

@@ -16,6 +16,9 @@ namespace Discord.WebSocket
internal readonly Dictionary<ulong, SocketMessage> Messages
= new Dictionary<ulong, SocketMessage>();

internal readonly Dictionary<ulong, Attachment> Attachments
= new Dictionary<ulong, Attachment>();

internal SocketResolvableData(DiscordSocketClient discord, ulong? guildId, T model)
{
var guild = guildId.HasValue ? discord.GetGuild(guildId.Value) : null;
@@ -104,6 +107,16 @@ namespace Discord.WebSocket
Messages.Add(message.Id, message);
}
}

if (resolved.Attachments.IsSpecified)
{
foreach (var attachment in resolved.Attachments.Value)
{
var discordAttachment = Attachment.Create(attachment.Value);

Attachments.Add(ulong.Parse(attachment.Key), discordAttachment);
}
}
}
}
}

+ 4
- 0
src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs View File

@@ -17,6 +17,10 @@ namespace Discord.WebSocket
/// <summary>
/// The <see cref="ISocketMessageChannel"/> this interaction was used in.
/// </summary>
/// <remarks>
/// If the channel isn't cached or the bot doesn't have access to it then
/// this property will be <see langword="null"/>.
/// </remarks>
public ISocketMessageChannel Channel { get; private set; }

/// <summary>


Loading…
Cancel
Save