| @@ -5653,7 +5653,7 @@ | |||||
| Gets or sets this menu options description. | Gets or sets this menu options description. | ||||
| </summary> | </summary> | ||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.SelectMenuOptionBuilder.Description"/> length exceeds <see cref="F:Discord.SelectMenuOptionBuilder.MaxDescriptionLength"/>.</exception> | <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.SelectMenuOptionBuilder.Description"/> length exceeds <see cref="F:Discord.SelectMenuOptionBuilder.MaxDescriptionLength"/>.</exception> | ||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.SelectMenuOptionBuilder.Label"/> length subceeds 1.</exception> | |||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.SelectMenuOptionBuilder.Description"/> length subceeds 1.</exception> | |||||
| </member> | </member> | ||||
| <member name="P:Discord.SelectMenuOptionBuilder.Emote"> | <member name="P:Discord.SelectMenuOptionBuilder.Emote"> | ||||
| <summary> | <summary> | ||||
| @@ -10979,7 +10979,7 @@ | |||||
| <seealso cref="M:Discord.IMessage.RemoveReactionAsync(Discord.IEmote,Discord.IUser,Discord.RequestOptions)"/> | <seealso cref="M:Discord.IMessage.RemoveReactionAsync(Discord.IEmote,Discord.IUser,Discord.RequestOptions)"/> | ||||
| <seealso cref="T:Discord.IEmote"/> | <seealso cref="T:Discord.IEmote"/> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.MessageExtensions.ReplyAsync(Discord.IUserMessage,System.String,System.Boolean,Discord.Embed,Discord.AllowedMentions,Discord.RequestOptions)"> | |||||
| <member name="M:Discord.MessageExtensions.ReplyAsync(Discord.IUserMessage,System.String,System.Boolean,Discord.Embed,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.ISticker[])"> | |||||
| <summary> | <summary> | ||||
| Sends an inline reply that references a message. | Sends an inline reply that references a message. | ||||
| </summary> | </summary> | ||||
| @@ -367,8 +367,6 @@ namespace Discord | |||||
| if (value.Length < 1) | if (value.Length < 1) | ||||
| throw new ArgumentException("Button label must be 1 character or more!", paramName: nameof(Label)); | throw new ArgumentException("Button label must be 1 character or more!", paramName: nameof(Label)); | ||||
| } | } | ||||
| else | |||||
| throw new ArgumentException("Button label must not be null or empty!", paramName: nameof(Label)); | |||||
| _label = value; | _label = value; | ||||
| } | } | ||||
| @@ -391,8 +389,6 @@ namespace Discord | |||||
| if (value.Length < 1) | if (value.Length < 1) | ||||
| throw new ArgumentException("Custom Id must be 1 character or more!", paramName: nameof(CustomId)); | throw new ArgumentException("Custom Id must be 1 character or more!", paramName: nameof(CustomId)); | ||||
| } | } | ||||
| else | |||||
| throw new ArgumentException("Custom Id must not be null or empty!", paramName: nameof(CustomId)); | |||||
| _customId = value; | _customId = value; | ||||
| } | } | ||||
| } | } | ||||
| @@ -644,8 +640,6 @@ namespace Discord | |||||
| if (value.Length < 1) | if (value.Length < 1) | ||||
| throw new ArgumentException("Custom Id must be 1 character or more!", paramName: nameof(CustomId)); | throw new ArgumentException("Custom Id must be 1 character or more!", paramName: nameof(CustomId)); | ||||
| } | } | ||||
| else | |||||
| throw new ArgumentException("Custom Id must not be null or empty!", paramName: nameof(CustomId)); | |||||
| _customId = value; | _customId = value; | ||||
| } | } | ||||
| } | } | ||||
| @@ -667,8 +661,6 @@ namespace Discord | |||||
| if (value.Length < 1) | if (value.Length < 1) | ||||
| throw new ArgumentException("The placeholder must be 1 character or more!", paramName: nameof(Placeholder)); | throw new ArgumentException("The placeholder must be 1 character or more!", paramName: nameof(Placeholder)); | ||||
| } | } | ||||
| else | |||||
| throw new ArgumentException("The placeholder must not be null or empty!", paramName: nameof(Placeholder)); | |||||
| _placeholder = value; | _placeholder = value; | ||||
| } | } | ||||
| @@ -938,8 +930,6 @@ namespace Discord | |||||
| if (value.Length < 1) | if (value.Length < 1) | ||||
| throw new ArgumentException("Select option label must be 1 character or more!", paramName: nameof(Label)); | throw new ArgumentException("Select option label must be 1 character or more!", paramName: nameof(Label)); | ||||
| } | } | ||||
| else | |||||
| throw new ArgumentException("Select option label must not be null or empty!", paramName: nameof(Label)); | |||||
| _label = value; | _label = value; | ||||
| } | } | ||||
| @@ -973,7 +963,7 @@ namespace Discord | |||||
| /// Gets or sets this menu options description. | /// Gets or sets this menu options description. | ||||
| /// </summary> | /// </summary> | ||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Description"/> length exceeds <see cref="MaxDescriptionLength"/>.</exception> | /// <exception cref="ArgumentException" accessor="set"><see cref="Description"/> length exceeds <see cref="MaxDescriptionLength"/>.</exception> | ||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length subceeds 1.</exception> | |||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Description"/> length subceeds 1.</exception> | |||||
| public string Description | public string Description | ||||
| { | { | ||||
| get => _description; | get => _description; | ||||
| @@ -986,8 +976,6 @@ namespace Discord | |||||
| if (value.Length < 1) | if (value.Length < 1) | ||||
| throw new ArgumentException("The description must be 1 character or more!", paramName: nameof(Label)); | throw new ArgumentException("The description must be 1 character or more!", paramName: nameof(Label)); | ||||
| } | } | ||||
| else | |||||
| throw new ArgumentException("The description must not be null or empty!", paramName: nameof(Label)); | |||||
| _description = value; | _description = value; | ||||
| } | } | ||||
| @@ -87,9 +87,9 @@ namespace Discord | |||||
| /// A task that represents an asynchronous send operation for delivering the message. The task result | /// A task that represents an asynchronous send operation for delivering the message. The task result | ||||
| /// contains the sent message. | /// contains the sent message. | ||||
| /// </returns> | /// </returns> | ||||
| public static async Task<IUserMessage> ReplyAsync(this IUserMessage msg, string text = null, bool isTTS = false, Embed embed = null, AllowedMentions allowedMentions = null, RequestOptions options = null) | |||||
| public static async Task<IUserMessage> ReplyAsync(this IUserMessage msg, string text = null, bool isTTS = false, Embed embed = null, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, ISticker[] stickers = null) | |||||
| { | { | ||||
| return await msg.Channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, new MessageReference(messageId: msg.Id)).ConfigureAwait(false); | |||||
| return await msg.Channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, new MessageReference(messageId: msg.Id), components, stickers).ConfigureAwait(false); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,7 +4,7 @@ namespace Discord | |||||
| { | { | ||||
| internal static class Preconditions | internal static class Preconditions | ||||
| { | { | ||||
| //Objects | |||||
| #region Objects | |||||
| /// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | /// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | ||||
| public static void NotNull<T>(T obj, string name, string msg = null) where T : class { if (obj == null) throw CreateNotNullException(name, msg); } | public static void NotNull<T>(T obj, string name, string msg = null) where T : class { if (obj == null) throw CreateNotNullException(name, msg); } | ||||
| /// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | /// <exception cref="ArgumentNullException"><paramref name="obj"/> must not be <see langword="null"/>.</exception> | ||||
| @@ -15,8 +15,9 @@ namespace Discord | |||||
| if (msg == null) return new ArgumentNullException(paramName: name); | if (msg == null) return new ArgumentNullException(paramName: name); | ||||
| else return new ArgumentNullException(paramName: name, message: msg); | else return new ArgumentNullException(paramName: name, message: msg); | ||||
| } | } | ||||
| #endregion | |||||
| //Strings | |||||
| #region Strings | |||||
| /// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | /// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | ||||
| public static void NotEmpty(string obj, string name, string msg = null) { if (obj.Length == 0) throw CreateNotEmptyException(name, msg); } | public static void NotEmpty(string obj, string name, string msg = null) { if (obj.Length == 0) throw CreateNotEmptyException(name, msg); } | ||||
| /// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | /// <exception cref="ArgumentException"><paramref name="obj"/> cannot be blank.</exception> | ||||
| @@ -58,8 +59,9 @@ namespace Discord | |||||
| private static ArgumentException CreateNotEmptyException(string name, string msg) | private static ArgumentException CreateNotEmptyException(string name, string msg) | ||||
| => new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | => new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | ||||
| #endregion | |||||
| //Numerics | |||||
| #region Numerics | |||||
| /// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | ||||
| public static void NotEqual(sbyte obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); } | public static void NotEqual(sbyte obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); } | ||||
| /// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | /// <exception cref="ArgumentException">Value may not be equal to <paramref name="value"/>.</exception> | ||||
| @@ -271,8 +273,9 @@ namespace Discord | |||||
| private static ArgumentException CreateLessThanException<T>(string name, string msg, T value) | private static ArgumentException CreateLessThanException<T>(string name, string msg, T value) | ||||
| => new ArgumentException(message: msg ?? $"Value must be less than {value}.", paramName: name); | => new ArgumentException(message: msg ?? $"Value must be less than {value}.", paramName: name); | ||||
| #endregion | |||||
| // Bulk Delete | |||||
| #region Bulk Delete | |||||
| /// <exception cref="ArgumentOutOfRangeException">Messages are younger than 2 weeks.</exception> | /// <exception cref="ArgumentOutOfRangeException">Messages are younger than 2 weeks.</exception> | ||||
| public static void YoungerThanTwoWeeks(ulong[] collection, string name) | public static void YoungerThanTwoWeeks(ulong[] collection, string name) | ||||
| { | { | ||||
| @@ -293,5 +296,6 @@ namespace Discord | |||||
| throw new ArgumentException(message: "The everyone role cannot be assigned to a user.", paramName: name); | throw new ArgumentException(message: "The everyone role cannot be assigned to a user.", paramName: name); | ||||
| } | } | ||||
| } | } | ||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,7 @@ namespace Discord.Rest | |||||
| { | { | ||||
| internal static class ChannelHelper | internal static class ChannelHelper | ||||
| { | { | ||||
| //General | |||||
| #region General | |||||
| public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, | public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, | ||||
| RequestOptions options) | RequestOptions options) | ||||
| { | { | ||||
| @@ -107,8 +107,9 @@ namespace Discord.Rest | |||||
| return await client.ApiClient.ModifyStageInstanceAsync(channel.Id, apiArgs, options); | return await client.ApiClient.ModifyStageInstanceAsync(channel.Id, apiArgs, options); | ||||
| } | } | ||||
| #endregion | |||||
| //Invites | |||||
| #region Invites | |||||
| public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
| RequestOptions options) | RequestOptions options) | ||||
| { | { | ||||
| @@ -183,8 +184,9 @@ namespace Discord.Rest | |||||
| var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
| return RestInviteMetadata.Create(client, null, channel, model); | return RestInviteMetadata.Create(client, null, channel, model); | ||||
| } | } | ||||
| #endregion | |||||
| //Messages | |||||
| #region Messages | |||||
| public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, | public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, | ||||
| ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
| { | { | ||||
| @@ -285,12 +287,12 @@ namespace Discord.Rest | |||||
| } | } | ||||
| } | } | ||||
| if(stickers != null) | |||||
| if (stickers != null) | |||||
| { | { | ||||
| Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | ||||
| } | } | ||||
| var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel(), Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional<ulong[]>.Unspecified}; | |||||
| var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel(), Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional<ulong[]>.Unspecified }; | |||||
| var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
| return RestUserMessage.Create(client, channel, client.CurrentUser, model); | return RestUserMessage.Create(client, channel, client.CurrentUser, model); | ||||
| } | } | ||||
| @@ -397,8 +399,9 @@ namespace Discord.Rest | |||||
| await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false); | await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
| } | } | ||||
| } | } | ||||
| #endregion | |||||
| //Permission Overwrites | |||||
| #region Permission Overwrites | |||||
| public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
| IUser user, OverwritePermissions perms, RequestOptions options) | IUser user, OverwritePermissions perms, RequestOptions options) | ||||
| { | { | ||||
| @@ -421,8 +424,9 @@ namespace Discord.Rest | |||||
| { | { | ||||
| await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id, options).ConfigureAwait(false); | await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id, options).ConfigureAwait(false); | ||||
| } | } | ||||
| #endregion | |||||
| //Users | |||||
| #region Users | |||||
| /// <exception cref="InvalidOperationException">Resolving permissions requires the parent guild to be downloaded.</exception> | /// <exception cref="InvalidOperationException">Resolving permissions requires the parent guild to be downloaded.</exception> | ||||
| public static async Task<RestGuildUser> GetUserAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client, | public static async Task<RestGuildUser> GetUserAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client, | ||||
| ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
| @@ -467,8 +471,9 @@ namespace Discord.Rest | |||||
| count: limit | count: limit | ||||
| ); | ); | ||||
| } | } | ||||
| #endregion | |||||
| //Typing | |||||
| #region Typing | |||||
| public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscordClient client, | public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscordClient client, | ||||
| RequestOptions options = null) | RequestOptions options = null) | ||||
| { | { | ||||
| @@ -477,8 +482,9 @@ namespace Discord.Rest | |||||
| public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, | public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, | ||||
| RequestOptions options) | RequestOptions options) | ||||
| => new TypingNotifier(channel, options); | => new TypingNotifier(channel, options); | ||||
| #endregion | |||||
| //Webhooks | |||||
| #region Webhooks | |||||
| public static async Task<RestWebhook> CreateWebhookAsync(ITextChannel channel, BaseDiscordClient client, string name, Stream avatar, RequestOptions options) | public static async Task<RestWebhook> CreateWebhookAsync(ITextChannel channel, BaseDiscordClient client, string name, Stream avatar, RequestOptions options) | ||||
| { | { | ||||
| var args = new CreateWebhookParams { Name = name }; | var args = new CreateWebhookParams { Name = name }; | ||||
| @@ -501,7 +507,9 @@ namespace Discord.Rest | |||||
| return models.Select(x => RestWebhook.Create(client, channel, x)) | return models.Select(x => RestWebhook.Create(client, channel, x)) | ||||
| .ToImmutableArray(); | .ToImmutableArray(); | ||||
| } | } | ||||
| // Categories | |||||
| #endregion | |||||
| #region Categories | |||||
| public static async Task<ICategoryChannel> GetCategoryAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | public static async Task<ICategoryChannel> GetCategoryAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | ||||
| { | { | ||||
| // if no category id specified, return null | // if no category id specified, return null | ||||
| @@ -515,7 +523,8 @@ namespace Discord.Rest | |||||
| public static async Task SyncPermissionsAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | public static async Task SyncPermissionsAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) | ||||
| { | { | ||||
| var category = await GetCategoryAsync(channel, client, options).ConfigureAwait(false); | var category = await GetCategoryAsync(channel, client, options).ConfigureAwait(false); | ||||
| if (category == null) throw new InvalidOperationException("This channel does not have a parent channel."); | |||||
| if (category == null) | |||||
| throw new InvalidOperationException("This channel does not have a parent channel."); | |||||
| var apiArgs = new ModifyGuildChannelParams | var apiArgs = new ModifyGuildChannelParams | ||||
| { | { | ||||
| @@ -530,5 +539,6 @@ namespace Discord.Rest | |||||
| }; | }; | ||||
| await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
| } | } | ||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -15,6 +15,7 @@ namespace Discord.Rest | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel | public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel | ||||
| { | { | ||||
| #region RestDMChannel | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets the current logged-in user. | /// Gets the current logged-in user. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -154,20 +155,24 @@ namespace Discord.Rest | |||||
| /// </returns> | /// </returns> | ||||
| public override string ToString() => $"@{Recipient}"; | public override string ToString() => $"@{Recipient}"; | ||||
| private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; | private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; | ||||
| #endregion | |||||
| //IDMChannel | |||||
| #region IDMChannel | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IUser IDMChannel.Recipient => Recipient; | IUser IDMChannel.Recipient => Recipient; | ||||
| #endregion | |||||
| //IRestPrivateChannel | |||||
| #region IRestPrivateChannel | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => ImmutableArray.Create(Recipient); | IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => ImmutableArray.Create(Recipient); | ||||
| #endregion | |||||
| //IPrivateChannel | |||||
| #region IPrivateChannel | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create<IUser>(Recipient); | IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create<IUser>(Recipient); | ||||
| #endregion | |||||
| //IMessageChannel | |||||
| #region IMessageChannel | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| { | { | ||||
| @@ -212,8 +217,9 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | ||||
| => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | ||||
| #endregion | |||||
| //IChannel | |||||
| #region IChannel | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| string IChannel.Name => $"@{Recipient}"; | string IChannel.Name => $"@{Recipient}"; | ||||
| @@ -223,5 +229,6 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | ||||
| => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | ||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -16,6 +16,7 @@ namespace Discord.Rest | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel | public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel | ||||
| { | { | ||||
| #region RestGroupChannel | |||||
| private string _iconId; | private string _iconId; | ||||
| private ImmutableDictionary<ulong, RestGroupUser> _users; | private ImmutableDictionary<ulong, RestGroupUser> _users; | ||||
| @@ -143,14 +144,17 @@ namespace Discord.Rest | |||||
| public override string ToString() => Name; | public override string ToString() => Name; | ||||
| private string DebuggerDisplay => $"{Name} ({Id}, Group)"; | private string DebuggerDisplay => $"{Name} ({Id}, Group)"; | ||||
| #endregion | |||||
| //ISocketPrivateChannel | |||||
| #region ISocketPrivateChannel | |||||
| IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => Recipients; | IReadOnlyCollection<RestUser> IRestPrivateChannel.Recipients => Recipients; | ||||
| #endregion | |||||
| //IPrivateChannel | |||||
| #region IPrivateChannel | |||||
| IReadOnlyCollection<IUser> IPrivateChannel.Recipients => Recipients; | IReadOnlyCollection<IUser> IPrivateChannel.Recipients => Recipients; | ||||
| #endregion | |||||
| //IMessageChannel | |||||
| #region IMessageChannel | |||||
| async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| { | { | ||||
| if (mode == CacheMode.AllowDownload) | if (mode == CacheMode.AllowDownload) | ||||
| @@ -190,17 +194,20 @@ namespace Discord.Rest | |||||
| async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) | ||||
| => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); | ||||
| #endregion | |||||
| //IAudioChannel | |||||
| #region IAudioChannel | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| /// <exception cref="NotSupportedException">Connecting to a group channel is not supported.</exception> | /// <exception cref="NotSupportedException">Connecting to a group channel is not supported.</exception> | ||||
| Task<IAudioClient> IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } | Task<IAudioClient> IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } | ||||
| Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } | Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } | ||||
| #endregion | |||||
| //IChannel | |||||
| #region IChannel | |||||
| Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<IUser>(GetUser(id)); | => Task.FromResult<IUser>(GetUser(id)); | ||||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | ||||
| => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); | ||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,6 +9,7 @@ namespace Discord.Rest | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public class RestBan : IBan | public class RestBan : IBan | ||||
| { | { | ||||
| #region RestBan | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets the banned user. | /// Gets the banned user. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -37,9 +38,11 @@ namespace Discord.Rest | |||||
| /// </returns> | /// </returns> | ||||
| public override string ToString() => User.ToString(); | public override string ToString() => User.ToString(); | ||||
| private string DebuggerDisplay => $"{User}: {Reason}"; | private string DebuggerDisplay => $"{User}: {Reason}"; | ||||
| #endregion | |||||
| //IBan | |||||
| #region IBan | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| IUser IBan.User => User; | IUser IBan.User => User; | ||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -340,9 +340,10 @@ namespace Discord.Rest | |||||
| var embeds = args.Embeds; | var embeds = args.Embeds; | ||||
| bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(message.Content); | bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(message.Content); | ||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || message.Embeds.Any(); | |||||
| bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0 || message.Embeds.Any(); | |||||
| bool hasComponents = args.Components.IsSpecified && args.Components.Value != null; | |||||
| if (!hasText && !hasEmbeds) | |||||
| if (!hasComponents && !hasText && !hasEmbeds) | |||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | ||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | ||||
| @@ -383,9 +384,10 @@ namespace Discord.Rest | |||||
| var embeds = args.Embeds; | var embeds = args.Embeds; | ||||
| bool hasText = !string.IsNullOrEmpty(args.Content.GetValueOrDefault()); | bool hasText = !string.IsNullOrEmpty(args.Content.GetValueOrDefault()); | ||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0); | |||||
| bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0; | |||||
| bool hasComponents = args.Components.IsSpecified && args.Components.Value != null; | |||||
| if (!hasText && !hasEmbeds) | |||||
| if (!hasComponents && !hasText && !hasEmbeds) | |||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | ||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | ||||
| @@ -38,7 +38,7 @@ namespace Discord.Rest | |||||
| var embeds = args.Embeds; | var embeds = args.Embeds; | ||||
| bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(msg.Content); | bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(msg.Content); | ||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || msg.Embeds.Any(); | |||||
| bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0 || msg.Embeds.Any(); | |||||
| if (!hasText && !hasEmbeds) | if (!hasText && !hasEmbeds) | ||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | ||||
| @@ -101,9 +101,10 @@ namespace Discord.Rest | |||||
| var embeds = args.Embeds; | var embeds = args.Embeds; | ||||
| bool hasText = args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value); | bool hasText = args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value); | ||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0); | |||||
| bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0; | |||||
| bool hasComponents = args.Components.IsSpecified && args.Components.Value != null; | |||||
| if (!hasText && !hasEmbeds) | |||||
| if (!hasComponents && !hasText && !hasEmbeds) | |||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | ||||
| if (args.AllowedMentions.IsSpecified) | if (args.AllowedMentions.IsSpecified) | ||||
| @@ -10,6 +10,7 @@ namespace Discord.Rest | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public class RestGroupUser : RestUser, IGroupUser | public class RestGroupUser : RestUser, IGroupUser | ||||
| { | { | ||||
| #region RestGroupUser | |||||
| internal RestGroupUser(BaseDiscordClient discord, ulong id) | internal RestGroupUser(BaseDiscordClient discord, ulong id) | ||||
| : base(discord, id) | : base(discord, id) | ||||
| { | { | ||||
| @@ -20,8 +21,9 @@ namespace Discord.Rest | |||||
| entity.Update(model); | entity.Update(model); | ||||
| return entity; | return entity; | ||||
| } | } | ||||
| #endregion | |||||
| //IVoiceState | |||||
| #region IVoiceState | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| bool IVoiceState.IsDeafened => false; | bool IVoiceState.IsDeafened => false; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -40,5 +42,6 @@ namespace Discord.Rest | |||||
| bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | ||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -24,6 +24,7 @@ namespace Discord.WebSocket | |||||
| /// </summary> | /// </summary> | ||||
| public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient | public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient | ||||
| { | { | ||||
| #region DiscordSocketClient | |||||
| private readonly ConcurrentQueue<ulong> _largeGuilds; | private readonly ConcurrentQueue<ulong> _largeGuilds; | ||||
| internal readonly JsonSerializer _serializer; | internal readonly JsonSerializer _serializer; | ||||
| private readonly DiscordShardedClient _shardedClient; | private readonly DiscordShardedClient _shardedClient; | ||||
| @@ -62,6 +63,7 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override IActivity Activity { get => _activity.GetValueOrDefault(); protected set => _activity = Optional.Create(value); } | public override IActivity Activity { get => _activity.GetValueOrDefault(); protected set => _activity = Optional.Create(value); } | ||||
| private Optional<IActivity> _activity; | private Optional<IActivity> _activity; | ||||
| #endregion | |||||
| //From DiscordSocketConfig | //From DiscordSocketConfig | ||||
| internal int TotalShards { get; private set; } | internal int TotalShards { get; private set; } | ||||
| @@ -436,7 +438,7 @@ namespace Discord.WebSocket | |||||
| var entity = State.GetOrAddCommand(model.Id, (id) => SocketApplicationCommand.Create(this, model)); | var entity = State.GetOrAddCommand(model.Id, (id) => SocketApplicationCommand.Create(this, model)); | ||||
| // update it incase it was cached | |||||
| //Update it incase it was cached | |||||
| entity.Update(model); | entity.Update(model); | ||||
| return entity; | return entity; | ||||
| @@ -448,7 +450,7 @@ namespace Discord.WebSocket | |||||
| var entities = models.Select(x => SocketApplicationCommand.Create(this, x)); | var entities = models.Select(x => SocketApplicationCommand.Create(this, x)); | ||||
| // purge our previous commands | |||||
| //Purge our previous commands | |||||
| State.PurgeCommands(x => x.IsGlobalCommand); | State.PurgeCommands(x => x.IsGlobalCommand); | ||||
| foreach(var entity in entities) | foreach(var entity in entities) | ||||
| @@ -513,7 +515,7 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| var guild = State.GetGuild(model.GuildId.Value); | var guild = State.GetGuild(model.GuildId.Value); | ||||
| // since the sticker can be from another guild, check if we are in the guild or its in the cache | |||||
| //Since the sticker can be from another guild, check if we are in the guild or its in the cache | |||||
| if (guild != null) | if (guild != null) | ||||
| sticker = guild.AddOrUpdateSticker(model); | sticker = guild.AddOrUpdateSticker(model); | ||||
| else | else | ||||
| @@ -678,7 +680,7 @@ namespace Discord.WebSocket | |||||
| return null; | return null; | ||||
| GameModel game = null; | GameModel game = null; | ||||
| // Discord only accepts rich presence over RPC, don't even bother building a payload | |||||
| //Discord only accepts rich presence over RPC, don't even bother building a payload | |||||
| if (activity.GetValueOrDefault() != null) | if (activity.GetValueOrDefault() != null) | ||||
| { | { | ||||
| @@ -700,6 +702,7 @@ namespace Discord.WebSocket | |||||
| game); | game); | ||||
| } | } | ||||
| #region ProcessMessageAsync | |||||
| private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload) | private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload) | ||||
| { | { | ||||
| if (seq != null) | if (seq != null) | ||||
| @@ -772,7 +775,7 @@ namespace Discord.WebSocket | |||||
| case GatewayOpCode.Dispatch: | case GatewayOpCode.Dispatch: | ||||
| switch (type) | switch (type) | ||||
| { | { | ||||
| //Connection | |||||
| #region Connection | |||||
| case "READY": | case "READY": | ||||
| { | { | ||||
| try | try | ||||
| @@ -849,8 +852,9 @@ namespace Discord.WebSocket | |||||
| await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false); | await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false); | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Guilds | |||||
| #region Guilds | |||||
| case "GUILD_CREATE": | case "GUILD_CREATE": | ||||
| { | { | ||||
| var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer); | var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer); | ||||
| @@ -1000,8 +1004,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Channels | |||||
| #region Channels | |||||
| case "CHANNEL_CREATE": | case "CHANNEL_CREATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | ||||
| @@ -1103,8 +1108,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Members | |||||
| #region Members | |||||
| case "GUILD_MEMBER_ADD": | case "GUILD_MEMBER_ADD": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false); | ||||
| @@ -1275,8 +1281,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Roles | |||||
| #region Roles | |||||
| case "GUILD_ROLE_CREATE": | case "GUILD_ROLE_CREATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false); | ||||
| @@ -1368,8 +1375,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Bans | |||||
| #region Bans | |||||
| case "GUILD_BAN_ADD": | case "GUILD_BAN_ADD": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false); | ||||
| @@ -1422,8 +1430,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Messages | |||||
| #region Messages | |||||
| case "MESSAGE_CREATE": | case "MESSAGE_CREATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | ||||
| @@ -1754,8 +1763,9 @@ namespace Discord.WebSocket | |||||
| await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false); | await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false); | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Statuses | |||||
| #region Statuses | |||||
| case "PRESENCE_UPDATE": | case "PRESENCE_UPDATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false); | ||||
| @@ -1843,8 +1853,9 @@ namespace Discord.WebSocket | |||||
| await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false); | await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false); | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Users | |||||
| #region Users | |||||
| case "USER_UPDATE": | case "USER_UPDATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); | ||||
| @@ -1863,8 +1874,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Voice | |||||
| #region Voice | |||||
| case "VOICE_STATE_UPDATE": | case "VOICE_STATE_UPDATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | ||||
| @@ -1901,7 +1913,7 @@ namespace Discord.WebSocket | |||||
| after = SocketVoiceState.Create(null, data); | after = SocketVoiceState.Create(null, data); | ||||
| } | } | ||||
| // per g250k, this should always be sent, but apparently not always | |||||
| //Per g250k, this should always be sent, but apparently not always | |||||
| user = guild.GetUser(data.UserId) | user = guild.GetUser(data.UserId) | ||||
| ?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null); | ?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null); | ||||
| if (user == null) | if (user == null) | ||||
| @@ -1993,8 +2005,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Invites | |||||
| #region Invites | |||||
| case "INVITE_CREATE": | case "INVITE_CREATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false); | ||||
| @@ -2051,8 +2064,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| // Interactions | |||||
| #region Interactions | |||||
| case "INTERACTION_CREATE": | case "INTERACTION_CREATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); | ||||
| @@ -2189,8 +2203,9 @@ namespace Discord.WebSocket | |||||
| await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false); | await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false); | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| // Threads | |||||
| #region Threads | |||||
| case "THREAD_CREATE": | case "THREAD_CREATE": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false); | ||||
| @@ -2251,7 +2266,7 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // Thread is updated but was not cached, likely meaning the thread was unarchived. | |||||
| //Thread is updated but was not cached, likely meaning the thread was unarchived. | |||||
| threadChannel = (SocketThreadChannel)guild.AddChannel(State, data); | threadChannel = (SocketThreadChannel)guild.AddChannel(State, data); | ||||
| if (data.ThreadMember.IsSpecified) | if (data.ThreadMember.IsSpecified) | ||||
| threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); | threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); | ||||
| @@ -2507,8 +2522,9 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #endregion | |||||
| //Ignored (User only) | |||||
| #region Ignored (User only) | |||||
| case "CHANNEL_PINS_ACK": | case "CHANNEL_PINS_ACK": | ||||
| await _gatewayLogger.DebugAsync("Ignored Dispatch (CHANNEL_PINS_ACK)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored Dispatch (CHANNEL_PINS_ACK)").ConfigureAwait(false); | ||||
| break; | break; | ||||
| @@ -2530,11 +2546,13 @@ namespace Discord.WebSocket | |||||
| case "WEBHOOKS_UPDATE": | case "WEBHOOKS_UPDATE": | ||||
| await _gatewayLogger.DebugAsync("Ignored Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false); | ||||
| break; | break; | ||||
| #endregion | |||||
| //Others | |||||
| #region Others | |||||
| default: | default: | ||||
| await _gatewayLogger.WarningAsync($"Unknown Dispatch ({type})").ConfigureAwait(false); | await _gatewayLogger.WarningAsync($"Unknown Dispatch ({type})").ConfigureAwait(false); | ||||
| break; | break; | ||||
| #endregion | |||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -2548,6 +2566,7 @@ namespace Discord.WebSocket | |||||
| Console.WriteLine(ex); | Console.WriteLine(ex); | ||||
| } | } | ||||
| } | } | ||||
| #endregion | |||||
| private async Task RunHeartbeatAsync(int intervalMillis, CancellationToken cancelToken) | private async Task RunHeartbeatAsync(int intervalMillis, CancellationToken cancelToken) | ||||
| { | { | ||||
| @@ -150,7 +150,7 @@ namespace Discord.WebSocket | |||||
| var embeds = args.Embeds; | var embeds = args.Embeds; | ||||
| bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(Message.Content); | bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(Message.Content); | ||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || Message.Embeds.Any(); | |||||
| bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0 || Message.Embeds.Any(); | |||||
| if (!hasText && !hasEmbeds) | if (!hasText && !hasEmbeds) | ||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | ||||
| @@ -9,7 +9,7 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| public static IActivity ToEntity(this API.Game model) | public static IActivity ToEntity(this API.Game model) | ||||
| { | { | ||||
| // Custom Status Game | |||||
| #region Custom Status Game | |||||
| if (model.Id.IsSpecified && model.Id.Value == "custom") | if (model.Id.IsSpecified && model.Id.Value == "custom") | ||||
| { | { | ||||
| return new CustomStatusGame() | return new CustomStatusGame() | ||||
| @@ -21,13 +21,14 @@ namespace Discord.WebSocket | |||||
| CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(model.CreatedAt.Value), | CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(model.CreatedAt.Value), | ||||
| }; | }; | ||||
| } | } | ||||
| #endregion | |||||
| // Spotify Game | |||||
| #region Spotify Game | |||||
| if (model.SyncId.IsSpecified) | if (model.SyncId.IsSpecified) | ||||
| { | { | ||||
| var assets = model.Assets.GetValueOrDefault()?.ToEntity(); | var assets = model.Assets.GetValueOrDefault()?.ToEntity(); | ||||
| string albumText = assets?[1]?.Text; | string albumText = assets?[1]?.Text; | ||||
| string albumArtId = assets?[1]?.ImageId?.Replace("spotify:",""); | |||||
| string albumArtId = assets?[1]?.ImageId?.Replace("spotify:", ""); | |||||
| var timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null; | var timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null; | ||||
| return new SpotifyGame | return new SpotifyGame | ||||
| { | { | ||||
| @@ -37,7 +38,7 @@ namespace Discord.WebSocket | |||||
| TrackUrl = CDN.GetSpotifyDirectUrl(model.SyncId.Value), | TrackUrl = CDN.GetSpotifyDirectUrl(model.SyncId.Value), | ||||
| AlbumTitle = albumText, | AlbumTitle = albumText, | ||||
| TrackTitle = model.Details.GetValueOrDefault(), | TrackTitle = model.Details.GetValueOrDefault(), | ||||
| Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), | |||||
| Artists = model.State.GetValueOrDefault()?.Split(';').Select(x => x?.Trim()).ToImmutableArray(), | |||||
| StartedAt = timestamps?.Start, | StartedAt = timestamps?.Start, | ||||
| EndsAt = timestamps?.End, | EndsAt = timestamps?.End, | ||||
| Duration = timestamps?.End - timestamps?.Start, | Duration = timestamps?.End - timestamps?.Start, | ||||
| @@ -46,8 +47,9 @@ namespace Discord.WebSocket | |||||
| Flags = model.Flags.GetValueOrDefault(), | Flags = model.Flags.GetValueOrDefault(), | ||||
| }; | }; | ||||
| } | } | ||||
| #endregion | |||||
| // Rich Game | |||||
| #region Rich Game | |||||
| if (model.ApplicationId.IsSpecified) | if (model.ApplicationId.IsSpecified) | ||||
| { | { | ||||
| ulong appId = model.ApplicationId.Value; | ulong appId = model.ApplicationId.Value; | ||||
| @@ -66,7 +68,9 @@ namespace Discord.WebSocket | |||||
| Flags = model.Flags.GetValueOrDefault() | Flags = model.Flags.GetValueOrDefault() | ||||
| }; | }; | ||||
| } | } | ||||
| // Stream Game | |||||
| #endregion | |||||
| #region Stream Game | |||||
| if (model.StreamUrl.IsSpecified) | if (model.StreamUrl.IsSpecified) | ||||
| { | { | ||||
| return new StreamingGame( | return new StreamingGame( | ||||
| @@ -77,10 +81,13 @@ namespace Discord.WebSocket | |||||
| Details = model.Details.GetValueOrDefault() | Details = model.Details.GetValueOrDefault() | ||||
| }; | }; | ||||
| } | } | ||||
| // Normal Game | |||||
| #endregion | |||||
| #region Normal Game | |||||
| return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, | return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, | ||||
| model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, | model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, | ||||
| model.Details.GetValueOrDefault()); | model.Details.GetValueOrDefault()); | ||||
| #endregion | |||||
| } | } | ||||
| // (Small, Large) | // (Small, Large) | ||||