| @@ -46,14 +46,16 @@ form; this can be obtained in several different ways. | |||||
| ### Emoji Declaration | ### Emoji Declaration | ||||
| After obtaining the Unicode representation of the emoji, you may | After obtaining the Unicode representation of the emoji, you may | ||||
| create the @Discord.Emoji object by passing the string into its | |||||
| create the @Discord.Emoji object by passing the string with unicode into its | |||||
| constructor (e.g. `new Emoji("👌");` or `new Emoji("\uD83D\uDC4C");`). | constructor (e.g. `new Emoji("👌");` or `new Emoji("\uD83D\uDC4C");`). | ||||
| Your method of declaring an @Discord.Emoji should look similar to | Your method of declaring an @Discord.Emoji should look similar to | ||||
| this: | this: | ||||
| [!code-csharp[Emoji Sample](samples/emoji-sample.cs)] | [!code-csharp[Emoji Sample](samples/emoji-sample.cs)] | ||||
| Also you can use `Emoji.Parse()` or `Emoji.TryParse()` methods | |||||
| for parsing emojis from strings like `:heart:`, `<3` or `❤`. | |||||
| [FileFormat.Info]: https://www.fileformat.info/info/emoji/list.htm | [FileFormat.Info]: https://www.fileformat.info/info/emoji/list.htm | ||||
| ## Emote | ## Emote | ||||
| @@ -97,4 +99,4 @@ this: | |||||
| ## Additional Information | ## Additional Information | ||||
| To learn more about emote and emojis and how they could be used, | To learn more about emote and emojis and how they could be used, | ||||
| see the documentation of @Discord.IEmote. | |||||
| see the documentation of @Discord.IEmote. | |||||
| @@ -45,6 +45,6 @@ Let's try this out! | |||||
| Let's go over the response types quickly, as you would only change them for style points :P | Let's go over the response types quickly, as you would only change them for style points :P | ||||
| > After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `ChannelMessageWithSource` or you can choose to send a deferred response with `DeferredChannelMessageWithSource`. If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using Edit Original Interaction Response. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response) | |||||
| > After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `RespondAsync()` or you can choose to send a deferred response with `DeferAsync()`. If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using `ModifyOriginalResponseAsync()`. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response) | |||||
| This seems to be working! Next, we will look at parameters for slash commands. | This seems to be working! Next, we will look at parameters for slash commands. | ||||
| @@ -46,6 +46,24 @@ namespace Discord | |||||
| string extension = FormatToExtension(format, avatarId); | string extension = FormatToExtension(format, avatarId); | ||||
| return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}"; | return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}"; | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Returns a user banner URL. | |||||
| /// </summary> | |||||
| /// <param name="userId">The user snowflake identifier.</param> | |||||
| /// <param name="bannerId">The banner identifier.</param> | |||||
| /// <param name="size">The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048.</param> | |||||
| /// <param name="format">The format to return.</param> | |||||
| /// <returns> | |||||
| /// A URL pointing to the user's banner in the specified size. | |||||
| /// </returns> | |||||
| public static string GetUserBannerUrl(ulong userId, string bannerId, ushort size, ImageFormat format) | |||||
| { | |||||
| if (bannerId == null) | |||||
| return null; | |||||
| string extension = FormatToExtension(format, bannerId); | |||||
| return $"{DiscordConfig.CDNUrl}banners/{userId}/{bannerId}.{extension}?size={size}"; | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// Returns the default user avatar URL. | /// Returns the default user avatar URL. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -8,12 +8,12 @@ | |||||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks> | <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks> | ||||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | ||||
| <PackageId>Discord.Net.Labs.Core</PackageId> | <PackageId>Discord.Net.Labs.Core</PackageId> | ||||
| <Version>2.4.6</Version> | |||||
| <Version>3.0.1-pre</Version> | |||||
| <Product>Discord.Net.Labs.Core</Product> | <Product>Discord.Net.Labs.Core</Product> | ||||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | ||||
| <PackageIcon>Temporary.png</PackageIcon> | <PackageIcon>Temporary.png</PackageIcon> | ||||
| <AssemblyVersion>2.3.8</AssemblyVersion> | |||||
| <FileVersion>2.3.8</FileVersion> | |||||
| <AssemblyVersion>3.3.1</AssemblyVersion> | |||||
| <FileVersion>3.0.1</FileVersion> | |||||
| <GeneratePackageOnBuild>false</GeneratePackageOnBuild> | <GeneratePackageOnBuild>false</GeneratePackageOnBuild> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup> | <PropertyGroup> | ||||
| @@ -100,6 +100,18 @@ | |||||
| A URL pointing to the user's avatar in the specified size. | A URL pointing to the user's avatar in the specified size. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.CDN.GetUserBannerUrl(System.UInt64,System.String,System.UInt16,Discord.ImageFormat)"> | |||||
| <summary> | |||||
| Returns a user banner URL. | |||||
| </summary> | |||||
| <param name="userId">The user snowflake identifier.</param> | |||||
| <param name="bannerId">The banner identifier.</param> | |||||
| <param name="size">The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048.</param> | |||||
| <param name="format">The format to return.</param> | |||||
| <returns> | |||||
| A URL pointing to the user's banner in the specified size. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.CDN.GetDefaultUserAvatarUrl(System.UInt16)"> | <member name="M:Discord.CDN.GetDefaultUserAvatarUrl(System.UInt16)"> | ||||
| <summary> | <summary> | ||||
| Returns the default user avatar URL. | Returns the default user avatar URL. | ||||
| @@ -1914,6 +1926,117 @@ | |||||
| A read-only collection of users that can access this channel. | A read-only collection of users that can access this channel. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="T:Discord.IStageChannel"> | |||||
| <summary> | |||||
| Represents a generic Stage Channel. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.IStageChannel.Topic"> | |||||
| <summary> | |||||
| Gets the topic of the Stage instance. | |||||
| </summary> | |||||
| <remarks> | |||||
| If the stage isn't live then this property will be set to <see langword="null"/>. | |||||
| </remarks> | |||||
| </member> | |||||
| <member name="P:Discord.IStageChannel.PrivacyLevel"> | |||||
| <summary> | |||||
| The <see cref="T:Discord.StagePrivacyLevel"/> of the current stage. | |||||
| </summary> | |||||
| <remarks> | |||||
| If the stage isn't live then this property will be set to <see langword="null"/>. | |||||
| </remarks> | |||||
| </member> | |||||
| <member name="P:Discord.IStageChannel.DiscoverableDisabled"> | |||||
| <summary> | |||||
| <see langword="true"/> if stage discovery is disabled, otherwise <see langword="false"/>. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.IStageChannel.Live"> | |||||
| <summary> | |||||
| <see langword="true"/> when the stage is live, otherwise <see langword="false"/>. | |||||
| </summary> | |||||
| <remarks> | |||||
| If the stage isn't live then this property will be set to <see langword="null"/>. | |||||
| </remarks> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.StartStageAsync(System.String,Discord.StagePrivacyLevel,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Starts the stage, creating a stage instance. | |||||
| </summary> | |||||
| <param name="topic">The topic for the stage/</param> | |||||
| <param name="privacyLevel">The privacy level of the stage</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous start operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.ModifyInstanceAsync(System.Action{Discord.StageInstanceProperties},Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Modifies the current stage instance. | |||||
| </summary> | |||||
| <param name="func">The properties to modify the stage instance with.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous modify operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.StopStageAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Stops the stage, deleting the stage instance. | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous stop operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.RequestToSpeak(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Indicates that the bot would like to speak within a stage channel. | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous request to speak operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.BecomeSpeakerAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Makes the current user become a speaker within a stage. | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous speaker modify operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.StopSpeakingAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Makes the current user a listener. | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous stop operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.MoveToSpeaker(Discord.IGuildUser,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Makes a user a speaker within a stage. | |||||
| </summary> | |||||
| <param name="user">The user to make the speaker.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous move operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IStageChannel.RemoveFromSpeaker(Discord.IGuildUser,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Removes a user from speaking. | |||||
| </summary> | |||||
| <param name="user">The user to remove from speaking.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous remove operation. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="T:Discord.ITextChannel"> | <member name="T:Discord.ITextChannel"> | ||||
| <summary> | <summary> | ||||
| Represents a generic channel in a guild that can send and receive messages. | Represents a generic channel in a guild that can send and receive messages. | ||||
| @@ -2202,6 +2325,21 @@ | |||||
| <param name="id"> Sets the ID of the channel to apply this position to. </param> | <param name="id"> Sets the ID of the channel to apply this position to. </param> | ||||
| <param name="position"> Sets the new zero-based position of this channel. </param> | <param name="position"> Sets the new zero-based position of this channel. </param> | ||||
| </member> | </member> | ||||
| <member name="T:Discord.StageInstanceProperties"> | |||||
| <summary> | |||||
| Represents properties to use when modifying a stage instance. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.StageInstanceProperties.Topic"> | |||||
| <summary> | |||||
| Gets or sets the topic of the stage. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.StageInstanceProperties.PrivacyLevel"> | |||||
| <summary> | |||||
| Gets or sets the privacy level of the stage. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="T:Discord.TextChannelProperties"> | <member name="T:Discord.TextChannelProperties"> | ||||
| <summary> | <summary> | ||||
| Provides properties that are used to modify an <see cref="T:Discord.ITextChannel"/> with the specified changes. | Provides properties that are used to modify an <see cref="T:Discord.ITextChannel"/> with the specified changes. | ||||
| @@ -3114,6 +3252,14 @@ | |||||
| language tag format. | language tag format. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.IGuild.NsfwLevel"> | |||||
| <summary> | |||||
| Gets the NSFW level of this guild. | |||||
| </summary> | |||||
| <returns> | |||||
| The NSFW level of this guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="P:Discord.IGuild.PreferredCulture"> | <member name="P:Discord.IGuild.PreferredCulture"> | ||||
| <summary> | <summary> | ||||
| Gets the preferred culture of this guild. | Gets the preferred culture of this guild. | ||||
| @@ -3336,6 +3482,29 @@ | |||||
| with the specified <paramref name="id"/>; <see langword="null" /> if none is found. | with the specified <paramref name="id"/>; <see langword="null" /> if none is found. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.IGuild.GetStageChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a stage channel in this guild | |||||
| </summary> | |||||
| <param name="id">The snowflake identifier for the stage channel.</param> | |||||
| <param name="mode">The <see cref="T:Discord.CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains the stage channel associated | |||||
| with the specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IGuild.GetStageChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a collection of all stage channels in this guild. | |||||
| </summary> | |||||
| <param name="mode">The <see cref="T:Discord.CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| stage channels found within this guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IGuild.GetAFKChannelAsync(Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.IGuild.GetAFKChannelAsync(Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <summary> | <summary> | ||||
| Gets the AFK voice channel in this guild. | Gets the AFK voice channel in this guild. | ||||
| @@ -3402,6 +3571,28 @@ | |||||
| admins and moderators of Community guilds receive notices from Discord; <see langword="null" /> if none is set. | admins and moderators of Community guilds receive notices from Discord; <see langword="null" /> if none is set. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.IGuild.GetThreadChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a thread channel within this guild. | |||||
| </summary> | |||||
| <param name="id">The id of the thread channel.</param> | |||||
| <param name="mode">The <see cref="T:Discord.CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains the thread channel. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IGuild.GetThreadChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a collection of all thread channels in this guild. | |||||
| </summary> | |||||
| <param name="mode">The <see cref="T:Discord.CacheMode" /> that determines whether the object should be fetched from cache.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| thread channels found within this guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IGuild.CreateTextChannelAsync(System.String,System.Action{Discord.TextChannelProperties},Discord.RequestOptions)"> | <member name="M:Discord.IGuild.CreateTextChannelAsync(System.String,System.Action{Discord.TextChannelProperties},Discord.RequestOptions)"> | ||||
| <summary> | <summary> | ||||
| Creates a new text channel in this guild. | Creates a new text channel in this guild. | ||||
| @@ -3723,6 +3914,16 @@ | |||||
| A task that represents the asynchronous removal operation. | A task that represents the asynchronous removal operation. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.IGuild.GetApplicationCommandsAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets this guilds slash commands commands | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains a read-only collection | |||||
| of application commands found within the guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="T:Discord.IGuildIntegration"> | <member name="T:Discord.IGuildIntegration"> | ||||
| <summary> | <summary> | ||||
| Holds information for a guild integration feature. | Holds information for a guild integration feature. | ||||
| @@ -3891,6 +4092,26 @@ | |||||
| Users must have MFA enabled on their account to perform administrative actions. | Users must have MFA enabled on their account to perform administrative actions. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.NsfwLevel.Default"> | |||||
| <summary> | |||||
| Default or unset. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.NsfwLevel.Explicit"> | |||||
| <summary> | |||||
| Guild has extremely suggestive or mature content that would only be suitable for users 18 or over. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.NsfwLevel.Safe"> | |||||
| <summary> | |||||
| Guild has no content that could be deemed NSFW; in other words, SFW. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.NsfwLevel.AgeRestricted"> | |||||
| <summary> | |||||
| Guild has mildly NSFW content that may not be suitable for users under 18. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="T:Discord.PermissionTarget"> | <member name="T:Discord.PermissionTarget"> | ||||
| <summary> | <summary> | ||||
| Specifies the target of the permission. | Specifies the target of the permission. | ||||
| @@ -4293,13 +4514,6 @@ | |||||
| If the option is a subcommand or subcommand group type, this nested options will be the parameters. | If the option is a subcommand or subcommand group type, this nested options will be the parameters. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.IApplicationCommand.DeleteAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Deletes this command | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns>A task that represents the asynchronous delete operation.</returns> | |||||
| </member> | |||||
| <member name="T:Discord.IApplicationCommandInteractionData"> | <member name="T:Discord.IApplicationCommandInteractionData"> | ||||
| <summary> | <summary> | ||||
| Represents data of an Interaction Command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata"/>. | Represents data of an Interaction Command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata"/>. | ||||
| @@ -4433,6 +4647,58 @@ | |||||
| read-only property, always 1. | read-only property, always 1. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.IDiscordInteraction.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <summary> | |||||
| Responds to an Interaction with type <see cref="F:Discord.InteractionResponseType.ChannelMessageWithSource"/>. | |||||
| </summary> | |||||
| <param name="text">The text of the message to be sent.</param> | |||||
| <param name="embeds">A array of embeds to send with this response. Max 10</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="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> | |||||
| <param name="component">A <see cref="T:Discord.MessageComponent"/> to be sent with this response</param> | |||||
| <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> | |||||
| </member> | |||||
| <member name="M:Discord.IDiscordInteraction.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <summary> | |||||
| Sends a followup message for this interaction. | |||||
| </summary> | |||||
| <param name="text">The text of the message to be sent</param> | |||||
| <param name="embeds">A array of embeds to send with this response. Max 10</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="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> | |||||
| <param name="component">A <see cref="T:Discord.MessageComponent"/> to be sent with this response</param> | |||||
| <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> | |||||
| <returns> | |||||
| The sent message. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IDiscordInteraction.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.IUserMessage"/> that represents the initial response.</returns> | |||||
| </member> | |||||
| <member name="M:Discord.IDiscordInteraction.ModifyOriginalResponseAsync(System.Action{Discord.MessageProperties},Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Edits original response for this interaction. | |||||
| </summary> | |||||
| <param name="func">A delegate containing the properties to modify the message with.</param> | |||||
| <param name="options">The request options for this async request.</param> | |||||
| <returns>A <see cref="T:Discord.IUserMessage"/> that represents the initial response.</returns> | |||||
| </member> | |||||
| <member name="M:Discord.IDiscordInteraction.DeferAsync(System.Boolean,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Acknowledges this interaction. | |||||
| </summary> | |||||
| <returns> | |||||
| A task that represents the asynchronous operation of acknowledging the interaction. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="T:Discord.IDiscordInteractionData"> | <member name="T:Discord.IDiscordInteractionData"> | ||||
| <summary> | <summary> | ||||
| Represents an interface used to specify classes that they are a vaild dataype of a <see cref="T:Discord.IDiscordInteraction"/> class. | Represents an interface used to specify classes that they are a vaild dataype of a <see cref="T:Discord.IDiscordInteraction"/> class. | ||||
| @@ -4583,7 +4849,7 @@ | |||||
| Represents a builder for creating a <see cref="T:Discord.MessageComponent"/>. | Represents a builder for creating a <see cref="T:Discord.MessageComponent"/>. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.ComponentBuilder.MaxLabelLength"> | |||||
| <member name="F:Discord.ComponentBuilder.MaxButtonLabelLength"> | |||||
| <summary> | <summary> | ||||
| The max length of a <see cref="P:Discord.ButtonComponent.Label"/>. | The max length of a <see cref="P:Discord.ButtonComponent.Label"/>. | ||||
| </summary> | </summary> | ||||
| @@ -4706,11 +4972,16 @@ | |||||
| Represents a class used to build <see cref="T:Discord.ButtonComponent"/>'s. | Represents a class used to build <see cref="T:Discord.ButtonComponent"/>'s. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.ButtonBuilder.MaxLabelLength"> | |||||
| <summary> | |||||
| The max length of a <see cref="P:Discord.ButtonComponent.Label"/>. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.ButtonBuilder.Label"> | <member name="P:Discord.ButtonBuilder.Label"> | ||||
| <summary> | <summary> | ||||
| Gets or sets the label of the current button. | Gets or sets the label of the current button. | ||||
| </summary> | </summary> | ||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.ButtonBuilder.Label"/> length exceeds <see cref="F:Discord.ComponentBuilder.MaxLabelLength"/>.</exception> | |||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.ButtonBuilder.Label"/> length exceeds <see cref="F:Discord.ComponentBuilder.MaxButtonLabelLength"/>.</exception> | |||||
| </member> | </member> | ||||
| <member name="P:Discord.ButtonBuilder.CustomId"> | <member name="P:Discord.ButtonBuilder.CustomId"> | ||||
| <summary> | <summary> | ||||
| @@ -5030,16 +5301,26 @@ | |||||
| Represents a class used to build <see cref="T:Discord.SelectMenuOption"/>'s. | Represents a class used to build <see cref="T:Discord.SelectMenuOption"/>'s. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.SelectMenuOptionBuilder.MaxLabelLength"> | |||||
| <summary> | |||||
| The maximum length of a <see cref="P:Discord.SelectMenuOption.Label"/>. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.SelectMenuOptionBuilder.MaxDescriptionLength"> | <member name="F:Discord.SelectMenuOptionBuilder.MaxDescriptionLength"> | ||||
| <summary> | <summary> | ||||
| The maximum length of a <see cref="P:Discord.SelectMenuOption.Description"/>. | The maximum length of a <see cref="P:Discord.SelectMenuOption.Description"/>. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.SelectMenuOptionBuilder.MaxSelectLabelLength"> | |||||
| <summary> | |||||
| The maximum length of a <see cref="P:Discord.SelectMenuOption.Label"/>. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.SelectMenuOptionBuilder.Label"> | <member name="P:Discord.SelectMenuOptionBuilder.Label"> | ||||
| <summary> | <summary> | ||||
| Gets or sets the label of the current select menu. | Gets or sets the label of the current select menu. | ||||
| </summary> | </summary> | ||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.SelectMenuOptionBuilder.Label"/> length exceeds <see cref="F:Discord.ComponentBuilder.MaxLabelLength"/></exception> | |||||
| <exception cref="T:System.ArgumentException" accessor="set"><see cref="P:Discord.SelectMenuOptionBuilder.Label"/> length exceeds <see cref="F:Discord.SelectMenuOptionBuilder.MaxSelectLabelLength"/></exception> | |||||
| </member> | </member> | ||||
| <member name="P:Discord.SelectMenuOptionBuilder.Value"> | <member name="P:Discord.SelectMenuOptionBuilder.Value"> | ||||
| <summary> | <summary> | ||||
| @@ -7398,6 +7679,14 @@ | |||||
| This must be less than the constant defined by <see cref="F:Discord.DiscordConfig.MaxMessageSize"/>. | This must be less than the constant defined by <see cref="F:Discord.DiscordConfig.MaxMessageSize"/>. | ||||
| </remarks> | </remarks> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.MessageProperties.Embed"> | |||||
| <summary> | |||||
| Gets or sets a single embed for this message. | |||||
| </summary> | |||||
| <remarks> | |||||
| This property will be added to the <see cref="P:Discord.MessageProperties.Embeds"/> array, in the future please use the array rather than this property. | |||||
| </remarks> | |||||
| </member> | |||||
| <member name="P:Discord.MessageProperties.Embeds"> | <member name="P:Discord.MessageProperties.Embeds"> | ||||
| <summary> | <summary> | ||||
| Gets or sets the embeds of the message. | Gets or sets the embeds of the message. | ||||
| @@ -7554,10 +7843,38 @@ | |||||
| The message for when a news channel subscription is added to a text channel. | The message for when a news channel subscription is added to a text channel. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.MessageType.GuildDiscoveryDisqualified"> | |||||
| <summary> | |||||
| The message for when a guild is disqualified from discovery. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.MessageType.GuildDiscoveryRequalified"> | |||||
| <summary> | |||||
| The message for when a guild is requalified for discovery. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.MessageType.GuildDiscoveryGracePeriodInitialWarning"> | |||||
| <summary> | |||||
| The message for when the initial warning is sent for the initial grace period discovery. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.MessageType.GuildDiscoveryGracePeriodFinalWarning"> | |||||
| <summary> | |||||
| The message for when the final warning is sent for the initial grace period discovery. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.MessageType.ThreadCreated"> | |||||
| <summary> | |||||
| The message for when a thread is created. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="F:Discord.MessageType.Reply"> | <member name="F:Discord.MessageType.Reply"> | ||||
| <summary> | <summary> | ||||
| The message is an inline reply. | The message is an inline reply. | ||||
| </summary> | </summary> | ||||
| <remarks> | |||||
| Only available in API v8 | |||||
| </remarks> | |||||
| </member> | </member> | ||||
| <member name="F:Discord.MessageType.ApplicationCommand"> | <member name="F:Discord.MessageType.ApplicationCommand"> | ||||
| <summary> | <summary> | ||||
| @@ -7567,6 +7884,19 @@ | |||||
| Only available in API v8 | Only available in API v8 | ||||
| </remarks> | </remarks> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.MessageType.ThreadStarterMessage"> | |||||
| <summary> | |||||
| The message that starts a thread. | |||||
| </summary> | |||||
| <remarks> | |||||
| Only available in API v9 | |||||
| </remarks> | |||||
| </member> | |||||
| <member name="F:Discord.MessageType.GuildInviteReminder"> | |||||
| <summary> | |||||
| The message for a invite reminder | |||||
| </summary> | |||||
| </member> | |||||
| <member name="T:Discord.ReactionMetadata"> | <member name="T:Discord.ReactionMetadata"> | ||||
| <summary> | <summary> | ||||
| A metadata containing reaction information. | A metadata containing reaction information. | ||||
| @@ -8397,7 +8727,25 @@ | |||||
| <summary> If <c>true</c>, a user may edit the webhooks for this guild. </summary> | <summary> If <c>true</c>, a user may edit the webhooks for this guild. </summary> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.GuildPermissions.ManageEmojisAndStickers"> | <member name="P:Discord.GuildPermissions.ManageEmojisAndStickers"> | ||||
| <summary> If <c>true</c>, a user may edit the emojis for this guild. </summary> | |||||
| <summary> If <c>true</c>, a user may edit the emojis and stickers for this guild. </summary> | |||||
| </member> | |||||
| <member name="P:Discord.GuildPermissions.UseSlashCommands"> | |||||
| <summary> If <c>true</c>, a user may use slash commands in this guild. </summary> | |||||
| </member> | |||||
| <member name="P:Discord.GuildPermissions.RequestToSpeak"> | |||||
| <summary> If <c>true</c>, a user may request to speak in stage channels. </summary> | |||||
| </member> | |||||
| <member name="P:Discord.GuildPermissions.ManageThreads"> | |||||
| <summary> If <c>true</c>, a user may manage threads in this guild. </summary> | |||||
| </member> | |||||
| <member name="P:Discord.GuildPermissions.UsePublicThreads"> | |||||
| <summary> If <c>true</c>, a user may create public threads in this guild. </summary> | |||||
| </member> | |||||
| <member name="P:Discord.GuildPermissions.UsePrivateThreads"> | |||||
| <summary> If <c>true</c>, a user may create private threads in this guild. </summary> | |||||
| </member> | |||||
| <member name="P:Discord.GuildPermissions.UseExternalStickers"> | |||||
| <summary> If <c>true</c>, a user may use external stickers in this guild. </summary> | |||||
| </member> | </member> | ||||
| <member name="M:Discord.GuildPermissions.#ctor(System.UInt64)"> | <member name="M:Discord.GuildPermissions.#ctor(System.UInt64)"> | ||||
| <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> with the provided packed value. </summary> | <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> with the provided packed value. </summary> | ||||
| @@ -8405,10 +8753,10 @@ | |||||
| <member name="M:Discord.GuildPermissions.#ctor(System.String)"> | <member name="M:Discord.GuildPermissions.#ctor(System.String)"> | ||||
| <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> with the provided packed value after converting to ulong. </summary> | <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> with the provided packed value after converting to ulong. </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.GuildPermissions.#ctor(System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"> | |||||
| <member name="M:Discord.GuildPermissions.#ctor(System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"> | |||||
| <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> structure with the provided permissions. </summary> | <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> structure with the provided permissions. </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.GuildPermissions.Modify(System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean})"> | |||||
| <member name="M:Discord.GuildPermissions.Modify(System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean})"> | |||||
| <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> from this one, changing the provided non-null permissions. </summary> | <summary> Creates a new <see cref="T:Discord.GuildPermissions"/> from this one, changing the provided non-null permissions. </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.GuildPermissions.Has(Discord.GuildPermission)"> | <member name="M:Discord.GuildPermissions.Has(Discord.GuildPermission)"> | ||||
| @@ -8595,6 +8943,9 @@ | |||||
| Represents a color used in Discord. | Represents a color used in Discord. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.Color.MaxDecimalValue"> | |||||
| <summary> Gets the max decimal value of color. </summary> | |||||
| </member> | |||||
| <member name="F:Discord.Color.Default"> | <member name="F:Discord.Color.Default"> | ||||
| <summary> Gets the default user color value. </summary> | <summary> Gets the default user color value. </summary> | ||||
| </member> | </member> | ||||
| @@ -8699,20 +9050,21 @@ | |||||
| Initializes a <see cref="T:Discord.Color"/> struct with the given raw value. | Initializes a <see cref="T:Discord.Color"/> struct with the given raw value. | ||||
| </summary> | </summary> | ||||
| <example> | <example> | ||||
| The following will create a color that has a hex value of | |||||
| The following will create a color that has a hex value of | |||||
| <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | ||||
| <code language="cs"> | <code language="cs"> | ||||
| Color darkGrey = new Color(0x607D8B); | Color darkGrey = new Color(0x607D8B); | ||||
| </code> | </code> | ||||
| </example> | </example> | ||||
| <param name="rawValue">The raw value of the color (e.g. <c>0x607D8B</c>).</param> | <param name="rawValue">The raw value of the color (e.g. <c>0x607D8B</c>).</param> | ||||
| <exception cref="T:System.ArgumentException">Value exceeds <see cref="F:Discord.Color.MaxDecimalValue"/>.</exception> | |||||
| </member> | </member> | ||||
| <member name="M:Discord.Color.#ctor(System.Byte,System.Byte,System.Byte)"> | <member name="M:Discord.Color.#ctor(System.Byte,System.Byte,System.Byte)"> | ||||
| <summary> | <summary> | ||||
| Initializes a <see cref="T:Discord.Color" /> struct with the given RGB bytes. | Initializes a <see cref="T:Discord.Color" /> struct with the given RGB bytes. | ||||
| </summary> | </summary> | ||||
| <example> | <example> | ||||
| The following will create a color that has a value of | |||||
| The following will create a color that has a value of | |||||
| <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | ||||
| <code language="cs"> | <code language="cs"> | ||||
| Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); | Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); | ||||
| @@ -8721,13 +9073,14 @@ | |||||
| <param name="r">The byte that represents the red color.</param> | <param name="r">The byte that represents the red color.</param> | ||||
| <param name="g">The byte that represents the green color.</param> | <param name="g">The byte that represents the green color.</param> | ||||
| <param name="b">The byte that represents the blue color.</param> | <param name="b">The byte that represents the blue color.</param> | ||||
| <exception cref="T:System.ArgumentException">Value exceeds <see cref="F:Discord.Color.MaxDecimalValue"/>.</exception> | |||||
| </member> | </member> | ||||
| <member name="M:Discord.Color.#ctor(System.Int32,System.Int32,System.Int32)"> | <member name="M:Discord.Color.#ctor(System.Int32,System.Int32,System.Int32)"> | ||||
| <summary> | <summary> | ||||
| Initializes a <see cref="T:Discord.Color"/> struct with the given RGB value. | Initializes a <see cref="T:Discord.Color"/> struct with the given RGB value. | ||||
| </summary> | </summary> | ||||
| <example> | <example> | ||||
| The following will create a color that has a value of | |||||
| The following will create a color that has a value of | |||||
| <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | ||||
| <code language="cs"> | <code language="cs"> | ||||
| Color darkGrey = new Color(96, 125, 139); | Color darkGrey = new Color(96, 125, 139); | ||||
| @@ -8743,7 +9096,7 @@ | |||||
| Initializes a <see cref="T:Discord.Color"/> struct with the given RGB float value. | Initializes a <see cref="T:Discord.Color"/> struct with the given RGB float value. | ||||
| </summary> | </summary> | ||||
| <example> | <example> | ||||
| The following will create a color that has a value of | |||||
| The following will create a color that has a value of | |||||
| <see href="http://www.color-hex.com/color/607c8c">#607c8c</see>. | <see href="http://www.color-hex.com/color/607c8c">#607c8c</see>. | ||||
| <code language="cs"> | <code language="cs"> | ||||
| Color darkGrey = new Color(0.38f, 0.49f, 0.55f); | Color darkGrey = new Color(0.38f, 0.49f, 0.55f); | ||||
| @@ -9511,19 +9864,33 @@ | |||||
| Gets the identifier of this user's avatar. | Gets the identifier of this user's avatar. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.IUser.BannerId"> | |||||
| <summary> | |||||
| Gets the identifier of this user's banner. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.IUser.AccentColor"> | |||||
| <summary> | |||||
| Gets the user's banner color. | |||||
| </summary> | |||||
| <returns> | |||||
| A <see cref="T:Discord.Color"/> struct representing the accent color of this user's banner. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IUser.GetAvatarUrl(Discord.ImageFormat,System.UInt16)"> | <member name="M:Discord.IUser.GetAvatarUrl(Discord.ImageFormat,System.UInt16)"> | ||||
| <summary> | <summary> | ||||
| Gets the avatar URL for this user. | Gets the avatar URL for this user. | ||||
| </summary> | </summary> | ||||
| <remarks> | <remarks> | ||||
| This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar | This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar | ||||
| (i.e. their avatar identifier is not set), this property will return <c>null</c>. If you wish to | |||||
| (i.e. their avatar identifier is not set), this method will return <c>null</c>. If you wish to | |||||
| retrieve the default avatar for this user, consider using <see cref="M:Discord.IUser.GetDefaultAvatarUrl"/> (see | retrieve the default avatar for this user, consider using <see cref="M:Discord.IUser.GetDefaultAvatarUrl"/> (see | ||||
| example). | example). | ||||
| </remarks> | </remarks> | ||||
| <example> | <example> | ||||
| <para>The following example attempts to retrieve the user's current avatar and send it to a channel; if one is | |||||
| not set, a default avatar for this user will be returned instead.</para> | |||||
| <para | |||||
| >The following example attempts to retrieve the user's current avatar and send it to a channel; if one is | |||||
| not set, a default avatar for this user will be returned instead.</para> | |||||
| <code language="cs" region="GetAvatarUrl" | <code language="cs" region="GetAvatarUrl" | ||||
| source="..\..\..\Discord.Net.Examples\Core\Entities\Users\IUser.Examples.cs"/> | source="..\..\..\Discord.Net.Examples\Core\Entities\Users\IUser.Examples.cs"/> | ||||
| </example> | </example> | ||||
| @@ -9534,6 +9901,17 @@ | |||||
| A string representing the user's avatar URL; <c>null</c> if the user does not have an avatar in place. | A string representing the user's avatar URL; <c>null</c> if the user does not have an avatar in place. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.IUser.GetBannerUrl(Discord.ImageFormat,System.UInt16)"> | |||||
| <summary> | |||||
| Gets the banner URL for this user. | |||||
| </summary> | |||||
| <param name="format">The format to return.</param> | |||||
| <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048. | |||||
| </param> | |||||
| <returns> | |||||
| A string representing the user's avatar URL; <c>null</c> if the user does not have an banner in place. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.IUser.GetDefaultAvatarUrl"> | <member name="M:Discord.IUser.GetDefaultAvatarUrl"> | ||||
| <summary> | <summary> | ||||
| Gets the default avatar URL for this user. | Gets the default avatar URL for this user. | ||||
| @@ -9601,8 +9979,8 @@ | |||||
| This method is used to obtain or create a channel used to send a direct message. | This method is used to obtain or create a channel used to send a direct message. | ||||
| <note type="warning"> | <note type="warning"> | ||||
| In event that the current user cannot send a message to the target user, a channel can and will | In event that the current user cannot send a message to the target user, a channel can and will | ||||
| still be created by Discord. However, attempting to send a message will yield a | |||||
| <see cref="T:Discord.Net.HttpException"/> with a 403 as its | |||||
| still be created by Discord. However, attempting to send a message will yield a | |||||
| <see cref="T:Discord.Net.HttpException"/> with a 403 as its | |||||
| <see cref="P:Discord.Net.HttpException.HttpCode"/>. There are currently no official workarounds by | <see cref="P:Discord.Net.HttpException.HttpCode"/>. There are currently no official workarounds by | ||||
| Discord. | Discord. | ||||
| </note> | </note> | ||||
| @@ -9689,6 +10067,11 @@ | |||||
| <c>true</c> if the user is streaming; otherwise <c>false</c>. | <c>true</c> if the user is streaming; otherwise <c>false</c>. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.IVoiceState.RequestToSpeakTimestamp"> | |||||
| <summary> | |||||
| Gets the time on which the user requested to speak. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="T:Discord.IWebhookUser"> | <member name="T:Discord.IWebhookUser"> | ||||
| <summary> Represents a Webhook Discord user. </summary> | <summary> Represents a Webhook Discord user. </summary> | ||||
| </member> | </member> | ||||
| @@ -9891,6 +10274,11 @@ | |||||
| Gets the user that created this webhook. | Gets the user that created this webhook. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.IWebhook.ApplicationId"> | |||||
| <summary> | |||||
| Gets the ID of the application owning this webhook. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="M:Discord.IWebhook.ModifyAsync(System.Action{Discord.WebhookProperties},Discord.RequestOptions)"> | <member name="M:Discord.IWebhook.ModifyAsync(System.Action{Discord.WebhookProperties},Discord.RequestOptions)"> | ||||
| <summary> | <summary> | ||||
| Modifies this webhook. | Modifies this webhook. | ||||
| @@ -0,0 +1,120 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord | |||||
| { | |||||
| /// <summary> | |||||
| /// Represents a generic Stage Channel. | |||||
| /// </summary> | |||||
| public interface IStageChannel : IVoiceChannel | |||||
| { | |||||
| /// <summary> | |||||
| /// Gets the topic of the Stage instance. | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// If the stage isn't live then this property will be set to <see langword="null"/>. | |||||
| /// </remarks> | |||||
| string Topic { get; } | |||||
| /// <summary> | |||||
| /// The <see cref="StagePrivacyLevel"/> of the current stage. | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// If the stage isn't live then this property will be set to <see langword="null"/>. | |||||
| /// </remarks> | |||||
| StagePrivacyLevel? PrivacyLevel { get; } | |||||
| /// <summary> | |||||
| /// <see langword="true"/> if stage discovery is disabled, otherwise <see langword="false"/>. | |||||
| /// </summary> | |||||
| bool? DiscoverableDisabled { get; } | |||||
| /// <summary> | |||||
| /// <see langword="true"/> when the stage is live, otherwise <see langword="false"/>. | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// If the stage isn't live then this property will be set to <see langword="null"/>. | |||||
| /// </remarks> | |||||
| bool Live { get; } | |||||
| /// <summary> | |||||
| /// Starts the stage, creating a stage instance. | |||||
| /// </summary> | |||||
| /// <param name="topic">The topic for the stage/</param> | |||||
| /// <param name="privacyLevel">The privacy level of the stage</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous start operation. | |||||
| /// </returns> | |||||
| Task StartStageAsync(string topic, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Modifies the current stage instance. | |||||
| /// </summary> | |||||
| /// <param name="func">The properties to modify the stage instance with.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous modify operation. | |||||
| /// </returns> | |||||
| Task ModifyInstanceAsync(Action<StageInstanceProperties> func, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Stops the stage, deleting the stage instance. | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous stop operation. | |||||
| /// </returns> | |||||
| Task StopStageAsync(RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Indicates that the bot would like to speak within a stage channel. | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous request to speak operation. | |||||
| /// </returns> | |||||
| Task RequestToSpeak(RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Makes the current user become a speaker within a stage. | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous speaker modify operation. | |||||
| /// </returns> | |||||
| Task BecomeSpeakerAsync(RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Makes the current user a listener. | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous stop operation. | |||||
| /// </returns> | |||||
| Task StopSpeakingAsync(RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Makes a user a speaker within a stage. | |||||
| /// </summary> | |||||
| /// <param name="user">The user to make the speaker.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous move operation. | |||||
| /// </returns> | |||||
| Task MoveToSpeaker(IGuildUser user, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Removes a user from speaking. | |||||
| /// </summary> | |||||
| /// <param name="user">The user to remove from speaking.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous remove operation. | |||||
| /// </returns> | |||||
| Task RemoveFromSpeaker(IGuildUser user, RequestOptions options = null); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord | |||||
| { | |||||
| /// <summary> | |||||
| /// Represents properties to use when modifying a stage instance. | |||||
| /// </summary> | |||||
| public class StageInstanceProperties | |||||
| { | |||||
| /// <summary> | |||||
| /// Gets or sets the topic of the stage. | |||||
| /// </summary> | |||||
| public Optional<string> Topic { get; set; } | |||||
| /// <summary> | |||||
| /// Gets or sets the privacy level of the stage. | |||||
| /// </summary> | |||||
| public Optional<StagePrivacyLevel> PrivacyLevel { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord | |||||
| { | |||||
| public enum StagePrivacyLevel | |||||
| { | |||||
| Public = 1, | |||||
| GuildOnly = 2, | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,7 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | |||||
| using System.Collections.ObjectModel; | |||||
| using System.Linq; | using System.Linq; | ||||
| namespace Discord | namespace Discord | ||||
| @@ -56,7 +58,7 @@ namespace Discord | |||||
| if (NamesAndUnicodes.ContainsKey(text)) | if (NamesAndUnicodes.ContainsKey(text)) | ||||
| result = new Emoji(NamesAndUnicodes[text]); | result = new Emoji(NamesAndUnicodes[text]); | ||||
| if (UnicodesAndNames.ContainsKey(text)) | |||||
| if (Unicodes.Contains(text)) | |||||
| result = new Emoji(text); | result = new Emoji(text); | ||||
| return result != null; | return result != null; | ||||
| @@ -5942,12 +5944,30 @@ namespace Discord | |||||
| ["♡"] = "❤️" | ["♡"] = "❤️" | ||||
| }; | }; | ||||
| private static IReadOnlyDictionary<string, string> _unicodesAndNames; | |||||
| private static IReadOnlyDictionary<string, string> UnicodesAndNames | |||||
| private static IReadOnlyCollection<string> _unicodes; | |||||
| private static IReadOnlyCollection<string> Unicodes | |||||
| { | { | ||||
| get | get | ||||
| { | { | ||||
| _unicodesAndNames ??= NamesAndUnicodes.ToDictionary(kvp => kvp.Value, kvp => kvp.Key); | |||||
| _unicodes ??= NamesAndUnicodes.Select(kvp => kvp.Value).ToImmutableHashSet(); | |||||
| return _unicodes; | |||||
| } | |||||
| } | |||||
| private static IReadOnlyDictionary<string, ReadOnlyCollection<string>> _unicodesAndNames; | |||||
| private static IReadOnlyDictionary<string, ReadOnlyCollection<string>> UnicodesAndNames | |||||
| { | |||||
| get | |||||
| { | |||||
| _unicodesAndNames ??= | |||||
| NamesAndUnicodes | |||||
| .GroupBy(kvp => kvp.Value) | |||||
| .ToImmutableDictionary( | |||||
| grouping => grouping.Key, | |||||
| grouping => grouping.Select(kvp => kvp.Key) | |||||
| .ToList() | |||||
| .AsReadOnly() | |||||
| ); | |||||
| return _unicodesAndNames; | return _unicodesAndNames; | ||||
| } | } | ||||
| } | } | ||||
| @@ -316,6 +316,14 @@ namespace Discord | |||||
| /// </returns> | /// </returns> | ||||
| string PreferredLocale { get; } | string PreferredLocale { get; } | ||||
| /// <summary> | |||||
| /// Gets the NSFW level of this guild. | |||||
| /// </summary> | |||||
| /// <returns> | |||||
| /// The NSFW level of this guild. | |||||
| /// </returns> | |||||
| NsfwLevel NsfwLevel { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets the preferred culture of this guild. | /// Gets the preferred culture of this guild. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -522,6 +530,27 @@ namespace Discord | |||||
| /// </returns> | /// </returns> | ||||
| Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets a stage channel in this guild | |||||
| /// </summary> | |||||
| /// <param name="id">The snowflake identifier for the stage channel.</param> | |||||
| /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains the stage channel associated | |||||
| /// with the specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
| /// </returns> | |||||
| Task<IStageChannel> GetStageChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Gets a collection of all stage channels in this guild. | |||||
| /// </summary> | |||||
| /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| /// stage channels found within this guild. | |||||
| /// </returns> | |||||
| Task<IReadOnlyCollection<IStageChannel>> GetStageChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Gets the AFK voice channel in this guild. | /// Gets the AFK voice channel in this guild. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | ||||
| @@ -581,6 +610,26 @@ namespace Discord | |||||
| /// admins and moderators of Community guilds receive notices from Discord; <see langword="null" /> if none is set. | /// admins and moderators of Community guilds receive notices from Discord; <see langword="null" /> if none is set. | ||||
| /// </returns> | /// </returns> | ||||
| Task<ITextChannel> GetPublicUpdatesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetPublicUpdatesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| /// <summary> | |||||
| /// Gets a thread channel within this guild. | |||||
| /// </summary> | |||||
| /// <param name="id">The id of the thread channel.</param> | |||||
| /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains the thread channel. | |||||
| /// </returns> | |||||
| Task<IThreadChannel> GetThreadChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Gets a collection of all thread channels in this guild. | |||||
| /// </summary> | |||||
| /// <param name="mode">The <see cref="CacheMode" /> that determines whether the object should be fetched from cache.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| /// thread channels found within this guild. | |||||
| /// </returns> | |||||
| Task<IReadOnlyCollection<IThreadChannel>> GetThreadChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
| /// <summary> | /// <summary> | ||||
| /// Creates a new text channel in this guild. | /// Creates a new text channel in this guild. | ||||
| @@ -892,5 +941,15 @@ namespace Discord | |||||
| /// A task that represents the asynchronous removal operation. | /// A task that represents the asynchronous removal operation. | ||||
| /// </returns> | /// </returns> | ||||
| Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null); | Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null); | ||||
| /// <summary> | |||||
| /// Gets this guilds slash commands commands | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains a read-only collection | |||||
| /// of application commands found within the guild. | |||||
| /// </returns> | |||||
| Task<IReadOnlyCollection<IApplicationCommand>> GetApplicationCommandsAsync (RequestOptions options = null); | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,22 @@ | |||||
| namespace Discord | |||||
| { | |||||
| public enum NsfwLevel | |||||
| { | |||||
| /// <summary> | |||||
| /// Default or unset. | |||||
| /// </summary> | |||||
| Default = 0, | |||||
| /// <summary> | |||||
| /// Guild has extremely suggestive or mature content that would only be suitable for users 18 or over. | |||||
| /// </summary> | |||||
| Explicit = 1, | |||||
| /// <summary> | |||||
| /// Guild has no content that could be deemed NSFW; in other words, SFW. | |||||
| /// </summary> | |||||
| Safe = 2, | |||||
| /// <summary> | |||||
| /// Guild has mildly NSFW content that may not be suitable for users under 18. | |||||
| /// </summary> | |||||
| AgeRestricted = 3 | |||||
| } | |||||
| } | |||||
| @@ -9,7 +9,7 @@ namespace Discord | |||||
| /// <summary> | /// <summary> | ||||
| /// The base command model that belongs to an application. see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommand"/> | /// The base command model that belongs to an application. see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommand"/> | ||||
| /// </summary> | /// </summary> | ||||
| public interface IApplicationCommand : ISnowflakeEntity | |||||
| public interface IApplicationCommand : ISnowflakeEntity, IDeletable | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the unique id of the parent application. | /// Gets the unique id of the parent application. | ||||
| @@ -35,12 +35,5 @@ namespace Discord | |||||
| /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. | /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. | ||||
| /// </summary> | /// </summary> | ||||
| IReadOnlyCollection<IApplicationCommandOption> Options { get; } | IReadOnlyCollection<IApplicationCommandOption> Options { get; } | ||||
| /// <summary> | |||||
| /// Deletes this command | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns>A task that represents the asynchronous delete operation.</returns> | |||||
| Task DeleteAsync(RequestOptions options = null); | |||||
| } | } | ||||
| } | } | ||||
| @@ -39,5 +39,59 @@ namespace Discord | |||||
| /// read-only property, always 1. | /// read-only property, always 1. | ||||
| /// </summary> | /// </summary> | ||||
| int Version { get; } | int Version { get; } | ||||
| /// <summary> | |||||
| /// Responds to an Interaction with type <see cref="InteractionResponseType.ChannelMessageWithSource"/>. | |||||
| /// </summary> | |||||
| /// <param name="text">The text of the message to be sent.</param> | |||||
| /// <param name="embeds">A array of embeds to send with this response. Max 10</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="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> | |||||
| /// <param name="component">A <see cref="MessageComponent"/> to be sent with this response</param> | |||||
| /// <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> | |||||
| Task RespondAsync (string text = null, Embed[] embeds = null, bool isTTS = false, | |||||
| bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); | |||||
| /// <summary> | |||||
| /// Sends a followup message for this interaction. | |||||
| /// </summary> | |||||
| /// <param name="text">The text of the message to be sent</param> | |||||
| /// <param name="embeds">A array of embeds to send with this response. Max 10</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="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> | |||||
| /// <param name="component">A <see cref="MessageComponent"/> to be sent with this response</param> | |||||
| /// <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> | |||||
| /// <returns> | |||||
| /// The sent message. | |||||
| /// </returns> | |||||
| Task<IUserMessage> FollowupAsync (string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, | |||||
| AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); | |||||
| /// <summary> | |||||
| /// Gets the original response for this interaction. | |||||
| /// </summary> | |||||
| /// <param name="options">The request options for this async request.</param> | |||||
| /// <returns>A <see cref="IUserMessage"/> that represents the initial response.</returns> | |||||
| Task<IUserMessage> GetOriginalResponseAsync (RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Edits original response for this interaction. | |||||
| /// </summary> | |||||
| /// <param name="func">A delegate containing the properties to modify the message with.</param> | |||||
| /// <param name="options">The request options for this async request.</param> | |||||
| /// <returns>A <see cref="IUserMessage"/> that represents the initial response.</returns> | |||||
| Task<IUserMessage> ModifyOriginalResponseAsync (Action<MessageProperties> func, RequestOptions options = null); | |||||
| /// <summary> | |||||
| /// Acknowledges this interaction. | |||||
| /// </summary> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous operation of acknowledging the interaction. | |||||
| /// </returns> | |||||
| Task DeferAsync (bool ephemeral = false, RequestOptions options = null); | |||||
| } | } | ||||
| } | } | ||||
| @@ -13,7 +13,7 @@ namespace Discord | |||||
| /// <summary> | /// <summary> | ||||
| /// The max length of a <see cref="ButtonComponent.Label"/>. | /// The max length of a <see cref="ButtonComponent.Label"/>. | ||||
| /// </summary> | /// </summary> | ||||
| public const int MaxLabelLength = 80; | |||||
| public const int MaxButtonLabelLength = 80; | |||||
| /// <summary> | /// <summary> | ||||
| /// The max length of a <see cref="ButtonComponent.CustomId"/>. | /// The max length of a <see cref="ButtonComponent.CustomId"/>. | ||||
| @@ -307,17 +307,22 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| public class ButtonBuilder | public class ButtonBuilder | ||||
| { | { | ||||
| /// <summary> | |||||
| /// The max length of a <see cref="ButtonComponent.Label"/>. | |||||
| /// </summary> | |||||
| public const int MaxLabelLength = 80; | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the label of the current button. | /// Gets or sets the label of the current button. | ||||
| /// </summary> | /// </summary> | ||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="ComponentBuilder.MaxLabelLength"/>.</exception> | |||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="ComponentBuilder.MaxButtonLabelLength"/>.</exception> | |||||
| public string Label | public string Label | ||||
| { | { | ||||
| get => _label; | get => _label; | ||||
| set | set | ||||
| { | { | ||||
| if (value != null && value.Length > ComponentBuilder.MaxLabelLength) | |||||
| throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); | |||||
| if (value != null && value.Length > ComponentBuilder.MaxButtonLabelLength) | |||||
| throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxButtonLabelLength} characters or less!", paramName: nameof(Label)); | |||||
| _label = value; | _label = value; | ||||
| } | } | ||||
| @@ -539,8 +544,8 @@ namespace Discord | |||||
| if (string.IsNullOrEmpty(this.Url)) | if (string.IsNullOrEmpty(this.Url)) | ||||
| throw new InvalidOperationException("Link buttons must have a link associated with them"); | throw new InvalidOperationException("Link buttons must have a link associated with them"); | ||||
| else | else | ||||
| UrlValidation.Validate(this.Url); | |||||
| } | |||||
| UrlValidation.Validate(this.Url); | |||||
| } | |||||
| else if (string.IsNullOrEmpty(this.CustomId)) | else if (string.IsNullOrEmpty(this.CustomId)) | ||||
| throw new InvalidOperationException("Non-link buttons must have a custom id associated with them"); | throw new InvalidOperationException("Non-link buttons must have a custom id associated with them"); | ||||
| @@ -831,23 +836,33 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| public class SelectMenuOptionBuilder | public class SelectMenuOptionBuilder | ||||
| { | { | ||||
| /// <summary> | |||||
| /// The maximum length of a <see cref="SelectMenuOption.Label"/>. | |||||
| /// </summary> | |||||
| public const int MaxLabelLength = 100; | |||||
| /// <summary> | /// <summary> | ||||
| /// The maximum length of a <see cref="SelectMenuOption.Description"/>. | /// The maximum length of a <see cref="SelectMenuOption.Description"/>. | ||||
| /// </summary> | /// </summary> | ||||
| public const int MaxDescriptionLength = 50; | |||||
| public const int MaxDescriptionLength = 100; | |||||
| /// <summary> | |||||
| /// The maximum length of a <see cref="SelectMenuOption.Label"/>. | |||||
| /// </summary> | |||||
| public const int MaxSelectLabelLength = 100; | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the label of the current select menu. | /// Gets or sets the label of the current select menu. | ||||
| /// </summary> | /// </summary> | ||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="ComponentBuilder.MaxLabelLength"/></exception> | |||||
| /// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="MaxSelectLabelLength"/></exception> | |||||
| public string Label | public string Label | ||||
| { | { | ||||
| get => _label; | get => _label; | ||||
| set | set | ||||
| { | { | ||||
| if (value != null) | if (value != null) | ||||
| if (value.Length > ComponentBuilder.MaxLabelLength) | |||||
| throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); | |||||
| if (value.Length > MaxSelectLabelLength) | |||||
| throw new ArgumentException(message: $"Button label must be {MaxSelectLabelLength} characters or less!", paramName: nameof(Label)); | |||||
| _label = value; | _label = value; | ||||
| } | } | ||||
| @@ -411,7 +411,7 @@ namespace Discord | |||||
| UrlValidation.Validate(Url); | UrlValidation.Validate(Url); | ||||
| if (!string.IsNullOrEmpty(ThumbnailUrl)) | if (!string.IsNullOrEmpty(ThumbnailUrl)) | ||||
| UrlValidation.Validate(ThumbnailUrl); | UrlValidation.Validate(ThumbnailUrl); | ||||
| if (!string.IsNullOrEmpty(ImageUrl)) | |||||
| if (!string.IsNullOrEmpty(ImageUrl) && !ImageUrl.StartsWith("attachment://", StringComparison.Ordinal)) | |||||
| UrlValidation.Validate(ImageUrl); | UrlValidation.Validate(ImageUrl); | ||||
| if (Author != null) | if (Author != null) | ||||
| { | { | ||||
| @@ -18,6 +18,14 @@ namespace Discord | |||||
| /// </remarks> | /// </remarks> | ||||
| public Optional<string> Content { get; set; } | public Optional<string> Content { get; set; } | ||||
| /// <summary> | |||||
| /// Gets or sets a single embed for this message. | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// This property will be added to the <see cref="Embeds"/> array, in the future please use the array rather than this property. | |||||
| /// </remarks> | |||||
| public Optional<Embed> Embed { get; set; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the embeds of the message. | /// Gets or sets the embeds of the message. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -81,8 +81,20 @@ namespace Discord | |||||
| public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); | public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); | ||||
| /// <summary> If <c>true</c>, a user may edit the webhooks for this guild. </summary> | /// <summary> If <c>true</c>, a user may edit the webhooks for this guild. </summary> | ||||
| public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); | public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); | ||||
| /// <summary> If <c>true</c>, a user may edit the emojis for this guild. </summary> | |||||
| /// <summary> If <c>true</c>, a user may edit the emojis and stickers for this guild. </summary> | |||||
| public bool ManageEmojisAndStickers => Permissions.GetValue(RawValue, GuildPermission.ManageEmojisAndStickers); | public bool ManageEmojisAndStickers => Permissions.GetValue(RawValue, GuildPermission.ManageEmojisAndStickers); | ||||
| /// <summary> If <c>true</c>, a user may use slash commands in this guild. </summary> | |||||
| public bool UseSlashCommands => Permissions.GetValue(RawValue, GuildPermission.UseSlashCommands); | |||||
| /// <summary> If <c>true</c>, a user may request to speak in stage channels. </summary> | |||||
| public bool RequestToSpeak => Permissions.GetValue(RawValue, GuildPermission.RequestToSpeak); | |||||
| /// <summary> If <c>true</c>, a user may manage threads in this guild. </summary> | |||||
| public bool ManageThreads => Permissions.GetValue(RawValue, GuildPermission.ManageThreads); | |||||
| /// <summary> If <c>true</c>, a user may create public threads in this guild. </summary> | |||||
| public bool UsePublicThreads => Permissions.GetValue(RawValue, GuildPermission.UsePublicThreads); | |||||
| /// <summary> If <c>true</c>, a user may create private threads in this guild. </summary> | |||||
| public bool UsePrivateThreads => Permissions.GetValue(RawValue, GuildPermission.UsePrivateThreads); | |||||
| /// <summary> If <c>true</c>, a user may use external stickers in this guild. </summary> | |||||
| public bool UseExternalStickers => Permissions.GetValue(RawValue, GuildPermission.UseExternalStickers); | |||||
| /// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary> | /// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary> | ||||
| public GuildPermissions(ulong rawValue) { RawValue = rawValue; } | public GuildPermissions(ulong rawValue) { RawValue = rawValue; } | ||||
| @@ -121,7 +133,13 @@ namespace Discord | |||||
| bool? manageNicknames = null, | bool? manageNicknames = null, | ||||
| bool? manageRoles = null, | bool? manageRoles = null, | ||||
| bool? manageWebhooks = null, | bool? manageWebhooks = null, | ||||
| bool? manageEmojisAndStickers = null) | |||||
| bool? manageEmojisAndStickers = null, | |||||
| bool? useSlashCommands = null, | |||||
| bool? requestToSpeak = null, | |||||
| bool? manageThreads = null, | |||||
| bool? usePublicThreads = null, | |||||
| bool? usePrivateThreads = null, | |||||
| bool? useExternalStickers = null) | |||||
| { | { | ||||
| ulong value = initialValue; | ulong value = initialValue; | ||||
| @@ -156,6 +174,12 @@ namespace Discord | |||||
| Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); | Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); | ||||
| Permissions.SetValue(ref value, manageWebhooks, GuildPermission.ManageWebhooks); | Permissions.SetValue(ref value, manageWebhooks, GuildPermission.ManageWebhooks); | ||||
| Permissions.SetValue(ref value, manageEmojisAndStickers, GuildPermission.ManageEmojisAndStickers); | Permissions.SetValue(ref value, manageEmojisAndStickers, GuildPermission.ManageEmojisAndStickers); | ||||
| Permissions.SetValue(ref value, useSlashCommands, GuildPermission.UseSlashCommands); | |||||
| Permissions.SetValue(ref value, requestToSpeak, GuildPermission.RequestToSpeak); | |||||
| Permissions.SetValue(ref value, manageThreads, GuildPermission.ManageThreads); | |||||
| Permissions.SetValue(ref value, usePublicThreads, GuildPermission.UsePublicThreads); | |||||
| Permissions.SetValue(ref value, usePrivateThreads, GuildPermission.UseExternalStickers); | |||||
| Permissions.SetValue(ref value, useExternalStickers, GuildPermission.UseExternalStickers); | |||||
| RawValue = value; | RawValue = value; | ||||
| } | } | ||||
| @@ -192,7 +216,13 @@ namespace Discord | |||||
| bool manageNicknames = false, | bool manageNicknames = false, | ||||
| bool manageRoles = false, | bool manageRoles = false, | ||||
| bool manageWebhooks = false, | bool manageWebhooks = false, | ||||
| bool manageEmojis = false) | |||||
| bool manageEmojisAndStickers = false, | |||||
| bool useSlashCommands = false, | |||||
| bool requestToSpeak = false, | |||||
| bool manageThreads = false, | |||||
| bool usePublicThreads = false, | |||||
| bool usePrivateThreads = false, | |||||
| bool useExternalStickers = false) | |||||
| : this(0, | : this(0, | ||||
| createInstantInvite: createInstantInvite, | createInstantInvite: createInstantInvite, | ||||
| manageRoles: manageRoles, | manageRoles: manageRoles, | ||||
| @@ -224,7 +254,13 @@ namespace Discord | |||||
| changeNickname: changeNickname, | changeNickname: changeNickname, | ||||
| manageNicknames: manageNicknames, | manageNicknames: manageNicknames, | ||||
| manageWebhooks: manageWebhooks, | manageWebhooks: manageWebhooks, | ||||
| manageEmojisAndStickers: manageEmojis) | |||||
| manageEmojisAndStickers: manageEmojisAndStickers, | |||||
| useSlashCommands: useSlashCommands, | |||||
| requestToSpeak: requestToSpeak, | |||||
| manageThreads: manageThreads, | |||||
| usePublicThreads: usePublicThreads, | |||||
| usePrivateThreads: usePrivateThreads, | |||||
| useExternalStickers: useExternalStickers) | |||||
| { } | { } | ||||
| /// <summary> Creates a new <see cref="GuildPermissions"/> from this one, changing the provided non-null permissions. </summary> | /// <summary> Creates a new <see cref="GuildPermissions"/> from this one, changing the provided non-null permissions. </summary> | ||||
| @@ -259,11 +295,18 @@ namespace Discord | |||||
| bool? manageNicknames = null, | bool? manageNicknames = null, | ||||
| bool? manageRoles = null, | bool? manageRoles = null, | ||||
| bool? manageWebhooks = null, | bool? manageWebhooks = null, | ||||
| bool? manageEmojis = null) | |||||
| bool? manageEmojisAndStickers = null, | |||||
| bool? useSlashCommands = null, | |||||
| bool? requestToSpeak = null, | |||||
| bool? manageThreads = null, | |||||
| bool? usePublicThreads = null, | |||||
| bool? usePrivateThreads = null, | |||||
| bool? useExternalStickers = null) | |||||
| => new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions, | => new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions, | ||||
| viewAuditLog, viewGuildInsights, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, | viewAuditLog, viewGuildInsights, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, | ||||
| readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers, | readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers, | ||||
| useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis); | |||||
| useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojisAndStickers, | |||||
| useSlashCommands, requestToSpeak, manageThreads, usePublicThreads, usePrivateThreads, useExternalStickers); | |||||
| /// <summary> | /// <summary> | ||||
| /// Returns a value that indicates if a specific <see cref="GuildPermission"/> is enabled | /// Returns a value that indicates if a specific <see cref="GuildPermission"/> is enabled | ||||
| @@ -10,68 +10,70 @@ namespace Discord | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| public struct Color | public struct Color | ||||
| { | { | ||||
| /// <summary> Gets the max decimal value of color. </summary> | |||||
| public const uint MaxDecimalValue = 0xFFFFFF; | |||||
| /// <summary> Gets the default user color value. </summary> | /// <summary> Gets the default user color value. </summary> | ||||
| public static readonly Color Default = new Color(0); | |||||
| public static readonly Color Default = new(0); | |||||
| /// <summary> Gets the teal color value. </summary> | /// <summary> Gets the teal color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/1ABC9C">1ABC9C</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/1ABC9C">1ABC9C</see>.</returns> | ||||
| public static readonly Color Teal = new Color(0x1ABC9C); | |||||
| public static readonly Color Teal = new(0x1ABC9C); | |||||
| /// <summary> Gets the dark teal color value. </summary> | /// <summary> Gets the dark teal color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/11806A">11806A</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/11806A">11806A</see>.</returns> | ||||
| public static readonly Color DarkTeal = new Color(0x11806A); | |||||
| public static readonly Color DarkTeal = new(0x11806A); | |||||
| /// <summary> Gets the green color value. </summary> | /// <summary> Gets the green color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/2ECC71">2ECC71</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/2ECC71">2ECC71</see>.</returns> | ||||
| public static readonly Color Green = new Color(0x2ECC71); | |||||
| public static readonly Color Green = new(0x2ECC71); | |||||
| /// <summary> Gets the dark green color value. </summary> | /// <summary> Gets the dark green color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/1F8B4C">1F8B4C</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/1F8B4C">1F8B4C</see>.</returns> | ||||
| public static readonly Color DarkGreen = new Color(0x1F8B4C); | |||||
| public static readonly Color DarkGreen = new(0x1F8B4C); | |||||
| /// <summary> Gets the blue color value. </summary> | /// <summary> Gets the blue color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/3498DB">3498DB</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/3498DB">3498DB</see>.</returns> | ||||
| public static readonly Color Blue = new Color(0x3498DB); | |||||
| public static readonly Color Blue = new(0x3498DB); | |||||
| /// <summary> Gets the dark blue color value. </summary> | /// <summary> Gets the dark blue color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/206694">206694</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/206694">206694</see>.</returns> | ||||
| public static readonly Color DarkBlue = new Color(0x206694); | |||||
| public static readonly Color DarkBlue = new(0x206694); | |||||
| /// <summary> Gets the purple color value. </summary> | /// <summary> Gets the purple color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/9B59B6">9B59B6</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/9B59B6">9B59B6</see>.</returns> | ||||
| public static readonly Color Purple = new Color(0x9B59B6); | |||||
| public static readonly Color Purple = new(0x9B59B6); | |||||
| /// <summary> Gets the dark purple color value. </summary> | /// <summary> Gets the dark purple color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/71368A">71368A</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/71368A">71368A</see>.</returns> | ||||
| public static readonly Color DarkPurple = new Color(0x71368A); | |||||
| public static readonly Color DarkPurple = new(0x71368A); | |||||
| /// <summary> Gets the magenta color value. </summary> | /// <summary> Gets the magenta color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E91E63">E91E63</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E91E63">E91E63</see>.</returns> | ||||
| public static readonly Color Magenta = new Color(0xE91E63); | |||||
| public static readonly Color Magenta = new(0xE91E63); | |||||
| /// <summary> Gets the dark magenta color value. </summary> | /// <summary> Gets the dark magenta color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/AD1457">AD1457</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/AD1457">AD1457</see>.</returns> | ||||
| public static readonly Color DarkMagenta = new Color(0xAD1457); | |||||
| public static readonly Color DarkMagenta = new(0xAD1457); | |||||
| /// <summary> Gets the gold color value. </summary> | /// <summary> Gets the gold color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/F1C40F">F1C40F</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/F1C40F">F1C40F</see>.</returns> | ||||
| public static readonly Color Gold = new Color(0xF1C40F); | |||||
| public static readonly Color Gold = new(0xF1C40F); | |||||
| /// <summary> Gets the light orange color value. </summary> | /// <summary> Gets the light orange color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/C27C0E">C27C0E</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/C27C0E">C27C0E</see>.</returns> | ||||
| public static readonly Color LightOrange = new Color(0xC27C0E); | |||||
| public static readonly Color LightOrange = new(0xC27C0E); | |||||
| /// <summary> Gets the orange color value. </summary> | /// <summary> Gets the orange color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E67E22">E67E22</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E67E22">E67E22</see>.</returns> | ||||
| public static readonly Color Orange = new Color(0xE67E22); | |||||
| public static readonly Color Orange = new(0xE67E22); | |||||
| /// <summary> Gets the dark orange color value. </summary> | /// <summary> Gets the dark orange color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/A84300">A84300</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/A84300">A84300</see>.</returns> | ||||
| public static readonly Color DarkOrange = new Color(0xA84300); | |||||
| public static readonly Color DarkOrange = new(0xA84300); | |||||
| /// <summary> Gets the red color value. </summary> | /// <summary> Gets the red color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E74C3C">E74C3C</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E74C3C">E74C3C</see>.</returns> | ||||
| public static readonly Color Red = new Color(0xE74C3C); | |||||
| public static readonly Color Red = new(0xE74C3C); | |||||
| /// <summary> Gets the dark red color value. </summary> | /// <summary> Gets the dark red color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/992D22">992D22</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/992D22">992D22</see>.</returns> | ||||
| public static readonly Color DarkRed = new Color(0x992D22); | |||||
| public static readonly Color DarkRed = new(0x992D22); | |||||
| /// <summary> Gets the light grey color value. </summary> | /// <summary> Gets the light grey color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/979C9F">979C9F</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/979C9F">979C9F</see>.</returns> | ||||
| public static readonly Color LightGrey = new Color(0x979C9F); | |||||
| public static readonly Color LightGrey = new(0x979C9F); | |||||
| /// <summary> Gets the lighter grey color value. </summary> | /// <summary> Gets the lighter grey color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/95A5A6">95A5A6</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/95A5A6">95A5A6</see>.</returns> | ||||
| public static readonly Color LighterGrey = new Color(0x95A5A6); | |||||
| public static readonly Color LighterGrey = new(0x95A5A6); | |||||
| /// <summary> Gets the dark grey color value. </summary> | /// <summary> Gets the dark grey color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/607D8B">607D8B</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/607D8B">607D8B</see>.</returns> | ||||
| public static readonly Color DarkGrey = new Color(0x607D8B); | |||||
| public static readonly Color DarkGrey = new(0x607D8B); | |||||
| /// <summary> Gets the darker grey color value. </summary> | /// <summary> Gets the darker grey color value. </summary> | ||||
| /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/546E7A">546E7A</see>.</returns> | /// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/546E7A">546E7A</see>.</returns> | ||||
| public static readonly Color DarkerGrey = new Color(0x546E7A); | |||||
| public static readonly Color DarkerGrey = new(0x546E7A); | |||||
| /// <summary> Gets the encoded value for this color. </summary> | /// <summary> Gets the encoded value for this color. </summary> | ||||
| /// <remarks> | /// <remarks> | ||||
| @@ -91,22 +93,27 @@ namespace Discord | |||||
| /// Initializes a <see cref="Color"/> struct with the given raw value. | /// Initializes a <see cref="Color"/> struct with the given raw value. | ||||
| /// </summary> | /// </summary> | ||||
| /// <example> | /// <example> | ||||
| /// The following will create a color that has a hex value of | |||||
| /// The following will create a color that has a hex value of | |||||
| /// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | /// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | ||||
| /// <code language="cs"> | /// <code language="cs"> | ||||
| /// Color darkGrey = new Color(0x607D8B); | /// Color darkGrey = new Color(0x607D8B); | ||||
| /// </code> | /// </code> | ||||
| /// </example> | /// </example> | ||||
| /// <param name="rawValue">The raw value of the color (e.g. <c>0x607D8B</c>).</param> | /// <param name="rawValue">The raw value of the color (e.g. <c>0x607D8B</c>).</param> | ||||
| /// <exception cref="ArgumentException">Value exceeds <see cref="MaxDecimalValue"/>.</exception> | |||||
| public Color(uint rawValue) | public Color(uint rawValue) | ||||
| { | { | ||||
| if (rawValue > MaxDecimalValue) | |||||
| throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!", nameof(rawValue)); | |||||
| RawValue = rawValue; | RawValue = rawValue; | ||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Initializes a <see cref="Color" /> struct with the given RGB bytes. | /// Initializes a <see cref="Color" /> struct with the given RGB bytes. | ||||
| /// </summary> | /// </summary> | ||||
| /// <example> | /// <example> | ||||
| /// The following will create a color that has a value of | |||||
| /// The following will create a color that has a value of | |||||
| /// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | /// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | ||||
| /// <code language="cs"> | /// <code language="cs"> | ||||
| /// Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); | /// Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); | ||||
| @@ -115,19 +122,24 @@ namespace Discord | |||||
| /// <param name="r">The byte that represents the red color.</param> | /// <param name="r">The byte that represents the red color.</param> | ||||
| /// <param name="g">The byte that represents the green color.</param> | /// <param name="g">The byte that represents the green color.</param> | ||||
| /// <param name="b">The byte that represents the blue color.</param> | /// <param name="b">The byte that represents the blue color.</param> | ||||
| /// <exception cref="ArgumentException">Value exceeds <see cref="MaxDecimalValue"/>.</exception> | |||||
| public Color(byte r, byte g, byte b) | public Color(byte r, byte g, byte b) | ||||
| { | { | ||||
| RawValue = | |||||
| ((uint)r << 16) | | |||||
| ((uint)g << 8) | | |||||
| (uint)b; | |||||
| uint value = ((uint)r << 16) | |||||
| | ((uint)g << 8) | |||||
| | (uint)b; | |||||
| if (value > MaxDecimalValue) | |||||
| throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!"); | |||||
| RawValue = value; | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Initializes a <see cref="Color"/> struct with the given RGB value. | /// Initializes a <see cref="Color"/> struct with the given RGB value. | ||||
| /// </summary> | /// </summary> | ||||
| /// <example> | /// <example> | ||||
| /// The following will create a color that has a value of | |||||
| /// The following will create a color that has a value of | |||||
| /// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | /// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>. | ||||
| /// <code language="cs"> | /// <code language="cs"> | ||||
| /// Color darkGrey = new Color(96, 125, 139); | /// Color darkGrey = new Color(96, 125, 139); | ||||
| @@ -145,16 +157,15 @@ namespace Discord | |||||
| throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255]."); | throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255]."); | ||||
| if (b < 0 || b > 255) | if (b < 0 || b > 255) | ||||
| throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255]."); | throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255]."); | ||||
| RawValue = | |||||
| ((uint)r << 16) | | |||||
| ((uint)g << 8) | | |||||
| (uint)b; | |||||
| RawValue = ((uint)r << 16) | |||||
| | ((uint)g << 8) | |||||
| | (uint)b; | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Initializes a <see cref="Color"/> struct with the given RGB float value. | /// Initializes a <see cref="Color"/> struct with the given RGB float value. | ||||
| /// </summary> | /// </summary> | ||||
| /// <example> | /// <example> | ||||
| /// The following will create a color that has a value of | |||||
| /// The following will create a color that has a value of | |||||
| /// <see href="http://www.color-hex.com/color/607c8c">#607c8c</see>. | /// <see href="http://www.color-hex.com/color/607c8c">#607c8c</see>. | ||||
| /// <code language="cs"> | /// <code language="cs"> | ||||
| /// Color darkGrey = new Color(0.38f, 0.49f, 0.55f); | /// Color darkGrey = new Color(0.38f, 0.49f, 0.55f); | ||||
| @@ -172,10 +183,9 @@ namespace Discord | |||||
| throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1]."); | throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1]."); | ||||
| if (b < 0.0f || b > 1.0f) | if (b < 0.0f || b > 1.0f) | ||||
| throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1]."); | throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1]."); | ||||
| RawValue = | |||||
| ((uint)(r * 255.0f) << 16) | | |||||
| ((uint)(g * 255.0f) << 8) | | |||||
| (uint)(b * 255.0f); | |||||
| RawValue = ((uint)(r * 255.0f) << 16) | |||||
| | ((uint)(g * 255.0f) << 8) | |||||
| | (uint)(b * 255.0f); | |||||
| } | } | ||||
| public static bool operator ==(Color lhs, Color rhs) | public static bool operator ==(Color lhs, Color rhs) | ||||
| @@ -184,15 +194,22 @@ namespace Discord | |||||
| public static bool operator !=(Color lhs, Color rhs) | public static bool operator !=(Color lhs, Color rhs) | ||||
| => lhs.RawValue != rhs.RawValue; | => lhs.RawValue != rhs.RawValue; | ||||
| public static implicit operator Color(uint rawValue) | |||||
| => new(rawValue); | |||||
| public static implicit operator uint(Color color) | |||||
| => color.RawValue; | |||||
| public override bool Equals(object obj) | public override bool Equals(object obj) | ||||
| => (obj is Color c && RawValue == c.RawValue); | |||||
| => obj is Color c && RawValue == c.RawValue; | |||||
| public override int GetHashCode() => RawValue.GetHashCode(); | public override int GetHashCode() => RawValue.GetHashCode(); | ||||
| public static implicit operator StandardColor(Color color) => | |||||
| StandardColor.FromArgb((int)color.RawValue); | |||||
| public static explicit operator Color(StandardColor color) => | |||||
| new Color((uint)color.ToArgb() << 8 >> 8); | |||||
| public static implicit operator StandardColor(Color color) | |||||
| => StandardColor.FromArgb((int)color.RawValue); | |||||
| public static explicit operator Color(StandardColor color) | |||||
| => new((uint)color.ToArgb() << 8 >> 8); | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets the hexadecimal representation of the color (e.g. <c>#000ccc</c>). | /// Gets the hexadecimal representation of the color (e.g. <c>#000ccc</c>). | ||||
| @@ -12,17 +12,29 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| string AvatarId { get; } | string AvatarId { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the identifier of this user's banner. | |||||
| /// </summary> | |||||
| string BannerId { get; } | |||||
| /// <summary> | |||||
| /// Gets the user's banner color. | |||||
| /// </summary> | |||||
| /// <returns> | |||||
| /// A <see cref="Color"/> struct representing the accent color of this user's banner. | |||||
| /// </returns> | |||||
| Color? AccentColor { get; } | |||||
| /// <summary> | |||||
| /// Gets the avatar URL for this user. | /// Gets the avatar URL for this user. | ||||
| /// </summary> | /// </summary> | ||||
| /// <remarks> | /// <remarks> | ||||
| /// This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar | /// This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar | ||||
| /// (i.e. their avatar identifier is not set), this property will return <c>null</c>. If you wish to | |||||
| /// (i.e. their avatar identifier is not set), this method will return <c>null</c>. If you wish to | |||||
| /// retrieve the default avatar for this user, consider using <see cref="IUser.GetDefaultAvatarUrl"/> (see | /// retrieve the default avatar for this user, consider using <see cref="IUser.GetDefaultAvatarUrl"/> (see | ||||
| /// example). | /// example). | ||||
| /// </remarks> | /// </remarks> | ||||
| /// <example> | /// <example> | ||||
| /// <para>The following example attempts to retrieve the user's current avatar and send it to a channel; if one is | |||||
| /// not set, a default avatar for this user will be returned instead.</para> | |||||
| /// <para | |||||
| /// >The following example attempts to retrieve the user's current avatar and send it to a channel; if one is | |||||
| /// not set, a default avatar for this user will be returned instead.</para> | |||||
| /// <code language="cs" region="GetAvatarUrl" | /// <code language="cs" region="GetAvatarUrl" | ||||
| /// source="..\..\..\Discord.Net.Examples\Core\Entities\Users\IUser.Examples.cs"/> | /// source="..\..\..\Discord.Net.Examples\Core\Entities\Users\IUser.Examples.cs"/> | ||||
| /// </example> | /// </example> | ||||
| @@ -34,6 +46,16 @@ namespace Discord | |||||
| /// </returns> | /// </returns> | ||||
| string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); | string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the banner URL for this user. | |||||
| /// </summary> | |||||
| /// <param name="format">The format to return.</param> | |||||
| /// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048. | |||||
| /// </param> | |||||
| /// <returns> | |||||
| /// A string representing the user's avatar URL; <c>null</c> if the user does not have an banner in place. | |||||
| /// </returns> | |||||
| string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256); | |||||
| /// <summary> | |||||
| /// Gets the default avatar URL for this user. | /// Gets the default avatar URL for this user. | ||||
| /// </summary> | /// </summary> | ||||
| /// <remarks> | /// <remarks> | ||||
| @@ -93,8 +115,8 @@ namespace Discord | |||||
| /// This method is used to obtain or create a channel used to send a direct message. | /// This method is used to obtain or create a channel used to send a direct message. | ||||
| /// <note type="warning"> | /// <note type="warning"> | ||||
| /// In event that the current user cannot send a message to the target user, a channel can and will | /// In event that the current user cannot send a message to the target user, a channel can and will | ||||
| /// still be created by Discord. However, attempting to send a message will yield a | |||||
| /// <see cref="Discord.Net.HttpException"/> with a 403 as its | |||||
| /// still be created by Discord. However, attempting to send a message will yield a | |||||
| /// <see cref="Discord.Net.HttpException"/> with a 403 as its | |||||
| /// <see cref="Discord.Net.HttpException.HttpCode"/>. There are currently no official workarounds by | /// <see cref="Discord.Net.HttpException.HttpCode"/>. There are currently no official workarounds by | ||||
| /// Discord. | /// Discord. | ||||
| /// </note> | /// </note> | ||||
| @@ -1,3 +1,5 @@ | |||||
| using System; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -62,5 +64,9 @@ namespace Discord | |||||
| /// <c>true</c> if the user is streaming; otherwise <c>false</c>. | /// <c>true</c> if the user is streaming; otherwise <c>false</c>. | ||||
| /// </returns> | /// </returns> | ||||
| bool IsStreaming { get; } | bool IsStreaming { get; } | ||||
| /// <summary> | |||||
| /// Gets the time on which the user requested to speak. | |||||
| /// </summary> | |||||
| DateTimeOffset? RequestToSpeakTimestamp { get; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,4 @@ | |||||
| using System; | |||||
| using System; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| namespace Discord | namespace Discord | ||||
| @@ -49,6 +49,11 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| IUser Creator { get; } | IUser Creator { get; } | ||||
| /// <summary> | |||||
| /// Gets the ID of the application owning this webhook. | |||||
| /// </summary> | |||||
| ulong? ApplicationId { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Modifies this webhook. | /// Modifies this webhook. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -41,6 +41,8 @@ namespace Discord.API | |||||
| public Optional<Emoji> Emoji { get; set; } | public Optional<Emoji> Emoji { get; set; } | ||||
| [JsonProperty("created_at")] | [JsonProperty("created_at")] | ||||
| public Optional<long> CreatedAt { get; set; } | public Optional<long> CreatedAt { get; set; } | ||||
| //[JsonProperty("buttons")] | |||||
| //public Optional<RichPresenceButton[]> Buttons { get; set; } | |||||
| [OnError] | [OnError] | ||||
| internal void OnError(StreamingContext context, ErrorContext errorContext) | internal void OnError(StreamingContext context, ErrorContext errorContext) | ||||
| @@ -78,5 +78,7 @@ namespace Discord.API | |||||
| public Optional<int> ApproximatePresenceCount { get; set; } | public Optional<int> ApproximatePresenceCount { get; set; } | ||||
| [JsonProperty("threads")] | [JsonProperty("threads")] | ||||
| public Optional<Channel[]> Threads { get; set; } | public Optional<Channel[]> Threads { get; set; } | ||||
| [JsonProperty("nsfw_level")] | |||||
| public NsfwLevel NsfwLevel { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -18,7 +18,7 @@ namespace Discord.API | |||||
| // New flags prop. this make the response "ephemeral". see https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionapplicationcommandcallbackdata | // New flags prop. this make the response "ephemeral". see https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionapplicationcommandcallbackdata | ||||
| [JsonProperty("flags")] | [JsonProperty("flags")] | ||||
| public Optional<int> Flags { get; set; } | |||||
| public Optional<MessageFlags> Flags { get; set; } | |||||
| [JsonProperty("components")] | [JsonProperty("components")] | ||||
| public Optional<API.ActionRowComponent[]> Components { get; set; } | public Optional<API.ActionRowComponent[]> Components { get; set; } | ||||
| @@ -0,0 +1,30 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.API | |||||
| { | |||||
| internal class StageInstance | |||||
| { | |||||
| [JsonProperty("id")] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("guild_id")] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("channel_id")] | |||||
| public ulong ChannelId { get; set; } | |||||
| [JsonProperty("topic")] | |||||
| public string Topic { get; set; } | |||||
| [JsonProperty("privacy_level")] | |||||
| public StagePrivacyLevel PrivacyLevel { get; set; } | |||||
| [JsonProperty("discoverable_disabled")] | |||||
| public bool DiscoverableDisabled { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -15,6 +15,10 @@ namespace Discord.API | |||||
| public Optional<bool> Bot { get; set; } | public Optional<bool> Bot { get; set; } | ||||
| [JsonProperty("avatar")] | [JsonProperty("avatar")] | ||||
| public Optional<string> Avatar { get; set; } | public Optional<string> Avatar { get; set; } | ||||
| [JsonProperty("banner")] | |||||
| public Optional<string> Banner { get; set; } | |||||
| [JsonProperty("accent_color")] | |||||
| public Optional<uint?> AccentColor { get; set; } | |||||
| //CurrentUser | //CurrentUser | ||||
| [JsonProperty("verified")] | [JsonProperty("verified")] | ||||
| @@ -1,5 +1,6 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| @@ -28,5 +29,7 @@ namespace Discord.API | |||||
| public bool Suppress { get; set; } | public bool Suppress { get; set; } | ||||
| [JsonProperty("self_stream")] | [JsonProperty("self_stream")] | ||||
| public bool SelfStream { get; set; } | public bool SelfStream { get; set; } | ||||
| [JsonProperty("request_to_speak_timestamp")] | |||||
| public Optional<DateTimeOffset?> RequestToSpeakTimestamp { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -21,5 +21,7 @@ namespace Discord.API | |||||
| [JsonProperty("user")] | [JsonProperty("user")] | ||||
| public Optional<User> Creator { get; set; } | public Optional<User> Creator { get; set; } | ||||
| [JsonProperty("application_id")] | |||||
| public ulong? ApplicationId { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,21 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.API.Rest | |||||
| { | |||||
| internal class CreateStageInstanceParams | |||||
| { | |||||
| [JsonProperty("channel_id")] | |||||
| public ulong ChannelId { get; set; } | |||||
| [JsonProperty("topic")] | |||||
| public string Topic { get; set; } | |||||
| [JsonProperty("privacy_level")] | |||||
| public Optional<StagePrivacyLevel> PrivacyLevel { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -28,7 +28,7 @@ namespace Discord.API.Rest | |||||
| public Optional<AllowedMentions> AllowedMentions { get; set; } | public Optional<AllowedMentions> AllowedMentions { get; set; } | ||||
| [JsonProperty("flags")] | [JsonProperty("flags")] | ||||
| public Optional<int> Flags { get; set; } | |||||
| public Optional<MessageFlags> Flags { get; set; } | |||||
| [JsonProperty("components")] | [JsonProperty("components")] | ||||
| public Optional<API.ActionRowComponent[]> Components { get; set; } | public Optional<API.ActionRowComponent[]> Components { get; set; } | ||||
| @@ -0,0 +1,19 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.API.Rest | |||||
| { | |||||
| internal class ModifyStageInstanceParams | |||||
| { | |||||
| [JsonProperty("topic")] | |||||
| public Optional<string> Topic { get; set; } | |||||
| [JsonProperty("privacy_level")] | |||||
| public Optional<StagePrivacyLevel> PrivacyLevel { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| namespace Discord.API.Rest | |||||
| { | |||||
| internal class ModifyVoiceStateParams | |||||
| { | |||||
| [JsonProperty("channel_id")] | |||||
| public ulong ChannelId { get; set; } | |||||
| [JsonProperty("suppress")] | |||||
| public Optional<bool> Suppressed { get; set; } | |||||
| [JsonProperty("request_to_speak_timestamp")] | |||||
| public Optional<DateTimeOffset> RequestToSpeakTimestamp { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -12,5 +12,7 @@ namespace Discord.API.Rest | |||||
| public Optional<Embed[]> Embeds { get; set; } | public Optional<Embed[]> Embeds { get; set; } | ||||
| [JsonProperty("allowed_mentions")] | [JsonProperty("allowed_mentions")] | ||||
| public Optional<AllowedMentions> AllowedMentions { get; set; } | public Optional<AllowedMentions> AllowedMentions { get; set; } | ||||
| [JsonProperty("components")] | |||||
| public Optional<API.ActionRowComponent[]> Components { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,11 +9,11 @@ | |||||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | ||||
| <PackageIcon>Temporary.png</PackageIcon> | <PackageIcon>Temporary.png</PackageIcon> | ||||
| <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | ||||
| <Version>2.4.6</Version> | |||||
| <Version>3.0.1-pre</Version> | |||||
| <PackageId>Discord.Net.Labs.Rest</PackageId> | <PackageId>Discord.Net.Labs.Rest</PackageId> | ||||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | ||||
| <AssemblyVersion>2.3.4</AssemblyVersion> | |||||
| <FileVersion>2.3.4</FileVersion> | |||||
| <AssemblyVersion>3.0.1</AssemblyVersion> | |||||
| <FileVersion>3.0.1</FileVersion> | |||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup> | <PropertyGroup> | ||||
| <DocumentationFile>..\Discord.Net.Rest\Discord.Net.Rest.xml</DocumentationFile> | <DocumentationFile>..\Discord.Net.Rest\Discord.Net.Rest.xml</DocumentationFile> | ||||
| @@ -2281,6 +2281,50 @@ | |||||
| Represents a REST-based news channel in a guild that has the same properties as a <see cref="T:Discord.Rest.RestTextChannel"/>. | Represents a REST-based news channel in a guild that has the same properties as a <see cref="T:Discord.Rest.RestTextChannel"/>. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="T:Discord.Rest.RestStageChannel"> | |||||
| <summary> | |||||
| Represents a REST-based stage channel in a guild. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestStageChannel.Topic"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestStageChannel.PrivacyLevel"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestStageChannel.DiscoverableDisabled"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestStageChannel.Live"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.ModifyInstanceAsync(System.Action{Discord.StageInstanceProperties},Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.StartStageAsync(System.String,Discord.StagePrivacyLevel,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.StopStageAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.UpdateAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.RequestToSpeak(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.BecomeSpeakerAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.StopSpeakingAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.MoveToSpeaker(Discord.IGuildUser,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestStageChannel.RemoveFromSpeaker(Discord.IGuildUser,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="T:Discord.Rest.RestTextChannel"> | <member name="T:Discord.Rest.RestTextChannel"> | ||||
| <summary> | <summary> | ||||
| Represents a REST-based channel in a guild that can send and receive messages. | Represents a REST-based channel in a guild that can send and receive messages. | ||||
| @@ -2896,6 +2940,9 @@ | |||||
| <member name="P:Discord.Rest.RestGuild.ApproximatePresenceCount"> | <member name="P:Discord.Rest.RestGuild.ApproximatePresenceCount"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestGuild.NsfwLevel"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestGuild.PreferredCulture"> | <member name="P:Discord.Rest.RestGuild.PreferredCulture"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -3085,6 +3132,27 @@ | |||||
| message channels found within this guild. | message channels found within this guild. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.GetThreadChannelAsync(System.UInt64,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a thread channel in this guild. | |||||
| </summary> | |||||
| <param name="id">The snowflake identifier for the thread channel.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains the thread channel associated | |||||
| with the specified <paramref name="id"/>; <see langword="null"/> if none is found. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.GetThreadChannelsAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a collection of all thread in this guild. | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| threads found within this guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.GetVoiceChannelAsync(System.UInt64,Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.GetVoiceChannelAsync(System.UInt64,Discord.RequestOptions)"> | ||||
| <summary> | <summary> | ||||
| Gets a voice channel in this guild. | Gets a voice channel in this guild. | ||||
| @@ -3106,6 +3174,28 @@ | |||||
| voice channels found within this guild. | voice channels found within this guild. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.GetStageChannelAsync(System.UInt64,Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a stage channel in this guild | |||||
| </summary> | |||||
| <param name="id">The snowflake identifier for the stage channel.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains the stage channel associated | |||||
| with the specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.GetStageChannelsAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets a collection of all stage channels in this guild. | |||||
| </summary> | |||||
| <param name="mode">The <see cref="T:Discord.CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| stage channels found within this guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.GetCategoryChannelsAsync(Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.GetCategoryChannelsAsync(Discord.RequestOptions)"> | ||||
| <summary> | <summary> | ||||
| Gets a collection of all category channels in this guild. | Gets a collection of all category channels in this guild. | ||||
| @@ -3403,6 +3493,16 @@ | |||||
| of webhooks found within the guild. | of webhooks found within the guild. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.GetApplicationCommandsAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Gets this guilds slash commands commands | |||||
| </summary> | |||||
| <param name="options">The options to be used when sending the request.</param> | |||||
| <returns> | |||||
| A task that represents the asynchronous get operation. The task result contains a read-only collection | |||||
| of application commands found within the guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.ToString"> | <member name="M:Discord.Rest.RestGuild.ToString"> | ||||
| <summary> | <summary> | ||||
| Returns the name of the guild. | Returns the name of the guild. | ||||
| @@ -3460,12 +3560,24 @@ | |||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetTextChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetTextChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetThreadChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetThreadChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetVoiceChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetVoiceChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetCategoriesAsync(Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetCategoriesAsync(Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetStageChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetStageChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetVoiceChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetVoiceChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -3548,6 +3660,9 @@ | |||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetWebhooksAsync(Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetWebhooksAsync(Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestGuild.Discord#IGuild#GetApplicationCommandsAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestGuildIntegration.Name"> | <member name="P:Discord.Rest.RestGuildIntegration.Name"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4335,6 +4450,9 @@ | |||||
| <member name="P:Discord.Rest.RestGroupUser.Discord#IVoiceState#IsStreaming"> | <member name="P:Discord.Rest.RestGroupUser.Discord#IVoiceState#IsStreaming"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestGroupUser.Discord#IVoiceState#RequestToSpeakTimestamp"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="T:Discord.Rest.RestGuildUser"> | <member name="T:Discord.Rest.RestGuildUser"> | ||||
| <summary> | <summary> | ||||
| Represents a REST-based guild user. | Represents a REST-based guild user. | ||||
| @@ -4426,6 +4544,9 @@ | |||||
| <member name="P:Discord.Rest.RestGuildUser.Discord#IVoiceState#IsStreaming"> | <member name="P:Discord.Rest.RestGuildUser.Discord#IVoiceState#IsStreaming"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestGuildUser.Discord#IVoiceState#RequestToSpeakTimestamp"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="T:Discord.Rest.RestSelfUser"> | <member name="T:Discord.Rest.RestSelfUser"> | ||||
| <summary> | <summary> | ||||
| Represents the logged-in REST-based user. | Represents the logged-in REST-based user. | ||||
| @@ -4462,7 +4583,7 @@ | |||||
| </member> | </member> | ||||
| <member name="T:Discord.Rest.RestThreadUser"> | <member name="T:Discord.Rest.RestThreadUser"> | ||||
| <summary> | <summary> | ||||
| Represents a thread user recieved over the REST api. | |||||
| Represents a thread user received over the REST api. | |||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestThreadUser.Thread"> | <member name="P:Discord.Rest.RestThreadUser.Thread"> | ||||
| @@ -4485,7 +4606,7 @@ | |||||
| Gets the guild user for this thread user. | Gets the guild user for this thread user. | ||||
| </summary> | </summary> | ||||
| <returns> | <returns> | ||||
| A task representing the asyncronous get operation. The task returns a | |||||
| A task representing the asynchronous get operation. The task returns a | |||||
| <see cref="T:Discord.IGuildUser"/> that represents the current thread user. | <see cref="T:Discord.IGuildUser"/> that represents the current thread user. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| @@ -4506,6 +4627,12 @@ | |||||
| <member name="P:Discord.Rest.RestUser.AvatarId"> | <member name="P:Discord.Rest.RestUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestUser.PublicFlags"> | <member name="P:Discord.Rest.RestUser.PublicFlags"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4548,6 +4675,9 @@ | |||||
| <member name="M:Discord.Rest.RestUser.GetAvatarUrl(Discord.ImageFormat,System.UInt16)"> | <member name="M:Discord.Rest.RestUser.GetAvatarUrl(Discord.ImageFormat,System.UInt16)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Rest.RestUser.GetBannerUrl(Discord.ImageFormat,System.UInt16)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.Rest.RestUser.GetDefaultAvatarUrl"> | <member name="M:Discord.Rest.RestUser.GetDefaultAvatarUrl"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4649,6 +4779,9 @@ | |||||
| <member name="P:Discord.Rest.RestWebhookUser.Discord#IVoiceState#IsStreaming"> | <member name="P:Discord.Rest.RestWebhookUser.Discord#IVoiceState#IsStreaming"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestWebhookUser.Discord#IVoiceState#RequestToSpeakTimestamp"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestWebhook.Token"> | <member name="P:Discord.Rest.RestWebhook.Token"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4667,6 +4800,9 @@ | |||||
| <member name="P:Discord.Rest.RestWebhook.Creator"> | <member name="P:Discord.Rest.RestWebhook.Creator"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Rest.RestWebhook.ApplicationId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.Rest.RestWebhook.CreatedAt"> | <member name="P:Discord.Rest.RestWebhook.CreatedAt"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -55,7 +55,7 @@ namespace Discord.API | |||||
| _restClientProvider = restClientProvider; | _restClientProvider = restClientProvider; | ||||
| UserAgent = userAgent; | UserAgent = userAgent; | ||||
| DefaultRetryMode = defaultRetryMode; | DefaultRetryMode = defaultRetryMode; | ||||
| _serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver(), NullValueHandling = NullValueHandling.Ignore }; | |||||
| _serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver(), NullValueHandling = NullValueHandling.Include }; | |||||
| UseSystemClock = useSystemClock; | UseSystemClock = useSystemClock; | ||||
| RequestQueue = new RequestQueue(); | RequestQueue = new RequestQueue(); | ||||
| @@ -442,7 +442,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var bucket = new BucketIds(0, channelId); | |||||
| var bucket = new BucketIds(channelId: channelId); | |||||
| return await SendJsonAsync<Channel>("POST", () => $"channels/{channelId}/threads", args, bucket, options: options).ConfigureAwait(false); | return await SendJsonAsync<Channel>("POST", () => $"channels/{channelId}/threads", args, bucket, options: options).ConfigureAwait(false); | ||||
| } | } | ||||
| @@ -453,7 +453,9 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| await SendAsync("PUT", $"channels/{channelId}/thread-members/@me", options: options).ConfigureAwait(false); | |||||
| var bucket = new BucketIds(channelId: channelId); | |||||
| await SendAsync("PUT", () => $"channels/{channelId}/thread-members/@me", bucket, options: options).ConfigureAwait(false); | |||||
| } | } | ||||
| public async Task AddThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) | public async Task AddThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) | ||||
| @@ -474,7 +476,9 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| await SendAsync("DELETE", $"channels/{channelId}/thread-members/@me", options: options).ConfigureAwait(false); | |||||
| var bucket = new BucketIds(channelId: channelId); | |||||
| await SendAsync("DELETE", () => $"channels/{channelId}/thread-members/@me", bucket, options: options).ConfigureAwait(false); | |||||
| } | } | ||||
| public async Task RemoveThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) | public async Task RemoveThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) | ||||
| @@ -483,8 +487,9 @@ namespace Discord.API | |||||
| Preconditions.NotEqual(userId, 0, nameof(channelId)); | Preconditions.NotEqual(userId, 0, nameof(channelId)); | ||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var bucket = new BucketIds(channelId: channelId); | |||||
| await SendAsync("DELETE", $"channels/{channelId}/thread-members/{userId}", options: options).ConfigureAwait(false); | |||||
| await SendAsync("DELETE", () => $"channels/{channelId}/thread-members/{userId}", bucket, options: options).ConfigureAwait(false); | |||||
| } | } | ||||
| public async Task<ThreadMember[]> ListThreadMembersAsync(ulong channelId, RequestOptions options = null) | public async Task<ThreadMember[]> ListThreadMembersAsync(ulong channelId, RequestOptions options = null) | ||||
| @@ -506,7 +511,7 @@ namespace Discord.API | |||||
| var bucket = new BucketIds(channelId: channelId); | var bucket = new BucketIds(channelId: channelId); | ||||
| return await SendAsync<ChannelThreads>("GET", $"channels/{channelId}/threads/active"); | |||||
| return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/threads/active", bucket); | |||||
| } | } | ||||
| public async Task<ChannelThreads> GetPublicArchivedThreadsAsync(ulong channelId, DateTimeOffset? before = null, int? limit = null, RequestOptions options = null) | public async Task<ChannelThreads> GetPublicArchivedThreadsAsync(ulong channelId, DateTimeOffset? before = null, int? limit = null, RequestOptions options = null) | ||||
| @@ -577,6 +582,82 @@ namespace Discord.API | |||||
| return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/users/@me/threads/archived/private{query}", bucket, options: options); | return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/users/@me/threads/archived/private{query}", bucket, options: options); | ||||
| } | } | ||||
| // stage | |||||
| public async Task<StageInstance> CreateStageInstanceAsync(CreateStageInstanceParams args, RequestOptions options = null) | |||||
| { | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| var bucket = new BucketIds(); | |||||
| return await SendJsonAsync<StageInstance>("POST", () => $"stage-instances", args, bucket, options: options).ConfigureAwait(false); | |||||
| } | |||||
| public async Task<StageInstance> ModifyStageInstanceAsync(ulong channelId, ModifyStageInstanceParams args, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| var bucket = new BucketIds(channelId: channelId); | |||||
| return await SendJsonAsync<StageInstance>("PATCH", () => $"stage-instances/{channelId}", args, bucket, options: options).ConfigureAwait(false); | |||||
| } | |||||
| public async Task DeleteStageInstanceAsync(ulong channelId, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| try | |||||
| { | |||||
| await SendAsync("DELETE", $"stage-instances/{channelId}", options: options).ConfigureAwait(false); | |||||
| } | |||||
| catch (HttpException httpEx) when (httpEx.HttpCode == HttpStatusCode.NotFound) { } | |||||
| } | |||||
| public async Task<StageInstance> GetStageInstanceAsync(ulong channelId, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| var bucket = new BucketIds(channelId: channelId); | |||||
| try | |||||
| { | |||||
| return await SendAsync<StageInstance>("POST", () => $"stage-instances/{channelId}", bucket, options: options).ConfigureAwait(false); | |||||
| } | |||||
| catch(HttpException httpEx) when (httpEx.HttpCode == HttpStatusCode.NotFound) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| public async Task ModifyMyVoiceState(ulong guildId, ModifyVoiceStateParams args, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| var bucket = new BucketIds(); | |||||
| await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/@me", args, bucket, options: options).ConfigureAwait(false); | |||||
| } | |||||
| public async Task ModifyUserVoiceState(ulong guildId, ulong userId, ModifyVoiceStateParams args, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
| Preconditions.NotEqual(userId, 0, nameof(userId)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| var bucket = new BucketIds(); | |||||
| await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/{userId}", args, bucket, options: options).ConfigureAwait(false); | |||||
| } | |||||
| // roles | // roles | ||||
| public async Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) | public async Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -6,6 +6,7 @@ using System.IO; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Model = Discord.API.Channel; | using Model = Discord.API.Channel; | ||||
| using StageInstance = Discord.API.StageInstance; | |||||
| namespace Discord.Rest | namespace Discord.Rest | ||||
| { | { | ||||
| @@ -92,6 +93,21 @@ namespace Discord.Rest | |||||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
| } | } | ||||
| public static async Task<StageInstance> ModifyAsync(IStageChannel channel, BaseDiscordClient client, | |||||
| Action<StageInstanceProperties> func, RequestOptions options = null) | |||||
| { | |||||
| var args = new StageInstanceProperties(); | |||||
| func(args); | |||||
| var apiArgs = new ModifyStageInstanceParams() | |||||
| { | |||||
| PrivacyLevel = args.PrivacyLevel, | |||||
| Topic = args.Topic | |||||
| }; | |||||
| return await client.ApiClient.ModifyStageInstanceAsync(channel.Id, apiArgs, options); | |||||
| } | |||||
| //Invites | //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) | ||||
| @@ -40,8 +40,12 @@ namespace Discord.Rest | |||||
| return RestTextChannel.Create(discord, guild, model); | return RestTextChannel.Create(discord, guild, model); | ||||
| case ChannelType.Voice: | case ChannelType.Voice: | ||||
| return RestVoiceChannel.Create(discord, guild, model); | return RestVoiceChannel.Create(discord, guild, model); | ||||
| case ChannelType.Stage: | |||||
| return RestStageChannel.Create(discord, guild, model); | |||||
| case ChannelType.Category: | case ChannelType.Category: | ||||
| return RestCategoryChannel.Create(discord, guild, model); | return RestCategoryChannel.Create(discord, guild, model); | ||||
| case ChannelType.PublicThread or ChannelType.PrivateThread or ChannelType.NewsThread: | |||||
| return RestThreadChannel.Create(discord, guild, model); | |||||
| default: | default: | ||||
| return new RestGuildChannel(discord, guild, model.Id); | return new RestGuildChannel(discord, guild, model.Id); | ||||
| } | } | ||||
| @@ -0,0 +1,155 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| using Model = Discord.API.Channel; | |||||
| using StageInstance = Discord.API.StageInstance; | |||||
| namespace Discord.Rest | |||||
| { | |||||
| /// <summary> | |||||
| /// Represents a REST-based stage channel in a guild. | |||||
| /// </summary> | |||||
| public class RestStageChannel : RestVoiceChannel, IStageChannel | |||||
| { | |||||
| /// <inheritdoc/> | |||||
| public string Topic { get; private set; } | |||||
| /// <inheritdoc/> | |||||
| public StagePrivacyLevel? PrivacyLevel { get; private set; } | |||||
| /// <inheritdoc/> | |||||
| public bool? DiscoverableDisabled { get; private set; } | |||||
| /// <inheritdoc/> | |||||
| public bool Live { get; private set; } | |||||
| internal RestStageChannel(BaseDiscordClient discord, IGuild guild, ulong id) | |||||
| : base(discord, guild, id) | |||||
| { | |||||
| } | |||||
| internal static new RestStageChannel Create(BaseDiscordClient discord, IGuild guild, Model model) | |||||
| { | |||||
| var entity = new RestStageChannel(discord, guild, model.Id); | |||||
| entity.Update(model); | |||||
| return entity; | |||||
| } | |||||
| internal void Update(StageInstance model, bool isLive = false) | |||||
| { | |||||
| this.Live = isLive; | |||||
| if(isLive) | |||||
| { | |||||
| this.Topic = model.Topic; | |||||
| this.PrivacyLevel = model.PrivacyLevel; | |||||
| this.DiscoverableDisabled = model.DiscoverableDisabled; | |||||
| } | |||||
| else | |||||
| { | |||||
| this.Topic = null; | |||||
| this.PrivacyLevel = null; | |||||
| this.DiscoverableDisabled = null; | |||||
| } | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public async Task ModifyInstanceAsync(Action<StageInstanceProperties> func, RequestOptions options = null) | |||||
| { | |||||
| var model = await ChannelHelper.ModifyAsync(this, Discord, func, options); | |||||
| Update(model, true); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public async Task StartStageAsync(string topic, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.CreateStageInstanceParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| PrivacyLevel = privacyLevel, | |||||
| Topic = topic | |||||
| }; | |||||
| var model = await Discord.ApiClient.CreateStageInstanceAsync(args, options); | |||||
| Update(model, true); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public async Task StopStageAsync(RequestOptions options = null) | |||||
| { | |||||
| await Discord.ApiClient.DeleteStageInstanceAsync(this.Id, options); | |||||
| Update(null, false); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public override async Task UpdateAsync(RequestOptions options = null) | |||||
| { | |||||
| await base.UpdateAsync(options); | |||||
| var model = await Discord.ApiClient.GetStageInstanceAsync(this.Id, options); | |||||
| Update(model, model != null); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task RequestToSpeak(RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| RequestToSpeakTimestamp = DateTimeOffset.UtcNow | |||||
| }; | |||||
| return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task BecomeSpeakerAsync(RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = false | |||||
| }; | |||||
| return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task StopSpeakingAsync(RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = true | |||||
| }; | |||||
| return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task MoveToSpeaker(IGuildUser user, RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = false | |||||
| }; | |||||
| return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task RemoveFromSpeaker(IGuildUser user, RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = true | |||||
| }; | |||||
| return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -19,6 +19,9 @@ namespace Discord.Rest | |||||
| if (autoArchiveDuration == ThreadArchiveDuration.ThreeDays && !channel.Guild.Features.Contains("THREE_DAY_THREAD_ARCHIVE")) | if (autoArchiveDuration == ThreadArchiveDuration.ThreeDays && !channel.Guild.Features.Contains("THREE_DAY_THREAD_ARCHIVE")) | ||||
| throw new ArgumentException($"The guild {channel.Guild.Name} does not have the THREE_DAY_THREAD_ARCHIVE feature!"); | throw new ArgumentException($"The guild {channel.Guild.Name} does not have the THREE_DAY_THREAD_ARCHIVE feature!"); | ||||
| if (type == ThreadType.PrivateThread && !channel.Guild.Features.Contains("PRIVATE_THREADS")) | |||||
| throw new ArgumentException($"The guild {channel.Guild.Name} does not have the PRIVATE_THREADS feature!"); | |||||
| var args = new StartThreadParams() | var args = new StartThreadParams() | ||||
| { | { | ||||
| Name = name, | Name = name, | ||||
| @@ -83,6 +83,8 @@ namespace Discord.Rest | |||||
| public int? ApproximateMemberCount { get; private set; } | public int? ApproximateMemberCount { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public int? ApproximatePresenceCount { get; private set; } | public int? ApproximatePresenceCount { get; private set; } | ||||
| /// <inheritdoc /> | |||||
| public NsfwLevel NsfwLevel { get; private set; } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public CultureInfo PreferredCulture { get; private set; } | public CultureInfo PreferredCulture { get; private set; } | ||||
| @@ -151,6 +153,7 @@ namespace Discord.Rest | |||||
| SystemChannelFlags = model.SystemChannelFlags; | SystemChannelFlags = model.SystemChannelFlags; | ||||
| Description = model.Description; | Description = model.Description; | ||||
| PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault(); | PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault(); | ||||
| NsfwLevel = model.NsfwLevel; | |||||
| if (model.MaxPresences.IsSpecified) | if (model.MaxPresences.IsSpecified) | ||||
| MaxPresences = model.MaxPresences.Value ?? 25000; | MaxPresences = model.MaxPresences.Value ?? 25000; | ||||
| if (model.MaxMembers.IsSpecified) | if (model.MaxMembers.IsSpecified) | ||||
| @@ -391,6 +394,35 @@ namespace Discord.Rest | |||||
| return channels.OfType<RestTextChannel>().ToImmutableArray(); | return channels.OfType<RestTextChannel>().ToImmutableArray(); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Gets a thread channel in this guild. | |||||
| /// </summary> | |||||
| /// <param name="id">The snowflake identifier for the thread channel.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains the thread channel associated | |||||
| /// with the specified <paramref name="id"/>; <see langword="null"/> if none is found. | |||||
| /// </returns> | |||||
| public async Task<RestThreadChannel> GetThreadChannelAsync(ulong id, RequestOptions options = null) | |||||
| { | |||||
| var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); | |||||
| return channel as RestThreadChannel; | |||||
| } | |||||
| /// <summary> | |||||
| /// Gets a collection of all thread in this guild. | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| /// threads found within this guild. | |||||
| /// </returns> | |||||
| public async Task<IReadOnlyCollection<RestThreadChannel>> GetThreadChannelsAsync(RequestOptions options = null) | |||||
| { | |||||
| var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | |||||
| return channels.OfType<RestThreadChannel>().ToImmutableArray(); | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets a voice channel in this guild. | /// Gets a voice channel in this guild. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -419,6 +451,35 @@ namespace Discord.Rest | |||||
| var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | ||||
| return channels.OfType<RestVoiceChannel>().ToImmutableArray(); | return channels.OfType<RestVoiceChannel>().ToImmutableArray(); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Gets a stage channel in this guild | |||||
| /// </summary> | |||||
| /// <param name="id">The snowflake identifier for the stage channel.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains the stage channel associated | |||||
| /// with the specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
| /// </returns> | |||||
| public async Task<RestStageChannel> GetStageChannelAsync(ulong id, RequestOptions options = null) | |||||
| { | |||||
| var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); | |||||
| return channel as RestStageChannel; | |||||
| } | |||||
| /// <summary> | |||||
| /// Gets a collection of all stage channels in this guild. | |||||
| /// </summary> | |||||
| /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains a read-only collection of | |||||
| /// stage channels found within this guild. | |||||
| /// </returns> | |||||
| public async Task<IReadOnlyCollection<RestStageChannel>> GetStageChannelsAsync(RequestOptions options = null) | |||||
| { | |||||
| var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | |||||
| return channels.OfType<RestStageChannel>().ToImmutableArray(); | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets a collection of all category channels in this guild. | /// Gets a collection of all category channels in this guild. | ||||
| @@ -808,6 +869,18 @@ namespace Discord.Rest | |||||
| public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) | public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) | ||||
| => GuildHelper.GetWebhooksAsync(this, Discord, options); | => GuildHelper.GetWebhooksAsync(this, Discord, options); | ||||
| //Interactions | |||||
| /// <summary> | |||||
| /// Gets this guilds slash commands commands | |||||
| /// </summary> | |||||
| /// <param name="options">The options to be used when sending the request.</param> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous get operation. The task result contains a read-only collection | |||||
| /// of application commands found within the guild. | |||||
| /// </returns> | |||||
| public async Task<IReadOnlyCollection<RestApplicationCommand>> GetApplicationCommandsAsync (RequestOptions options = null) | |||||
| => await ClientHelper.GetGuildApplicationCommands(Discord, Id, options).ConfigureAwait(false); | |||||
| /// <summary> | /// <summary> | ||||
| /// Returns the name of the guild. | /// Returns the name of the guild. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -888,6 +961,22 @@ namespace Discord.Rest | |||||
| return null; | return null; | ||||
| } | } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| async Task<IThreadChannel> IGuild.GetThreadChannelAsync(ulong id, CacheMode mode, RequestOptions options) | |||||
| { | |||||
| if (mode == CacheMode.AllowDownload) | |||||
| return await GetThreadChannelAsync(id, options).ConfigureAwait(false); | |||||
| else | |||||
| return null; | |||||
| } | |||||
| /// <inheritdoc /> | |||||
| async Task<IReadOnlyCollection<IThreadChannel>> IGuild.GetThreadChannelsAsync(CacheMode mode, RequestOptions options) | |||||
| { | |||||
| if (mode == CacheMode.AllowDownload) | |||||
| return await GetThreadChannelsAsync(options).ConfigureAwait(false); | |||||
| else | |||||
| return null; | |||||
| } | |||||
| /// <inheritdoc /> | |||||
| async Task<IReadOnlyCollection<IVoiceChannel>> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) | async Task<IReadOnlyCollection<IVoiceChannel>> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) | ||||
| { | { | ||||
| if (mode == CacheMode.AllowDownload) | if (mode == CacheMode.AllowDownload) | ||||
| @@ -904,6 +993,22 @@ namespace Discord.Rest | |||||
| return null; | return null; | ||||
| } | } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| async Task<IStageChannel> IGuild.GetStageChannelAsync(ulong id, CacheMode mode, RequestOptions options ) | |||||
| { | |||||
| if (mode == CacheMode.AllowDownload) | |||||
| return await GetStageChannelAsync(id, options).ConfigureAwait(false); | |||||
| else | |||||
| return null; | |||||
| } | |||||
| /// <inheritdoc /> | |||||
| async Task<IReadOnlyCollection<IStageChannel>> IGuild.GetStageChannelsAsync(CacheMode mode, RequestOptions options) | |||||
| { | |||||
| if (mode == CacheMode.AllowDownload) | |||||
| return await GetStageChannelsAsync(options).ConfigureAwait(false); | |||||
| else | |||||
| return null; | |||||
| } | |||||
| /// <inheritdoc /> | |||||
| async Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | async Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| { | { | ||||
| if (mode == CacheMode.AllowDownload) | if (mode == CacheMode.AllowDownload) | ||||
| @@ -1061,5 +1166,8 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| async Task<IReadOnlyCollection<IWebhook>> IGuild.GetWebhooksAsync(RequestOptions options) | async Task<IReadOnlyCollection<IWebhook>> IGuild.GetWebhooksAsync(RequestOptions options) | ||||
| => await GetWebhooksAsync(options).ConfigureAwait(false); | => await GetWebhooksAsync(options).ConfigureAwait(false); | ||||
| /// <inheritdoc /> | |||||
| async Task<IReadOnlyCollection<IApplicationCommand>> IGuild.GetApplicationCommandsAsync (RequestOptions options) | |||||
| => await GetApplicationCommandsAsync(options).ConfigureAwait(false); | |||||
| } | } | ||||
| } | } | ||||
| @@ -296,15 +296,33 @@ namespace Discord.Rest | |||||
| var args = new MessageProperties(); | var args = new MessageProperties(); | ||||
| func(args); | func(args); | ||||
| var embed = args.Embed; | |||||
| 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 hasEmbed = args.Embeds.IsSpecified ? args.Embeds.Value != null : message.Embeds.Any(); | |||||
| if (!hasText && !hasEmbed) | |||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || message.Embeds.Any(); | |||||
| 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)); | ||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | |||||
| if (embed.IsSpecified && embed.Value != null) | |||||
| { | |||||
| apiEmbeds.Add(embed.Value.ToModel()); | |||||
| } | |||||
| if (embeds.IsSpecified && embeds.Value != null) | |||||
| { | |||||
| apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); | |||||
| } | |||||
| Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||||
| var apiArgs = new API.Rest.ModifyInteractionResponseParams | var apiArgs = new API.Rest.ModifyInteractionResponseParams | ||||
| { | { | ||||
| Content = args.Content, | Content = args.Content, | ||||
| Embeds = args.Embeds.IsSpecified ? args.Embeds.Value.Select(x => x.ToModel()).ToArray() : Optional.Create<API.Embed[]>(), | |||||
| Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified, | |||||
| AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional<API.AllowedMentions>.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, | Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | ||||
| }; | }; | ||||
| @@ -321,10 +339,33 @@ namespace Discord.Rest | |||||
| var args = new MessageProperties(); | var args = new MessageProperties(); | ||||
| func(args); | func(args); | ||||
| var embed = args.Embed; | |||||
| var embeds = args.Embeds; | |||||
| bool hasText = !string.IsNullOrEmpty(args.Content.GetValueOrDefault()); | |||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0); | |||||
| if (!hasText && !hasEmbeds) | |||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | |||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | |||||
| if (embed.IsSpecified && embed.Value != null) | |||||
| { | |||||
| apiEmbeds.Add(embed.Value.ToModel()); | |||||
| } | |||||
| if (embeds.IsSpecified && embeds.Value != null) | |||||
| { | |||||
| apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); | |||||
| } | |||||
| Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||||
| var apiArgs = new ModifyInteractionResponseParams | var apiArgs = new ModifyInteractionResponseParams | ||||
| { | { | ||||
| Content = args.Content, | Content = args.Content, | ||||
| Embeds = args.Embeds.IsSpecified ? args.Embeds.Value?.Select(x => x.ToModel()).ToArray() : Optional<API.Embed[]>.Unspecified, | |||||
| Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified, | |||||
| AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.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, | Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | ||||
| Flags = args.Flags | Flags = args.Flags | ||||
| @@ -1,3 +1,4 @@ | |||||
| using Discord.API; | |||||
| using Discord.API.Rest; | using Discord.API.Rest; | ||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| @@ -33,9 +34,13 @@ namespace Discord.Rest | |||||
| if (msg.Author.Id != client.CurrentUser.Id && (args.Content.IsSpecified || args.Embeds.IsSpecified || args.AllowedMentions.IsSpecified)) | if (msg.Author.Id != client.CurrentUser.Id && (args.Content.IsSpecified || args.Embeds.IsSpecified || args.AllowedMentions.IsSpecified)) | ||||
| throw new InvalidOperationException("Only the author of a message may modify the message content, embed, or allowed mentions."); | throw new InvalidOperationException("Only the author of a message may modify the message content, embed, or allowed mentions."); | ||||
| var embed = args.Embed; | |||||
| 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 hasEmbed = args.Embeds.IsSpecified ? args.Embeds.Value != null : msg.Embeds.Any(); | |||||
| if (!hasText && !hasEmbed) | |||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || msg.Embeds.Any(); | |||||
| 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)); | ||||
| if (args.AllowedMentions.IsSpecified) | if (args.AllowedMentions.IsSpecified) | ||||
| @@ -61,10 +66,24 @@ namespace Discord.Rest | |||||
| } | } | ||||
| } | } | ||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | |||||
| if (embed.IsSpecified && embed.Value != null) | |||||
| { | |||||
| apiEmbeds.Add(embed.Value.ToModel()); | |||||
| } | |||||
| if (embeds.IsSpecified && embeds.Value != null) | |||||
| { | |||||
| apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); | |||||
| } | |||||
| Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||||
| var apiArgs = new ModifyMessageParams | var apiArgs = new ModifyMessageParams | ||||
| { | { | ||||
| Content = args.Content, | Content = args.Content, | ||||
| Embeds = args.Embeds.IsSpecified ? args.Embeds.Value.Select(x => x.ToModel()).ToArray() : Optional<API.Embed[]>.Unspecified, | |||||
| Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified, | |||||
| Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | ||||
| Flags = args.Flags, | Flags = args.Flags, | ||||
| AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional<API.AllowedMentions>.Unspecified, | AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional<API.AllowedMentions>.Unspecified, | ||||
| @@ -78,7 +97,13 @@ namespace Discord.Rest | |||||
| var args = new MessageProperties(); | var args = new MessageProperties(); | ||||
| func(args); | func(args); | ||||
| if (args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value) && args.Embeds.IsSpecified && args.Embeds.Value == null) | |||||
| var embed = args.Embed; | |||||
| var embeds = args.Embeds; | |||||
| bool hasText = args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value); | |||||
| bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0); | |||||
| 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)); | ||||
| if (args.AllowedMentions.IsSpecified) | if (args.AllowedMentions.IsSpecified) | ||||
| @@ -105,12 +130,27 @@ namespace Discord.Rest | |||||
| } | } | ||||
| } | } | ||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | |||||
| if (embed.IsSpecified && embed.Value != null) | |||||
| { | |||||
| apiEmbeds.Add(embed.Value.ToModel()); | |||||
| } | |||||
| if (embeds.IsSpecified && embeds.Value != null) | |||||
| { | |||||
| apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); | |||||
| } | |||||
| Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||||
| var apiArgs = new API.Rest.ModifyMessageParams | var apiArgs = new API.Rest.ModifyMessageParams | ||||
| { | { | ||||
| Content = args.Content, | Content = args.Content, | ||||
| Embeds = args.Embeds.IsSpecified ? args.Embeds.Value.Select(x => x.ToModel()).ToArray() : Optional.Create<API.Embed[]>(), | |||||
| Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified, | |||||
| Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create<MessageFlags?>(), | Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create<MessageFlags?>(), | ||||
| AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create<API.AllowedMentions>(), | AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create<API.AllowedMentions>(), | ||||
| Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | |||||
| }; | }; | ||||
| return await client.ApiClient.ModifyMessageAsync(channelId, msgId, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyMessageAsync(channelId, msgId, apiArgs, options).ConfigureAwait(false); | ||||
| } | } | ||||
| @@ -1,3 +1,4 @@ | |||||
| using System; | |||||
| using System.Diagnostics; | using System.Diagnostics; | ||||
| using Model = Discord.API.User; | using Model = Discord.API.User; | ||||
| @@ -37,5 +38,7 @@ namespace Discord.Rest | |||||
| string IVoiceState.VoiceSessionId => null; | string IVoiceState.VoiceSessionId => null; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
| /// <inheritdoc /> | |||||
| DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | |||||
| } | } | ||||
| } | } | ||||
| @@ -169,5 +169,7 @@ namespace Discord.Rest | |||||
| string IVoiceState.VoiceSessionId => null; | string IVoiceState.VoiceSessionId => null; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
| /// <inheritdoc /> | |||||
| DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,7 +9,7 @@ using Model = Discord.API.ThreadMember; | |||||
| namespace Discord.Rest | namespace Discord.Rest | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Represents a thread user recieved over the REST api. | |||||
| /// Represents a thread user received over the REST api. | |||||
| /// </summary> | /// </summary> | ||||
| public class RestThreadUser : RestEntity<ulong> | public class RestThreadUser : RestEntity<ulong> | ||||
| { | { | ||||
| @@ -51,7 +51,7 @@ namespace Discord.Rest | |||||
| /// Gets the guild user for this thread user. | /// Gets the guild user for this thread user. | ||||
| /// </summary> | /// </summary> | ||||
| /// <returns> | /// <returns> | ||||
| /// A task representing the asyncronous get operation. The task returns a | |||||
| /// A task representing the asynchronous get operation. The task returns a | |||||
| /// <see cref="IGuildUser"/> that represents the current thread user. | /// <see cref="IGuildUser"/> that represents the current thread user. | ||||
| /// </returns> | /// </returns> | ||||
| public Task<IGuildUser> GetGuildUser() | public Task<IGuildUser> GetGuildUser() | ||||
| @@ -22,6 +22,10 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string AvatarId { get; private set; } | public string AvatarId { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string BannerId { get; private set; } | |||||
| /// <inheritdoc /> | |||||
| public Color? AccentColor { get; private set; } | |||||
| /// <inheritdoc /> | |||||
| public UserProperties? PublicFlags { get; private set; } | public UserProperties? PublicFlags { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -61,6 +65,10 @@ namespace Discord.Rest | |||||
| { | { | ||||
| if (model.Avatar.IsSpecified) | if (model.Avatar.IsSpecified) | ||||
| AvatarId = model.Avatar.Value; | AvatarId = model.Avatar.Value; | ||||
| if (model.Banner.IsSpecified) | |||||
| BannerId = model.Banner.Value; | |||||
| if (model.AccentColor.IsSpecified) | |||||
| AccentColor = model.AccentColor.Value; | |||||
| if (model.Discriminator.IsSpecified) | if (model.Discriminator.IsSpecified) | ||||
| DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); | DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); | ||||
| if (model.Bot.IsSpecified) | if (model.Bot.IsSpecified) | ||||
| @@ -92,6 +100,10 @@ namespace Discord.Rest | |||||
| public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | ||||
| => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); | => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); | ||||
| /// <inheritdoc /> | |||||
| public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) | |||||
| => CDN.GetUserBannerUrl(Id, BannerId, size, format); | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string GetDefaultAvatarUrl() | public string GetDefaultAvatarUrl() | ||||
| => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); | => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); | ||||
| @@ -107,5 +107,7 @@ namespace Discord.Rest | |||||
| string IVoiceState.VoiceSessionId => null; | string IVoiceState.VoiceSessionId => null; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
| /// <inheritdoc /> | |||||
| DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | |||||
| } | } | ||||
| } | } | ||||
| @@ -24,6 +24,8 @@ namespace Discord.Rest | |||||
| public ulong? GuildId { get; private set; } | public ulong? GuildId { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public IUser Creator { get; private set; } | public IUser Creator { get; private set; } | ||||
| /// <inheritdoc /> | |||||
| public ulong? ApplicationId { get; private set; } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | ||||
| @@ -66,6 +68,8 @@ namespace Discord.Rest | |||||
| GuildId = model.GuildId.Value; | GuildId = model.GuildId.Value; | ||||
| if (model.Name.IsSpecified) | if (model.Name.IsSpecified) | ||||
| Name = model.Name.Value; | Name = model.Name.Value; | ||||
| ApplicationId = model.ApplicationId; | |||||
| } | } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -68,6 +68,7 @@ namespace Discord.Rest | |||||
| model.Video = entity.Video.Value.ToModel(); | model.Video = entity.Video.Value.ToModel(); | ||||
| return model; | return model; | ||||
| } | } | ||||
| public static API.AllowedMentions ToModel(this AllowedMentions entity) | public static API.AllowedMentions ToModel(this AllowedMentions entity) | ||||
| { | { | ||||
| return new API.AllowedMentions() | return new API.AllowedMentions() | ||||
| @@ -1,4 +1,4 @@ | |||||
| using Newtonsoft.Json; | |||||
| using Newtonsoft.Json; | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| @@ -1,4 +1,4 @@ | |||||
| #pragma warning disable CS1591 | |||||
| #pragma warning disable CS1591 | |||||
| namespace Discord.API.Gateway | namespace Discord.API.Gateway | ||||
| { | { | ||||
| internal enum GatewayOpCode : byte | internal enum GatewayOpCode : byte | ||||
| @@ -10,7 +10,7 @@ namespace Discord.API.Gateway | |||||
| /// <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | /// <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | ||||
| Identify = 2, | Identify = 2, | ||||
| /// <summary> C→S - Used to update client's status and current game id. </summary> | /// <summary> C→S - Used to update client's status and current game id. </summary> | ||||
| StatusUpdate = 3, | |||||
| PresenceUpdate = 3, | |||||
| /// <summary> C→S - Used to join a particular voice channel. </summary> | /// <summary> C→S - Used to join a particular voice channel. </summary> | ||||
| VoiceStateUpdate = 4, | VoiceStateUpdate = 4, | ||||
| /// <summary> C→S - Used to ensure the guild's voice server is alive. </summary> | /// <summary> C→S - Used to ensure the guild's voice server is alive. </summary> | ||||
| @@ -1,10 +1,14 @@ | |||||
| #pragma warning disable CS1591 | |||||
| #pragma warning disable CS1591 | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System; | |||||
| namespace Discord.API.Gateway | namespace Discord.API.Gateway | ||||
| { | { | ||||
| internal class GuildMemberUpdateEvent : GuildMember | internal class GuildMemberUpdateEvent : GuildMember | ||||
| { | { | ||||
| [JsonProperty("joined_at")] | |||||
| public new DateTimeOffset? JoinedAt { get; set; } | |||||
| [JsonProperty("guild_id")] | [JsonProperty("guild_id")] | ||||
| public ulong GuildId { get; set; } | public ulong GuildId { get; set; } | ||||
| } | } | ||||
| @@ -16,7 +16,7 @@ namespace Discord.API.Gateway | |||||
| [JsonProperty("shard")] | [JsonProperty("shard")] | ||||
| public Optional<int[]> ShardingParams { get; set; } | public Optional<int[]> ShardingParams { get; set; } | ||||
| [JsonProperty("presence")] | [JsonProperty("presence")] | ||||
| public Optional<StatusUpdateParams> Presence { get; set; } | |||||
| public Optional<PresenceUpdateParams> Presence { get; set; } | |||||
| [JsonProperty("intents")] | [JsonProperty("intents")] | ||||
| public Optional<int> Intents { get; set; } | public Optional<int> Intents { get; set; } | ||||
| } | } | ||||
| @@ -4,15 +4,16 @@ using Newtonsoft.Json; | |||||
| namespace Discord.API.Gateway | namespace Discord.API.Gateway | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | ||||
| internal class StatusUpdateParams | |||||
| internal class PresenceUpdateParams | |||||
| { | { | ||||
| [JsonProperty("status")] | [JsonProperty("status")] | ||||
| public UserStatus Status { get; set; } | public UserStatus Status { get; set; } | ||||
| [JsonProperty("since"), Int53] | |||||
| [JsonProperty("since", NullValueHandling = NullValueHandling.Include), Int53] | |||||
| public long? IdleSince { get; set; } | public long? IdleSince { get; set; } | ||||
| [JsonProperty("afk")] | [JsonProperty("afk")] | ||||
| public bool IsAFK { get; set; } | public bool IsAFK { get; set; } | ||||
| [JsonProperty("game")] | |||||
| public Game Game { get; set; } | |||||
| [JsonProperty("activities")] | |||||
| public object[] Activities { get; set; } // TODO, change to interface later | |||||
| } | } | ||||
| } | } | ||||
| @@ -542,7 +542,7 @@ namespace Discord.WebSocket | |||||
| internal readonly AsyncEvent<Func<SocketApplicationCommand, Task>> _applicationCommandDeleted = new AsyncEvent<Func<SocketApplicationCommand, Task>>(); | internal readonly AsyncEvent<Func<SocketApplicationCommand, Task>> _applicationCommandDeleted = new AsyncEvent<Func<SocketApplicationCommand, Task>>(); | ||||
| /// <summary> | /// <summary> | ||||
| /// Fired when a thread is created within a guild. | |||||
| /// Fired when a thread is created within a guild, or when the current user is added to a thread. | |||||
| /// </summary> | /// </summary> | ||||
| public event Func<SocketThreadChannel, Task> ThreadCreated | public event Func<SocketThreadChannel, Task> ThreadCreated | ||||
| { | { | ||||
| @@ -592,5 +592,64 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| internal readonly AsyncEvent<Func<SocketThreadUser, Task>> _threadMemberLeft = new AsyncEvent<Func<SocketThreadUser, Task>>(); | internal readonly AsyncEvent<Func<SocketThreadUser, Task>> _threadMemberLeft = new AsyncEvent<Func<SocketThreadUser, Task>>(); | ||||
| /// <summary> | |||||
| /// Fired when a stage is started. | |||||
| /// </summary> | |||||
| public event Func<SocketStageChannel, Task> StageStarted | |||||
| { | |||||
| add { _stageStarted.Add(value); } | |||||
| remove { _stageStarted.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketStageChannel, Task>> _stageStarted = new AsyncEvent<Func<SocketStageChannel, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a stage ends. | |||||
| /// </summary> | |||||
| public event Func<SocketStageChannel, Task> StageEnded | |||||
| { | |||||
| add { _stageEnded.Add(value); } | |||||
| remove { _stageEnded.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketStageChannel, Task>> _stageEnded = new AsyncEvent<Func<SocketStageChannel, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a stage is updated. | |||||
| /// </summary> | |||||
| public event Func<SocketStageChannel, SocketStageChannel, Task> StageUpdated | |||||
| { | |||||
| add { _stageUpdated.Add(value); } | |||||
| remove { _stageUpdated.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketStageChannel, SocketStageChannel, Task>> _stageUpdated = new AsyncEvent<Func<SocketStageChannel, SocketStageChannel, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a user requests to speak within a stage channel. | |||||
| /// </summary> | |||||
| public event Func<SocketStageChannel, SocketGuildUser, Task> RequestToSpeak | |||||
| { | |||||
| add { _requestToSpeak.Add(value); } | |||||
| remove { _requestToSpeak.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>> _requestToSpeak = new AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a speaker is added in a stage channel. | |||||
| /// </summary> | |||||
| public event Func<SocketStageChannel, SocketGuildUser, Task> SpeakerAdded | |||||
| { | |||||
| add { _speakerAdded.Add(value); } | |||||
| remove { _speakerAdded.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>> _speakerAdded = new AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a speaker is removed from a stage channel. | |||||
| /// </summary> | |||||
| public event Func<SocketStageChannel, SocketGuildUser, Task> SpeakerRemoved | |||||
| { | |||||
| add { _speakerRemoved.Add(value); } | |||||
| remove { _speakerRemoved.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>> _speakerRemoved = new AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>>(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -185,6 +185,11 @@ namespace Discord | |||||
| _readyPromise.TrySetException(ex); | _readyPromise.TrySetException(ex); | ||||
| _connectionPromise.TrySetException(ex); | _connectionPromise.TrySetException(ex); | ||||
| _connectionCancelToken?.Cancel(); | _connectionCancelToken?.Cancel(); | ||||
| _ = Task.Run(async () => | |||||
| { | |||||
| await _logger.ErrorAsync($"Failed to start the connection: {ex}", ex); | |||||
| }); | |||||
| } | } | ||||
| public void CriticalError(Exception ex) | public void CriticalError(Exception ex) | ||||
| { | { | ||||
| @@ -1,4 +1,4 @@ | |||||
| <Project Sdk="Microsoft.NET.Sdk"> | |||||
| <Project Sdk="Microsoft.NET.Sdk"> | |||||
| <Import Project="../../Discord.Net.targets" /> | <Import Project="../../Discord.Net.targets" /> | ||||
| <Import Project="../../StyleAnalyzer.targets" /> | <Import Project="../../StyleAnalyzer.targets" /> | ||||
| <PropertyGroup> | <PropertyGroup> | ||||
| @@ -8,7 +8,7 @@ | |||||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks> | <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks> | ||||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks> | ||||
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
| <Version>2.4.9</Version> | |||||
| <Version>3.0.1-pre</Version> | |||||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | ||||
| <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | ||||
| <PackageIcon>Temporary.png</PackageIcon> | <PackageIcon>Temporary.png</PackageIcon> | ||||
| @@ -16,7 +16,13 @@ | |||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup> | <PropertyGroup> | ||||
| <DocumentationFile>..\Discord.Net.WebSocket\Discord.Net.WebSocket.xml</DocumentationFile> | <DocumentationFile>..\Discord.Net.WebSocket\Discord.Net.WebSocket.xml</DocumentationFile> | ||||
| <AssemblyVersion>3.0.1</AssemblyVersion> | |||||
| <FileVersion>3.0.1</FileVersion> | |||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | |||||
| <DefineConstants>TRACE;</DefineConstants> | |||||
| </PropertyGroup> | |||||
| <ItemGroup> | <ItemGroup> | ||||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | ||||
| <ProjectReference Include="..\Discord.Net.Rest\Discord.Net.Rest.csproj" /> | <ProjectReference Include="..\Discord.Net.Rest\Discord.Net.Rest.csproj" /> | ||||
| @@ -13,7 +13,7 @@ | |||||
| <member name="F:Discord.API.Gateway.GatewayOpCode.Identify"> | <member name="F:Discord.API.Gateway.GatewayOpCode.Identify"> | ||||
| <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.API.Gateway.GatewayOpCode.StatusUpdate"> | |||||
| <member name="F:Discord.API.Gateway.GatewayOpCode.PresenceUpdate"> | |||||
| <summary> C→S - Used to update client's status and current game id. </summary> | <summary> C→S - Used to update client's status and current game id. </summary> | ||||
| </member> | </member> | ||||
| <member name="F:Discord.API.Gateway.GatewayOpCode.VoiceStateUpdate"> | <member name="F:Discord.API.Gateway.GatewayOpCode.VoiceStateUpdate"> | ||||
| @@ -758,7 +758,7 @@ | |||||
| </member> | </member> | ||||
| <member name="E:Discord.WebSocket.BaseSocketClient.ThreadCreated"> | <member name="E:Discord.WebSocket.BaseSocketClient.ThreadCreated"> | ||||
| <summary> | <summary> | ||||
| Fired when a thread is created within a guild. | |||||
| Fired when a thread is created within a guild, or when the current user is added to a thread. | |||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="E:Discord.WebSocket.BaseSocketClient.ThreadUpdated"> | <member name="E:Discord.WebSocket.BaseSocketClient.ThreadUpdated"> | ||||
| @@ -781,6 +781,36 @@ | |||||
| Fired when a user leaves a thread | Fired when a user leaves a thread | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="E:Discord.WebSocket.BaseSocketClient.StageStarted"> | |||||
| <summary> | |||||
| Fired when a stage is started. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.StageEnded"> | |||||
| <summary> | |||||
| Fired when a stage ends. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.StageUpdated"> | |||||
| <summary> | |||||
| Fired when a stage is updated. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.RequestToSpeak"> | |||||
| <summary> | |||||
| Fired when a user requests to speak within a stage channel. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.SpeakerAdded"> | |||||
| <summary> | |||||
| Fired when a speaker is added in a stage channel. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.SpeakerRemoved"> | |||||
| <summary> | |||||
| Fired when a speaker is removed from a stage channel. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.DiscordShardedClient.Latency"> | <member name="P:Discord.WebSocket.DiscordShardedClient.Latency"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -2142,6 +2172,57 @@ | |||||
| </note> | </note> | ||||
| </remarks> | </remarks> | ||||
| </member> | </member> | ||||
| <member name="T:Discord.WebSocket.SocketStageChannel"> | |||||
| <summary> | |||||
| Represents a stage channel recieved over the gateway. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketStageChannel.Topic"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketStageChannel.PrivacyLevel"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketStageChannel.DiscoverableDisabled"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketStageChannel.Live"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketStageChannel.IsSpeaker"> | |||||
| <summary> | |||||
| Returns <see langword="true"/> if the current user is a speaker within the stage, otherwise <see langword="false"/>. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketStageChannel.Speakers"> | |||||
| <summary> | |||||
| Gets a collection of users who are speakers within the stage. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.StartStageAsync(System.String,Discord.StagePrivacyLevel,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.ModifyInstanceAsync(System.Action{Discord.StageInstanceProperties},Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.StopStageAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.RequestToSpeak(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.BecomeSpeakerAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.StopSpeakingAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.MoveToSpeaker(Discord.IGuildUser,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketStageChannel.RemoveFromSpeaker(Discord.IGuildUser,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketTextChannel"> | <member name="T:Discord.WebSocket.SocketTextChannel"> | ||||
| <summary> | <summary> | ||||
| Represents a WebSocket-based channel in a guild that can send and receive messages. | Represents a WebSocket-based channel in a guild that can send and receive messages. | ||||
| @@ -2787,6 +2868,9 @@ | |||||
| <member name="P:Discord.WebSocket.SocketGuild.MaxVideoChannelUsers"> | <member name="P:Discord.WebSocket.SocketGuild.MaxVideoChannelUsers"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketGuild.NsfwLevel"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGuild.PreferredCulture"> | <member name="P:Discord.WebSocket.SocketGuild.PreferredCulture"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -2898,6 +2982,14 @@ | |||||
| A read-only collection of voice channels found within this guild. | A read-only collection of voice channels found within this guild. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketGuild.StageChannels"> | |||||
| <summary> | |||||
| Gets a collection of all stage channels in this guild. | |||||
| </summary> | |||||
| <returns> | |||||
| A read-only collection of stage channels found within this guild. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGuild.CategoryChannels"> | <member name="P:Discord.WebSocket.SocketGuild.CategoryChannels"> | ||||
| <summary> | <summary> | ||||
| Gets a collection of all category channels in this guild. | Gets a collection of all category channels in this guild. | ||||
| @@ -3055,6 +3147,15 @@ | |||||
| A text channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | A text channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketGuild.GetThreadChannel(System.UInt64)"> | |||||
| <summary> | |||||
| Gets a thread in this guild. | |||||
| </summary> | |||||
| <param name="id">The snowflake identifier for the thread.</param> | |||||
| <returns> | |||||
| A thread channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketGuild.GetVoiceChannel(System.UInt64)"> | <member name="M:Discord.WebSocket.SocketGuild.GetVoiceChannel(System.UInt64)"> | ||||
| <summary> | <summary> | ||||
| Gets a voice channel in this guild. | Gets a voice channel in this guild. | ||||
| @@ -3064,6 +3165,15 @@ | |||||
| A voice channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | A voice channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketGuild.GetStageChannel(System.UInt64)"> | |||||
| <summary> | |||||
| Gets a stage channel in this guild. | |||||
| </summary> | |||||
| <param name="id">The snowflake identifier for the stage channel.</param> | |||||
| <returns> | |||||
| A stage channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | |||||
| </returns> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketGuild.GetCategoryChannel(System.UInt64)"> | <member name="M:Discord.WebSocket.SocketGuild.GetCategoryChannel(System.UInt64)"> | ||||
| <summary> | <summary> | ||||
| Gets a category channel in this guild. | Gets a category channel in this guild. | ||||
| @@ -3390,6 +3500,12 @@ | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetTextChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetTextChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetThreadChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetThreadChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetVoiceChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetVoiceChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -3399,6 +3515,12 @@ | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetVoiceChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetVoiceChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetStageChannelAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetStageChannelsAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetAFKChannelAsync(Discord.CacheMode,Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetAFKChannelAsync(Discord.CacheMode,Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -3477,6 +3599,9 @@ | |||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetWebhooksAsync(Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetWebhooksAsync(Discord.RequestOptions)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetApplicationCommandsAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketMessageComponent"> | <member name="T:Discord.WebSocket.SocketMessageComponent"> | ||||
| <summary> | <summary> | ||||
| Represents a Websocket-based interaction type for Message Components. | Represents a Websocket-based interaction type for Message Components. | ||||
| @@ -3492,7 +3617,7 @@ | |||||
| The message that contained the trigger for this interaction. | The message that contained the trigger for this interaction. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.UpdateAsync(System.Action{Discord.MessageProperties},Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketMessageComponent.UpdateAsync(System.Action{Discord.MessageProperties},Discord.RequestOptions)"> | ||||
| @@ -3503,18 +3628,22 @@ | |||||
| <param name="options">The request options for this async request.</param> | <param name="options">The request options for this async request.</param> | ||||
| <returns>A task that represents the asynchronous operation of updating the message.</returns> | <returns>A task that represents the asynchronous operation of updating the message.</returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.DeferAsync(Discord.RequestOptions)"> | |||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.DeferLoadingAsync(System.Boolean,Discord.RequestOptions)"> | |||||
| <summary> | <summary> | ||||
| Acknowledges this interaction with the <see cref="F:Discord.InteractionResponseType.DeferredUpdateMessage"/>. | |||||
| Defers an interaction and responds with type 5 (<see cref="F:Discord.InteractionResponseType.DeferredChannelMessageWithSource"/>) | |||||
| </summary> | </summary> | ||||
| <param name="ephemeral"><see langword="true"/> to send this message ephemerally, otherwise <see langword="false"/>.</param> | |||||
| <param name="options">The request options for this async request.</param> | <param name="options">The request options for this async request.</param> | ||||
| <returns> | <returns> | ||||
| A task that represents the asynchronous operation of acknowledging the interaction. | A task that represents the asynchronous operation of acknowledging the interaction. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketMessageComponent.DeferAsync(System.Boolean,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketMessageComponentData"> | <member name="T:Discord.WebSocket.SocketMessageComponentData"> | ||||
| <summary> | <summary> | ||||
| Represents the data sent with a <see cref="F:Discord.InteractionType.MessageComponent"/>. | Represents the data sent with a <see cref="F:Discord.InteractionType.MessageComponent"/>. | ||||
| @@ -3619,19 +3748,14 @@ | |||||
| The data associated with this interaction. | The data associated with this interaction. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketSlashCommand.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||||
| <member name="M:Discord.WebSocket.SocketSlashCommand.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketSlashCommand.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||||
| <member name="M:Discord.WebSocket.SocketSlashCommand.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketSlashCommand.DeferAsync(Discord.RequestOptions)"> | |||||
| <summary> | |||||
| Acknowledges this interaction with the <see cref="F:Discord.InteractionResponseType.DeferredChannelMessageWithSource"/>. | |||||
| </summary> | |||||
| <returns> | |||||
| A task that represents the asynchronous operation of acknowledging the interaction. | |||||
| </returns> | |||||
| <member name="M:Discord.WebSocket.SocketSlashCommand.DeferAsync(System.Boolean,Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | </member> | ||||
| <member name="T:Discord.WebSocket.SocketSlashCommandData"> | <member name="T:Discord.WebSocket.SocketSlashCommandData"> | ||||
| <summary> | <summary> | ||||
| @@ -3708,12 +3832,12 @@ | |||||
| <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/>. | <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/>. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketInteraction.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||||
| <member name="M:Discord.WebSocket.SocketInteraction.RespondAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <summary> | <summary> | ||||
| Responds to an Interaction with type <see cref="F:Discord.InteractionResponseType.ChannelMessageWithSource"/>. | Responds to an Interaction with type <see cref="F:Discord.InteractionResponseType.ChannelMessageWithSource"/>. | ||||
| <para> | <para> | ||||
| If you have <see cref="P:Discord.WebSocket.DiscordSocketConfig.AlwaysAcknowledgeInteractions"/> set to <see langword="true"/>, You should use | If you have <see cref="P:Discord.WebSocket.DiscordSocketConfig.AlwaysAcknowledgeInteractions"/> set to <see langword="true"/>, You should use | ||||
| <see cref="!:FollowupAsync(Discord.Embed[],string,bool,bool,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"/> instead. | |||||
| <see cref="M:Discord.WebSocket.SocketInteraction.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"/> instead. | |||||
| </para> | </para> | ||||
| </summary> | </summary> | ||||
| <param name="text">The text of the message to be sent.</param> | <param name="text">The text of the message to be sent.</param> | ||||
| @@ -3723,10 +3847,11 @@ | |||||
| <param name="allowedMentions">The allowed mentions for this response.</param> | <param name="allowedMentions">The allowed mentions for this response.</param> | ||||
| <param name="options">The request options 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> | <param name="component">A <see cref="T:Discord.MessageComponent"/> to be sent with this response</param> | ||||
| <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> | |||||
| <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.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> | <exception cref="T:System.InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketInteraction.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent)"> | |||||
| <member name="M:Discord.WebSocket.SocketInteraction.FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <summary> | <summary> | ||||
| Sends a followup message for this interaction. | Sends a followup message for this interaction. | ||||
| </summary> | </summary> | ||||
| @@ -3737,6 +3862,7 @@ | |||||
| <param name="allowedMentions">The allowed mentions for this response.</param> | <param name="allowedMentions">The allowed mentions for this response.</param> | ||||
| <param name="options">The request options 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> | <param name="component">A <see cref="T:Discord.MessageComponent"/> to be sent with this response</param> | ||||
| <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> | |||||
| <returns> | <returns> | ||||
| The sent message. | The sent message. | ||||
| </returns> | </returns> | ||||
| @@ -3764,14 +3890,25 @@ | |||||
| A task that represents the asynchronous operation of acknowledging the interaction. | A task that represents the asynchronous operation of acknowledging the interaction. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketInteraction.DeferAsync(Discord.RequestOptions)"> | |||||
| <member name="M:Discord.WebSocket.SocketInteraction.DeferAsync(System.Boolean,Discord.RequestOptions)"> | |||||
| <summary> | <summary> | ||||
| Acknowledges this interaction. | Acknowledges this interaction. | ||||
| </summary> | </summary> | ||||
| <param name="ephemeral"><see langword="true"/> to send this message ephemerally, otherwise <see langword="false"/>.</param> | |||||
| <param name="options">The request options for this async request.</param> | |||||
| <returns> | <returns> | ||||
| A task that represents the asynchronous operation of acknowledging the interaction. | A task that represents the asynchronous operation of acknowledging the interaction. | ||||
| </returns> | </returns> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketInteraction.Discord#IDiscordInteraction#FollowupAsync(System.String,Discord.Embed[],System.Boolean,System.Boolean,Discord.AllowedMentions,Discord.RequestOptions,Discord.MessageComponent,Discord.Embed)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketInteraction.Discord#IDiscordInteraction#GetOriginalResponseAsync(Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketInteraction.Discord#IDiscordInteraction#ModifyOriginalResponseAsync(System.Action{Discord.MessageProperties},Discord.RequestOptions)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketInvite"> | <member name="T:Discord.WebSocket.SocketInvite"> | ||||
| <summary> | <summary> | ||||
| Represents a WebSocket-based invite to a guild. | Represents a WebSocket-based invite to a guild. | ||||
| @@ -4308,6 +4445,12 @@ | |||||
| <member name="P:Discord.WebSocket.SocketGroupUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketGroupUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketGroupUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGroupUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGroupUser.Presence"> | <member name="P:Discord.WebSocket.SocketGroupUser.Presence"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4338,6 +4481,9 @@ | |||||
| <member name="P:Discord.WebSocket.SocketGroupUser.Discord#IVoiceState#IsStreaming"> | <member name="P:Discord.WebSocket.SocketGroupUser.Discord#IVoiceState#IsStreaming"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketGroupUser.Discord#IVoiceState#RequestToSpeakTimestamp"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketGuildUser"> | <member name="T:Discord.WebSocket.SocketGuildUser"> | ||||
| <summary> | <summary> | ||||
| Represents a WebSocket-based guild user. | Represents a WebSocket-based guild user. | ||||
| @@ -4363,6 +4509,12 @@ | |||||
| <member name="P:Discord.WebSocket.SocketGuildUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketGuildUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketGuildUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGuildUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGuildUser.GuildPermissions"> | <member name="P:Discord.WebSocket.SocketGuildUser.GuildPermissions"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4387,6 +4539,9 @@ | |||||
| <member name="P:Discord.WebSocket.SocketGuildUser.IsStreaming"> | <member name="P:Discord.WebSocket.SocketGuildUser.IsStreaming"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketGuildUser.RequestToSpeakTimestamp"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketGuildUser.IsPending"> | <member name="P:Discord.WebSocket.SocketGuildUser.IsPending"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4423,7 +4578,7 @@ | |||||
| Returns the position of the user within the role hierarchy. | Returns the position of the user within the role hierarchy. | ||||
| </summary> | </summary> | ||||
| <remarks> | <remarks> | ||||
| The returned value equal to the position of the highest role the user has, or | |||||
| The returned value equal to the position of the highest role the user has, or | |||||
| <see cref="F:System.Int32.MaxValue"/> if user is the server owner. | <see cref="F:System.Int32.MaxValue"/> if user is the server owner. | ||||
| </remarks> | </remarks> | ||||
| </member> | </member> | ||||
| @@ -4545,6 +4700,12 @@ | |||||
| <member name="P:Discord.WebSocket.SocketSelfUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketSelfUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketSelfUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketSelfUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketSelfUser.Presence"> | <member name="P:Discord.WebSocket.SocketSelfUser.Presence"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4598,6 +4759,12 @@ | |||||
| <member name="P:Discord.WebSocket.SocketThreadUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketThreadUser.AvatarId"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketThreadUser.BannerId"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketThreadUser.AccentColor"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketThreadUser.DiscriminatorValue"> | <member name="P:Discord.WebSocket.SocketThreadUser.DiscriminatorValue"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| @@ -4634,6 +4801,9 @@ | |||||
| <member name="P:Discord.WebSocket.SocketThreadUser.IsStreaming"> | <member name="P:Discord.WebSocket.SocketThreadUser.IsStreaming"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketThreadUser.RequestToSpeakTimestamp"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketThreadUser.GetPermissions(Discord.IGuildChannel)"> | <member name="M:Discord.WebSocket.SocketThreadUser.GetPermissions(Discord.IGuildChannel)"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| @@ -4702,6 +4872,12 @@ | |||||
| <member name="P:Discord.WebSocket.SocketUnknownUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketUnknownUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketUnknownUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketUnknownUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketUnknownUser.IsBot"> | <member name="P:Discord.WebSocket.SocketUnknownUser.IsBot"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4732,6 +4908,12 @@ | |||||
| <member name="P:Discord.WebSocket.SocketUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketUser.IsWebhook"> | <member name="P:Discord.WebSocket.SocketUser.IsWebhook"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4770,6 +4952,9 @@ | |||||
| <member name="M:Discord.WebSocket.SocketUser.GetAvatarUrl(Discord.ImageFormat,System.UInt16)"> | <member name="M:Discord.WebSocket.SocketUser.GetAvatarUrl(Discord.ImageFormat,System.UInt16)"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketUser.GetBannerUrl(Discord.ImageFormat,System.UInt16)"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="M:Discord.WebSocket.SocketUser.GetDefaultAvatarUrl"> | <member name="M:Discord.WebSocket.SocketUser.GetDefaultAvatarUrl"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4799,6 +4984,9 @@ | |||||
| <member name="P:Discord.WebSocket.SocketVoiceState.VoiceSessionId"> | <member name="P:Discord.WebSocket.SocketVoiceState.VoiceSessionId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketVoiceState.RequestToSpeakTimestamp"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketVoiceState.IsMuted"> | <member name="P:Discord.WebSocket.SocketVoiceState.IsMuted"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4848,6 +5036,14 @@ | |||||
| <member name="P:Discord.WebSocket.SocketWebhookUser.AvatarId"> | <member name="P:Discord.WebSocket.SocketWebhookUser.AvatarId"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketWebhookUser.BannerId"> | |||||
| <inheritdoc /> | |||||
| <exception cref="T:System.NotSupportedException">Webhook users does not support banners.</exception> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketWebhookUser.AccentColor"> | |||||
| <inheritdoc /> | |||||
| <exception cref="T:System.NotSupportedException">Webhook users does not support accent colors.</exception> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketWebhookUser.IsBot"> | <member name="P:Discord.WebSocket.SocketWebhookUser.IsBot"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4948,6 +5144,9 @@ | |||||
| <member name="P:Discord.WebSocket.SocketWebhookUser.Discord#IVoiceState#IsStreaming"> | <member name="P:Discord.WebSocket.SocketWebhookUser.Discord#IVoiceState#IsStreaming"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.WebSocket.SocketWebhookUser.Discord#IVoiceState#RequestToSpeakTimestamp"> | |||||
| <inheritdoc /> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketVoiceServer"> | <member name="T:Discord.WebSocket.SocketVoiceServer"> | ||||
| <summary> | <summary> | ||||
| Represents a WebSocket-based voice server. | Represents a WebSocket-based voice server. | ||||
| @@ -1,4 +1,4 @@ | |||||
| using System; | |||||
| using System; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
| @@ -35,4 +35,4 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| private readonly AsyncEvent<Func<int, int, DiscordSocketClient, Task>> _shardLatencyUpdatedEvent = new AsyncEvent<Func<int, int, DiscordSocketClient, Task>>(); | private readonly AsyncEvent<Func<int, int, DiscordSocketClient, Task>> _shardLatencyUpdatedEvent = new AsyncEvent<Func<int, int, DiscordSocketClient, Task>>(); | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -30,7 +30,16 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override IActivity Activity { get => _shards[0].Activity; protected set { } } | public override IActivity Activity { get => _shards[0].Activity; protected set { } } | ||||
| internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | |||||
| internal new DiscordSocketApiClient ApiClient | |||||
| { | |||||
| get | |||||
| { | |||||
| if (base.ApiClient.CurrentUserId == null) | |||||
| base.ApiClient.CurrentUserId = CurrentUser?.Id; | |||||
| return base.ApiClient; | |||||
| } | |||||
| } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override IReadOnlyCollection<SocketGuild> Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); | public override IReadOnlyCollection<SocketGuild> Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -379,6 +388,20 @@ namespace Discord.WebSocket | |||||
| client.InviteDeleted += (channel, invite) => _inviteDeletedEvent.InvokeAsync(channel, invite); | client.InviteDeleted += (channel, invite) => _inviteDeletedEvent.InvokeAsync(channel, invite); | ||||
| client.InteractionCreated += (interaction) => _interactionCreatedEvent.InvokeAsync(interaction); | client.InteractionCreated += (interaction) => _interactionCreatedEvent.InvokeAsync(interaction); | ||||
| client.ThreadUpdated += (thread1, thread2) => _threadUpdated.InvokeAsync(thread1, thread2); | |||||
| client.ThreadCreated += (thread) => _threadCreated.InvokeAsync(thread); | |||||
| client.ThreadDeleted += (thread) => _threadDeleted.InvokeAsync(thread); | |||||
| client.ThreadMemberJoined += (user) => _threadMemberJoined.InvokeAsync(user); | |||||
| client.ThreadMemberLeft += (user) => _threadMemberLeft.InvokeAsync(user); | |||||
| client.StageEnded += (stage) => _stageEnded.InvokeAsync(stage); | |||||
| client.StageStarted += (stage) => _stageStarted.InvokeAsync(stage); | |||||
| client.StageUpdated += (stage1, stage2) => _stageUpdated.InvokeAsync(stage1, stage2); | |||||
| client.RequestToSpeak += (stage, user) => _requestToSpeak.InvokeAsync(stage, user); | |||||
| client.SpeakerAdded += (stage, user) => _speakerAdded.InvokeAsync(stage, user); | |||||
| client.SpeakerRemoved += (stage, user) => _speakerRemoved.InvokeAsync(stage, user); | |||||
| } | } | ||||
| //IDiscordClient | //IDiscordClient | ||||
| @@ -75,8 +75,15 @@ namespace Discord.API | |||||
| using (var jsonReader = new JsonTextReader(reader)) | using (var jsonReader = new JsonTextReader(reader)) | ||||
| { | { | ||||
| var msg = _serializer.Deserialize<SocketFrame>(jsonReader); | var msg = _serializer.Deserialize<SocketFrame>(jsonReader); | ||||
| if (msg != null) | if (msg != null) | ||||
| { | |||||
| #if DEBUG_PACKETS | |||||
| Console.WriteLine($"<- {(GatewayOpCode)msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); | |||||
| #endif | |||||
| await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); | await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -87,11 +94,21 @@ namespace Discord.API | |||||
| { | { | ||||
| var msg = _serializer.Deserialize<SocketFrame>(jsonReader); | var msg = _serializer.Deserialize<SocketFrame>(jsonReader); | ||||
| if (msg != null) | if (msg != null) | ||||
| { | |||||
| #if DEBUG_PACKETS | |||||
| Console.WriteLine($"<- {(GatewayOpCode)msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); | |||||
| #endif | |||||
| await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); | await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); | ||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| WebSocketClient.Closed += async ex => | WebSocketClient.Closed += async ex => | ||||
| { | { | ||||
| #if DEBUG_PACKETS | |||||
| Console.WriteLine(ex); | |||||
| #endif | |||||
| await DisconnectAsync().ConfigureAwait(false); | await DisconnectAsync().ConfigureAwait(false); | ||||
| await _disconnectedEvent.InvokeAsync(ex).ConfigureAwait(false); | await _disconnectedEvent.InvokeAsync(ex).ConfigureAwait(false); | ||||
| }; | }; | ||||
| @@ -153,6 +170,11 @@ namespace Discord.API | |||||
| var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false); | var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false); | ||||
| _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}&compress=zlib-stream"; | _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}&compress=zlib-stream"; | ||||
| } | } | ||||
| #if DEBUG_PACKETS | |||||
| Console.WriteLine("Connecting to gateway: " + _gatewayUrl); | |||||
| #endif | |||||
| await WebSocketClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false); | await WebSocketClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false); | ||||
| ConnectionState = ConnectionState.Connected; | ConnectionState = ConnectionState.Connected; | ||||
| @@ -213,6 +235,10 @@ namespace Discord.API | |||||
| options.BucketId = GatewayBucket.Get(GatewayBucketType.Unbucketed).Id; | options.BucketId = GatewayBucket.Get(GatewayBucketType.Unbucketed).Id; | ||||
| await RequestQueue.SendAsync(new WebSocketRequest(WebSocketClient, bytes, true, opCode == GatewayOpCode.Heartbeat, options)).ConfigureAwait(false); | await RequestQueue.SendAsync(new WebSocketRequest(WebSocketClient, bytes, true, opCode == GatewayOpCode.Heartbeat, options)).ConfigureAwait(false); | ||||
| await _sentGatewayMessageEvent.InvokeAsync(opCode).ConfigureAwait(false); | await _sentGatewayMessageEvent.InvokeAsync(opCode).ConfigureAwait(false); | ||||
| #if DEBUG_PACKETS | |||||
| Console.WriteLine($"-> {opCode}:\n{SerializeJson(payload)}"); | |||||
| #endif | |||||
| } | } | ||||
| public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, int totalShards = 1, GatewayIntents gatewayIntents = GatewayIntents.AllUnprivileged, (UserStatus, bool, long?, GameModel)? presence = null, RequestOptions options = null) | public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, int totalShards = 1, GatewayIntents gatewayIntents = GatewayIntents.AllUnprivileged, (UserStatus, bool, long?, GameModel)? presence = null, RequestOptions options = null) | ||||
| @@ -220,7 +246,9 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var props = new Dictionary<string, string> | var props = new Dictionary<string, string> | ||||
| { | { | ||||
| ["$device"] = "Discord.Net" | |||||
| ["$device"] = "Discord.Net Labs", | |||||
| ["$os"] = Environment.OSVersion.Platform.ToString(), | |||||
| [$"browser"] = "Discord.Net Labs" | |||||
| }; | }; | ||||
| var msg = new IdentifyParams() | var msg = new IdentifyParams() | ||||
| { | { | ||||
| @@ -237,12 +265,12 @@ namespace Discord.API | |||||
| if (presence.HasValue) | if (presence.HasValue) | ||||
| { | { | ||||
| msg.Presence = new StatusUpdateParams | |||||
| msg.Presence = new PresenceUpdateParams | |||||
| { | { | ||||
| Status = presence.Value.Item1, | Status = presence.Value.Item1, | ||||
| IsAFK = presence.Value.Item2, | IsAFK = presence.Value.Item2, | ||||
| IdleSince = presence.Value.Item3, | IdleSince = presence.Value.Item3, | ||||
| Game = presence.Value.Item4, | |||||
| Activities = new object[] { presence.Value.Item4 } | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -264,18 +292,18 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false); | await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false); | ||||
| } | } | ||||
| public async Task SendStatusUpdateAsync(UserStatus status, bool isAFK, long? since, GameModel game, RequestOptions options = null) | |||||
| public async Task SendPresenceUpdateAsync(UserStatus status, bool isAFK, long? since, GameModel game, RequestOptions options = null) | |||||
| { | { | ||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var args = new StatusUpdateParams | |||||
| var args = new PresenceUpdateParams | |||||
| { | { | ||||
| Status = status, | Status = status, | ||||
| IdleSince = since, | IdleSince = since, | ||||
| IsAFK = isAFK, | IsAFK = isAFK, | ||||
| Game = game | |||||
| Activities = new object[] { game } | |||||
| }; | }; | ||||
| options.BucketId = GatewayBucket.Get(GatewayBucketType.PresenceUpdate).Id; | options.BucketId = GatewayBucket.Get(GatewayBucketType.PresenceUpdate).Id; | ||||
| await SendGatewayAsync(GatewayOpCode.StatusUpdate, args, options: options).ConfigureAwait(false); | |||||
| await SendGatewayAsync(GatewayOpCode.PresenceUpdate, args, options: options).ConfigureAwait(false); | |||||
| } | } | ||||
| public async Task SendRequestMembersAsync(IEnumerable<ulong> guildIds, RequestOptions options = null) | public async Task SendRequestMembersAsync(IEnumerable<ulong> guildIds, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -495,7 +495,7 @@ namespace Discord.WebSocket | |||||
| var presence = BuildCurrentStatus() ?? (UserStatus.Online, false, null, null); | var presence = BuildCurrentStatus() ?? (UserStatus.Online, false, null, null); | ||||
| await ApiClient.SendStatusUpdateAsync( | |||||
| await ApiClient.SendPresenceUpdateAsync( | |||||
| status: presence.Item1, | status: presence.Item1, | ||||
| isAFK: presence.Item2, | isAFK: presence.Item2, | ||||
| since: presence.Item3, | since: presence.Item3, | ||||
| @@ -1770,6 +1770,29 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| if (user is SocketGuildUser guildUser && data.ChannelId.HasValue) | |||||
| { | |||||
| SocketStageChannel stage = guildUser.Guild.GetStageChannel(data.ChannelId.Value); | |||||
| if (stage != null && before.VoiceChannel != null && after.VoiceChannel != null) | |||||
| { | |||||
| if (!before.RequestToSpeakTimestamp.HasValue && after.RequestToSpeakTimestamp.HasValue) | |||||
| { | |||||
| await TimedInvokeAsync(_requestToSpeak, nameof(RequestToSpeak), stage, guildUser); | |||||
| return; | |||||
| } | |||||
| if(before.IsSuppressed && !after.IsSuppressed) | |||||
| { | |||||
| await TimedInvokeAsync(_speakerAdded, nameof(SpeakerAdded), stage, guildUser); | |||||
| return; | |||||
| } | |||||
| if(!before.IsSuppressed && after.IsSuppressed) | |||||
| { | |||||
| await TimedInvokeAsync(_speakerRemoved, nameof(SpeakerRemoved), stage, guildUser); | |||||
| } | |||||
| } | |||||
| } | |||||
| await TimedInvokeAsync(_userVoiceStateUpdatedEvent, nameof(UserVoiceStateUpdated), user, before, after).ConfigureAwait(false); | await TimedInvokeAsync(_userVoiceStateUpdatedEvent, nameof(UserVoiceStateUpdated), user, before, after).ConfigureAwait(false); | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -2001,8 +2024,9 @@ namespace Discord.WebSocket | |||||
| threadChannel = (SocketThreadChannel)guild.AddChannel(this.State, data); | threadChannel = (SocketThreadChannel)guild.AddChannel(this.State, data); | ||||
| if (data.ThreadMember.IsSpecified) | if (data.ThreadMember.IsSpecified) | ||||
| threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); | threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); | ||||
| await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false); | |||||
| } | } | ||||
| await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false); | |||||
| } | } | ||||
| break; | break; | ||||
| @@ -2180,6 +2204,47 @@ namespace Discord.WebSocket | |||||
| break; | break; | ||||
| case "STAGE_INSTANCE_CREATE" or "STAGE_INSTANCE_UPDATE" or "STAGE_INSTANCE_DELETE": | |||||
| { | |||||
| await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); | |||||
| var data = (payload as JToken).ToObject<StageInstance>(_serializer); | |||||
| var guild = State.GetGuild(data.GuildId); | |||||
| if(guild == null) | |||||
| { | |||||
| await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); | |||||
| return; | |||||
| } | |||||
| var stageChannel = guild.GetStageChannel(data.ChannelId); | |||||
| if(stageChannel == null) | |||||
| { | |||||
| await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); | |||||
| return; | |||||
| } | |||||
| SocketStageChannel before = type == "STAGE_INSTANCE_UPDATE" ? stageChannel.Clone() : null; | |||||
| stageChannel.Update(data, type == "STAGE_INSTANCE_CREATE" ? true : type == "STAGE_INSTANCE_DELETE" ? false : false); | |||||
| switch (type) | |||||
| { | |||||
| case "STAGE_INSTANCE_CREATE": | |||||
| await TimedInvokeAsync(_stageStarted, nameof(StageStarted), stageChannel); | |||||
| return; | |||||
| case "STAGE_INSTANCE_DELETE": | |||||
| await TimedInvokeAsync(_stageEnded, nameof(StageEnded), stageChannel); | |||||
| return; | |||||
| case "STAGE_INSTANCE_UPDATE": | |||||
| await TimedInvokeAsync(_stageUpdated, nameof(StageUpdated), before, stageChannel); | |||||
| return; | |||||
| } | |||||
| } | |||||
| break; | |||||
| //Ignored (User only) | //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); | ||||
| @@ -58,6 +58,8 @@ namespace Discord.WebSocket | |||||
| return SocketCategoryChannel.Create(guild, state, model); | return SocketCategoryChannel.Create(guild, state, model); | ||||
| case ChannelType.PrivateThread or ChannelType.PublicThread or ChannelType.NewsThread: | case ChannelType.PrivateThread or ChannelType.PublicThread or ChannelType.NewsThread: | ||||
| return SocketThreadChannel.Create(guild, state, model); | return SocketThreadChannel.Create(guild, state, model); | ||||
| case ChannelType.Stage: | |||||
| return SocketStageChannel.Create(guild, state, model); | |||||
| default: | default: | ||||
| return new SocketGuildChannel(guild.Discord, model.Id, guild); | return new SocketGuildChannel(guild.Discord, model.Id, guild); | ||||
| } | } | ||||
| @@ -0,0 +1,168 @@ | |||||
| using Discord.Rest; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Collections.Immutable; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| using Model = Discord.API.Channel; | |||||
| using StageInstance = Discord.API.StageInstance; | |||||
| namespace Discord.WebSocket | |||||
| { | |||||
| /// <summary> | |||||
| /// Represents a stage channel recieved over the gateway. | |||||
| /// </summary> | |||||
| public class SocketStageChannel : SocketVoiceChannel, IStageChannel | |||||
| { | |||||
| /// <inheritdoc/> | |||||
| public string Topic { get; private set; } | |||||
| /// <inheritdoc/> | |||||
| public StagePrivacyLevel? PrivacyLevel { get; private set; } | |||||
| /// <inheritdoc/> | |||||
| public bool? DiscoverableDisabled { get; private set; } | |||||
| /// <inheritdoc/> | |||||
| public bool Live { get; private set; } = false; | |||||
| /// <summary> | |||||
| /// Returns <see langword="true"/> if the current user is a speaker within the stage, otherwise <see langword="false"/>. | |||||
| /// </summary> | |||||
| public bool IsSpeaker | |||||
| => !Guild.CurrentUser.IsSuppressed; | |||||
| /// <summary> | |||||
| /// Gets a collection of users who are speakers within the stage. | |||||
| /// </summary> | |||||
| public IReadOnlyCollection<SocketGuildUser> Speakers | |||||
| => this.Users.Where(x => !x.IsSuppressed).ToImmutableArray(); | |||||
| internal new SocketStageChannel Clone() => MemberwiseClone() as SocketStageChannel; | |||||
| internal SocketStageChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) | |||||
| : base(discord, id, guild) | |||||
| { | |||||
| } | |||||
| internal new static SocketStageChannel Create(SocketGuild guild, ClientState state, Model model) | |||||
| { | |||||
| var entity = new SocketStageChannel(guild.Discord, model.Id, guild); | |||||
| entity.Update(state, model); | |||||
| return entity; | |||||
| } | |||||
| internal override void Update(ClientState state, Model model) | |||||
| { | |||||
| base.Update(state, model); | |||||
| } | |||||
| internal void Update(StageInstance model, bool isLive = false) | |||||
| { | |||||
| this.Live = isLive; | |||||
| if (isLive) | |||||
| { | |||||
| this.Topic = model.Topic; | |||||
| this.PrivacyLevel = model.PrivacyLevel; | |||||
| this.DiscoverableDisabled = model.DiscoverableDisabled; | |||||
| } | |||||
| else | |||||
| { | |||||
| this.Topic = null; | |||||
| this.PrivacyLevel = null; | |||||
| this.DiscoverableDisabled = null; | |||||
| } | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public async Task StartStageAsync(string topic, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.CreateStageInstanceParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Topic = topic, | |||||
| PrivacyLevel = privacyLevel, | |||||
| }; | |||||
| var model = await Discord.ApiClient.CreateStageInstanceAsync(args, options).ConfigureAwait(false); | |||||
| this.Update(model, true); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public async Task ModifyInstanceAsync(Action<StageInstanceProperties> func, RequestOptions options = null) | |||||
| { | |||||
| var model = await ChannelHelper.ModifyAsync(this, Discord, func, options); | |||||
| this.Update(model, true); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public async Task StopStageAsync(RequestOptions options = null) | |||||
| { | |||||
| await Discord.ApiClient.DeleteStageInstanceAsync(this.Id, options); | |||||
| Update(null, false); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task RequestToSpeak(RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| RequestToSpeakTimestamp = DateTimeOffset.UtcNow | |||||
| }; | |||||
| return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task BecomeSpeakerAsync(RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = false | |||||
| }; | |||||
| return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task StopSpeakingAsync(RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = true | |||||
| }; | |||||
| return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task MoveToSpeaker(IGuildUser user, RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = false | |||||
| }; | |||||
| return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public Task RemoveFromSpeaker(IGuildUser user, RequestOptions options = null) | |||||
| { | |||||
| var args = new API.Rest.ModifyVoiceStateParams() | |||||
| { | |||||
| ChannelId = this.Id, | |||||
| Suppressed = true | |||||
| }; | |||||
| return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -281,14 +281,14 @@ namespace Discord.WebSocket | |||||
| /// <b>This method is not supported in threads.</b> | /// <b>This method is not supported in threads.</b> | ||||
| /// </remarks> | /// </remarks> | ||||
| public override OverwritePermissions? GetPermissionOverwrite(IRole role) | public override OverwritePermissions? GetPermissionOverwrite(IRole role) | ||||
| => throw new NotImplementedException(); | |||||
| => ParentChannel.GetPermissionOverwrite(role); | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| /// <remarks> | /// <remarks> | ||||
| /// <b>This method is not supported in threads.</b> | /// <b>This method is not supported in threads.</b> | ||||
| /// </remarks> | /// </remarks> | ||||
| public override OverwritePermissions? GetPermissionOverwrite(IUser user) | public override OverwritePermissions? GetPermissionOverwrite(IUser user) | ||||
| => throw new NotImplementedException(); | |||||
| => ParentChannel.GetPermissionOverwrite(user); | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| /// <remarks> | /// <remarks> | ||||
| @@ -118,6 +118,8 @@ namespace Discord.WebSocket | |||||
| public int? MaxMembers { get; private set; } | public int? MaxMembers { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public int? MaxVideoChannelUsers { get; private set; } | public int? MaxVideoChannelUsers { get; private set; } | ||||
| /// <inheritdoc /> | |||||
| public NsfwLevel NsfwLevel { get; private set; } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public CultureInfo PreferredCulture { get; private set; } | public CultureInfo PreferredCulture { get; private set; } | ||||
| @@ -269,6 +271,14 @@ namespace Discord.WebSocket | |||||
| public IReadOnlyCollection<SocketVoiceChannel> VoiceChannels | public IReadOnlyCollection<SocketVoiceChannel> VoiceChannels | ||||
| => Channels.OfType<SocketVoiceChannel>().ToImmutableArray(); | => Channels.OfType<SocketVoiceChannel>().ToImmutableArray(); | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets a collection of all stage channels in this guild. | |||||
| /// </summary> | |||||
| /// <returns> | |||||
| /// A read-only collection of stage channels found within this guild. | |||||
| /// </returns> | |||||
| public IReadOnlyCollection<SocketStageChannel> StageChannels | |||||
| => Channels.OfType<SocketStageChannel>().ToImmutableArray(); | |||||
| /// <summary> | |||||
| /// Gets a collection of all category channels in this guild. | /// Gets a collection of all category channels in this guild. | ||||
| /// </summary> | /// </summary> | ||||
| /// <returns> | /// <returns> | ||||
| @@ -464,6 +474,7 @@ namespace Discord.WebSocket | |||||
| SystemChannelFlags = model.SystemChannelFlags; | SystemChannelFlags = model.SystemChannelFlags; | ||||
| Description = model.Description; | Description = model.Description; | ||||
| PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault(); | PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault(); | ||||
| NsfwLevel = model.NsfwLevel; | |||||
| if (model.MaxPresences.IsSpecified) | if (model.MaxPresences.IsSpecified) | ||||
| MaxPresences = model.MaxPresences.Value ?? 25000; | MaxPresences = model.MaxPresences.Value ?? 25000; | ||||
| if (model.MaxMembers.IsSpecified) | if (model.MaxMembers.IsSpecified) | ||||
| @@ -630,6 +641,16 @@ namespace Discord.WebSocket | |||||
| public SocketTextChannel GetTextChannel(ulong id) | public SocketTextChannel GetTextChannel(ulong id) | ||||
| => GetChannel(id) as SocketTextChannel; | => GetChannel(id) as SocketTextChannel; | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets a thread in this guild. | |||||
| /// </summary> | |||||
| /// <param name="id">The snowflake identifier for the thread.</param> | |||||
| /// <returns> | |||||
| /// A thread channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | |||||
| /// </returns> | |||||
| public SocketThreadChannel GetThreadChannel(ulong id) | |||||
| => GetChannel(id) as SocketThreadChannel; | |||||
| /// <summary> | |||||
| /// Gets a voice channel in this guild. | /// Gets a voice channel in this guild. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="id">The snowflake identifier for the voice channel.</param> | /// <param name="id">The snowflake identifier for the voice channel.</param> | ||||
| @@ -639,6 +660,15 @@ namespace Discord.WebSocket | |||||
| public SocketVoiceChannel GetVoiceChannel(ulong id) | public SocketVoiceChannel GetVoiceChannel(ulong id) | ||||
| => GetChannel(id) as SocketVoiceChannel; | => GetChannel(id) as SocketVoiceChannel; | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets a stage channel in this guild. | |||||
| /// </summary> | |||||
| /// <param name="id">The snowflake identifier for the stage channel.</param> | |||||
| /// <returns> | |||||
| /// A stage channel associated with the specified <paramref name="id" />; <see langword="null"/> if none is found. | |||||
| /// </returns> | |||||
| public SocketStageChannel GetStageChannel(ulong id) | |||||
| => GetChannel(id) as SocketStageChannel; | |||||
| /// <summary> | |||||
| /// Gets a category channel in this guild. | /// Gets a category channel in this guild. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="id">The snowflake identifier for the category channel.</param> | /// <param name="id">The snowflake identifier for the category channel.</param> | ||||
| @@ -1326,6 +1356,12 @@ namespace Discord.WebSocket | |||||
| Task<ITextChannel> IGuild.GetTextChannelAsync(ulong id, CacheMode mode, RequestOptions options) | Task<ITextChannel> IGuild.GetTextChannelAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<ITextChannel>(GetTextChannel(id)); | => Task.FromResult<ITextChannel>(GetTextChannel(id)); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| Task<IThreadChannel> IGuild.GetThreadChannelAsync(ulong id, CacheMode mode, RequestOptions options) | |||||
| => Task.FromResult<IThreadChannel>(GetThreadChannel(id)); | |||||
| /// <inheritdoc /> | |||||
| Task<IReadOnlyCollection<IThreadChannel>> IGuild.GetThreadChannelsAsync(CacheMode mode, RequestOptions options) | |||||
| => Task.FromResult<IReadOnlyCollection<IThreadChannel>>(ThreadChannels); | |||||
| /// <inheritdoc /> | |||||
| Task<IReadOnlyCollection<IVoiceChannel>> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) | Task<IReadOnlyCollection<IVoiceChannel>> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<IReadOnlyCollection<IVoiceChannel>>(VoiceChannels); | => Task.FromResult<IReadOnlyCollection<IVoiceChannel>>(VoiceChannels); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -1335,6 +1371,12 @@ namespace Discord.WebSocket | |||||
| Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<IVoiceChannel>(GetVoiceChannel(id)); | => Task.FromResult<IVoiceChannel>(GetVoiceChannel(id)); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| Task<IStageChannel> IGuild.GetStageChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
| => Task.FromResult<IStageChannel>(GetStageChannel(id)); | |||||
| /// <inheritdoc /> | |||||
| Task<IReadOnlyCollection<IStageChannel>> IGuild.GetStageChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
| => Task.FromResult<IReadOnlyCollection<IStageChannel>>(StageChannels); | |||||
| /// <inheritdoc /> | |||||
| Task<IVoiceChannel> IGuild.GetAFKChannelAsync(CacheMode mode, RequestOptions options) | Task<IVoiceChannel> IGuild.GetAFKChannelAsync(CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<IVoiceChannel>(AFKChannel); | => Task.FromResult<IVoiceChannel>(AFKChannel); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -1436,6 +1478,9 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| async Task<IReadOnlyCollection<IWebhook>> IGuild.GetWebhooksAsync(RequestOptions options) | async Task<IReadOnlyCollection<IWebhook>> IGuild.GetWebhooksAsync(RequestOptions options) | ||||
| => await GetWebhooksAsync(options).ConfigureAwait(false); | => await GetWebhooksAsync(options).ConfigureAwait(false); | ||||
| /// <inheritdoc /> | |||||
| async Task<IReadOnlyCollection<IApplicationCommand>> IGuild.GetApplicationCommandsAsync (RequestOptions options) | |||||
| => await GetApplicationCommandsAsync(options).ConfigureAwait(false); | |||||
| void IDisposable.Dispose() | void IDisposable.Dispose() | ||||
| { | { | ||||
| @@ -1443,5 +1488,7 @@ namespace Discord.WebSocket | |||||
| _audioLock?.Dispose(); | _audioLock?.Dispose(); | ||||
| _audioClient?.Dispose(); | _audioClient?.Dispose(); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,12 +4,13 @@ using System.Threading.Tasks; | |||||
| using Model = Discord.API.Interaction; | using Model = Discord.API.Interaction; | ||||
| using DataModel = Discord.API.MessageComponentInteractionData; | using DataModel = Discord.API.MessageComponentInteractionData; | ||||
| using Discord.Rest; | using Discord.Rest; | ||||
| using System.Collections.Generic; | |||||
| namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Represents a Websocket-based interaction type for Message Components. | |||||
| /// </summary> | |||||
| /// <summary> | |||||
| /// Represents a Websocket-based interaction type for Message Components. | |||||
| /// </summary> | |||||
| public class SocketMessageComponent : SocketInteraction | public class SocketMessageComponent : SocketInteraction | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -123,7 +124,7 @@ namespace Discord.WebSocket | |||||
| }; | }; | ||||
| if (ephemeral) | if (ephemeral) | ||||
| response.Data.Value.Flags = 64; | |||||
| response.Data.Value.Flags = MessageFlags.Ephemeral; | |||||
| await InteractionHelper.SendInteractionResponse(this.Discord, response, this.Id, Token, options); | await InteractionHelper.SendInteractionResponse(this.Discord, response, this.Id, Token, options); | ||||
| } | } | ||||
| @@ -149,8 +150,28 @@ namespace Discord.WebSocket | |||||
| Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed."); | Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed."); | ||||
| } | } | ||||
| if (args.Embeds.IsSpecified) | |||||
| Preconditions.AtMost(args.Embeds.Value?.Length ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||||
| var embed = args.Embed; | |||||
| var embeds = args.Embeds; | |||||
| 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(); | |||||
| if (!hasText && !hasEmbeds) | |||||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | |||||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | |||||
| if (embed.IsSpecified && embed.Value != null) | |||||
| { | |||||
| apiEmbeds.Add(embed.Value.ToModel()); | |||||
| } | |||||
| if (embeds.IsSpecified && embeds.Value != null) | |||||
| { | |||||
| apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); | |||||
| } | |||||
| Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||||
| // check that user flag and user Id list are exclusive, same with role flag and role Id list | // check that user flag and user Id list are exclusive, same with role flag and role Id list | ||||
| if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue) | if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue) | ||||
| @@ -176,11 +197,11 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| Content = args.Content, | Content = args.Content, | ||||
| AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified, | AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified, | ||||
| Embeds = args.Embeds.IsSpecified ? args.Embeds.Value?.Select(x => x.ToModel()).ToArray() : Optional<API.Embed[]>.Unspecified, | |||||
| Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified, | |||||
| Components = args.Components.IsSpecified | Components = args.Components.IsSpecified | ||||
| ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() | ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() | ||||
| : Optional<API.ActionRowComponent[]>.Unspecified, | : Optional<API.ActionRowComponent[]>.Unspecified, | ||||
| Flags = args.Flags.IsSpecified ? (int?)args.Flags.Value ?? Optional<int>.Unspecified : Optional<int>.Unspecified | |||||
| Flags = args.Flags.IsSpecified ? args.Flags.Value ?? Optional<MessageFlags>.Unspecified : Optional<MessageFlags>.Unspecified | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -213,27 +234,43 @@ namespace Discord.WebSocket | |||||
| AllowedMentions = allowedMentions?.ToModel() ?? Optional<API.AllowedMentions>.Unspecified, | AllowedMentions = allowedMentions?.ToModel() ?? Optional<API.AllowedMentions>.Unspecified, | ||||
| IsTTS = isTTS, | IsTTS = isTTS, | ||||
| Embeds = embeds?.Select(x => x.ToModel()).ToArray() ?? Optional<API.Embed[]>.Unspecified, | Embeds = embeds?.Select(x => x.ToModel()).ToArray() ?? Optional<API.Embed[]>.Unspecified, | ||||
| Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified | |||||
| Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, | |||||
| }; | }; | ||||
| if (ephemeral) | if (ephemeral) | ||||
| args.Flags = 64; | |||||
| args.Flags = MessageFlags.Ephemeral; | |||||
| return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); | return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); | ||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Acknowledges this interaction with the <see cref="InteractionResponseType.DeferredUpdateMessage"/>. | |||||
| /// Defers an interaction and responds with type 5 (<see cref="InteractionResponseType.DeferredChannelMessageWithSource"/>) | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="ephemeral"><see langword="true"/> to send this message ephemerally, otherwise <see langword="false"/>.</param> | |||||
| /// <param name="options">The request options for this async request.</param> | /// <param name="options">The request options for this async request.</param> | ||||
| /// <returns> | /// <returns> | ||||
| /// A task that represents the asynchronous operation of acknowledging the interaction. | /// A task that represents the asynchronous operation of acknowledging the interaction. | ||||
| /// </returns> | /// </returns> | ||||
| public override Task DeferAsync(RequestOptions options = null) | |||||
| public Task DeferLoadingAsync(bool ephemeral = false, RequestOptions options = null) | |||||
| { | |||||
| var response = new API.InteractionResponse() | |||||
| { | |||||
| Type = InteractionResponseType.DeferredChannelMessageWithSource, | |||||
| Data = ephemeral ? new API.InteractionCallbackData() { Flags = MessageFlags.Ephemeral } : Optional<API.InteractionCallbackData>.Unspecified | |||||
| }; | |||||
| return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) | |||||
| { | { | ||||
| var response = new API.InteractionResponse() | var response = new API.InteractionResponse() | ||||
| { | { | ||||
| Type = InteractionResponseType.DeferredUpdateMessage, | Type = InteractionResponseType.DeferredUpdateMessage, | ||||
| Data = ephemeral ? new API.InteractionCallbackData() { Flags = MessageFlags.Ephemeral } : Optional<API.InteractionCallbackData>.Unspecified | |||||
| }; | }; | ||||
| return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); | return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); | ||||
| @@ -106,7 +106,7 @@ namespace Discord.WebSocket | |||||
| }; | }; | ||||
| if (ephemeral) | if (ephemeral) | ||||
| response.Data.Value.Flags = 64; | |||||
| response.Data.Value.Flags = MessageFlags.Ephemeral; | |||||
| await InteractionHelper.SendInteractionResponse(this.Discord, response, this.Id, Token, options); | await InteractionHelper.SendInteractionResponse(this.Discord, response, this.Id, Token, options); | ||||
| } | } | ||||
| @@ -141,22 +141,18 @@ namespace Discord.WebSocket | |||||
| }; | }; | ||||
| if (ephemeral) | if (ephemeral) | ||||
| args.Flags = 64; | |||||
| args.Flags = MessageFlags.Ephemeral; | |||||
| return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); | return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Acknowledges this interaction with the <see cref="InteractionResponseType.DeferredChannelMessageWithSource"/>. | |||||
| /// </summary> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous operation of acknowledging the interaction. | |||||
| /// </returns> | |||||
| public override Task DeferAsync(RequestOptions options = null) | |||||
| /// <inheritdoc/> | |||||
| public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) | |||||
| { | { | ||||
| var response = new API.InteractionResponse | var response = new API.InteractionResponse | ||||
| { | { | ||||
| Type = InteractionResponseType.DeferredChannelMessageWithSource, | Type = InteractionResponseType.DeferredChannelMessageWithSource, | ||||
| Data = ephemeral ? new API.InteractionCallbackData() { Flags = MessageFlags.Ephemeral } : Optional<API.InteractionCallbackData>.Unspecified | |||||
| }; | }; | ||||
| return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); | return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); | ||||
| @@ -86,9 +86,9 @@ namespace Discord.WebSocket | |||||
| break; | break; | ||||
| case ApplicationCommandOptionType.Integer: | case ApplicationCommandOptionType.Integer: | ||||
| { | { | ||||
| if (model.Value.Value is int val) | |||||
| if (model.Value.Value is long val) | |||||
| this.Value = val; | this.Value = val; | ||||
| else if (int.TryParse(model.Value.Value.ToString(), out int res)) | |||||
| else if (long.TryParse(model.Value.Value.ToString(), out long res)) | |||||
| this.Value = res; | this.Value = res; | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -109,7 +109,7 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| this.Options = model.Options.IsSpecified | this.Options = model.Options.IsSpecified | ||||
| @@ -156,20 +156,37 @@ namespace Discord.WebSocket | |||||
| /// A task that represents the asynchronous operation of acknowledging the interaction. | /// A task that represents the asynchronous operation of acknowledging the interaction. | ||||
| /// </returns> | /// </returns> | ||||
| [Obsolete("This method deprecated, please use DeferAsync instead")] | [Obsolete("This method deprecated, please use DeferAsync instead")] | ||||
| public Task AcknowledgeAsync(RequestOptions options = null) => DeferAsync(options); | |||||
| public Task AcknowledgeAsync(RequestOptions options = null) => DeferAsync(options: options); | |||||
| /// <summary> | /// <summary> | ||||
| /// Acknowledges this interaction. | /// Acknowledges this interaction. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="ephemeral"><see langword="true"/> to send this message ephemerally, otherwise <see langword="false"/>.</param> | |||||
| /// <param name="options">The request options for this async request.</param> | |||||
| /// <returns> | /// <returns> | ||||
| /// A task that represents the asynchronous operation of acknowledging the interaction. | /// A task that represents the asynchronous operation of acknowledging the interaction. | ||||
| /// </returns> | /// </returns> | ||||
| public abstract Task DeferAsync(RequestOptions options = null); | |||||
| public abstract Task DeferAsync(bool ephemeral = false, RequestOptions options = null); | |||||
| private bool CheckToken() | private bool CheckToken() | ||||
| { | { | ||||
| // Tokens last for 15 minutes according to https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction | // Tokens last for 15 minutes according to https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction | ||||
| return (DateTime.UtcNow - this.CreatedAt.UtcDateTime).TotalMinutes <= 15d; | return (DateTime.UtcNow - this.CreatedAt.UtcDateTime).TotalMinutes <= 15d; | ||||
| } | } | ||||
| // IDiscordInteraction | |||||
| /// <inheritdoc/> | |||||
| async Task<IUserMessage> IDiscordInteraction.FollowupAsync (string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, | |||||
| RequestOptions options, MessageComponent component, Embed embed) | |||||
| => await FollowupAsync(text, embeds, isTTS, ephemeral, allowedMentions, options, component, embed).ConfigureAwait(false); | |||||
| /// <inheritdoc/> | |||||
| async Task<IUserMessage> IDiscordInteraction.GetOriginalResponseAsync (RequestOptions options) | |||||
| => await GetOriginalResponseAsync(options).ConfigureAwait(false); | |||||
| /// <inheritdoc/> | |||||
| async Task<IUserMessage> IDiscordInteraction.ModifyOriginalResponseAsync (Action<MessageProperties> func, RequestOptions options) | |||||
| => await ModifyOriginalResponseAsync(func, options).ConfigureAwait(false); | |||||
| } | } | ||||
| } | } | ||||
| @@ -122,7 +122,10 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| internal static SocketMessage Create(DiscordSocketClient discord, ClientState state, SocketUser author, ISocketMessageChannel channel, Model model) | internal static SocketMessage Create(DiscordSocketClient discord, ClientState state, SocketUser author, ISocketMessageChannel channel, Model model) | ||||
| { | { | ||||
| if (model.Type == MessageType.Default || model.Type == MessageType.Reply) | |||||
| if (model.Type == MessageType.Default || | |||||
| model.Type == MessageType.Reply || | |||||
| model.Type == MessageType.ApplicationCommand || | |||||
| model.Type == MessageType.ThreadStarterMessage) | |||||
| return SocketUserMessage.Create(discord, state, author, channel, model); | return SocketUserMessage.Create(discord, state, author, channel, model); | ||||
| else | else | ||||
| return SocketSystemMessage.Create(discord, state, author, channel, model); | return SocketSystemMessage.Create(discord, state, author, channel, model); | ||||
| @@ -12,6 +12,8 @@ namespace Discord.WebSocket | |||||
| public override string Username { get; internal set; } | public override string Username { get; internal set; } | ||||
| public override ushort DiscriminatorValue { get; internal set; } | public override ushort DiscriminatorValue { get; internal set; } | ||||
| public override string AvatarId { get; internal set; } | public override string AvatarId { get; internal set; } | ||||
| public override string BannerId { get; internal set; } | |||||
| public override Color? AccentColor { get; internal set; } | |||||
| internal override SocketPresence Presence { get; set; } | internal override SocketPresence Presence { get; set; } | ||||
| public override bool IsWebhook => false; | public override bool IsWebhook => false; | ||||
| @@ -47,7 +49,7 @@ namespace Discord.WebSocket | |||||
| discord.RemoveUser(Id); | discord.RemoveUser(Id); | ||||
| } | } | ||||
| } | } | ||||
| internal void Update(ClientState state, PresenceModel model) | internal void Update(ClientState state, PresenceModel model) | ||||
| { | { | ||||
| Presence = SocketPresence.Create(model); | Presence = SocketPresence.Create(model); | ||||
| @@ -1,3 +1,4 @@ | |||||
| using System; | |||||
| using System.Diagnostics; | using System.Diagnostics; | ||||
| using Model = Discord.API.User; | using Model = Discord.API.User; | ||||
| @@ -28,6 +29,10 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } | |||||
| /// <inheritdoc /> | |||||
| public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } | |||||
| /// <inheritdoc /> | |||||
| internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } | internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -66,5 +71,7 @@ namespace Discord.WebSocket | |||||
| string IVoiceState.VoiceSessionId => null; | string IVoiceState.VoiceSessionId => null; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
| /// <inheritdoc /> | |||||
| DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | |||||
| } | } | ||||
| } | } | ||||
| @@ -38,6 +38,11 @@ namespace Discord.WebSocket | |||||
| public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } | public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | ||||
| /// <inheritdoc /> | |||||
| public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } | |||||
| /// <inheritdoc /> | |||||
| public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); | public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); | ||||
| internal override SocketPresence Presence { get; set; } | internal override SocketPresence Presence { get; set; } | ||||
| @@ -57,7 +62,11 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public bool IsStreaming => VoiceState?.IsStreaming ?? false; | public bool IsStreaming => VoiceState?.IsStreaming ?? false; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DateTimeOffset? RequestToSpeakTimestamp => VoiceState?.RequestToSpeakTimestamp ?? null; | |||||
| /// <inheritdoc /> | |||||
| public bool? IsPending { get; private set; } | public bool? IsPending { get; private set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); | public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -87,7 +96,7 @@ namespace Discord.WebSocket | |||||
| /// Returns the position of the user within the role hierarchy. | /// Returns the position of the user within the role hierarchy. | ||||
| /// </summary> | /// </summary> | ||||
| /// <remarks> | /// <remarks> | ||||
| /// The returned value equal to the position of the highest role the user has, or | |||||
| /// The returned value equal to the position of the highest role the user has, or | |||||
| /// <see cref="int.MaxValue"/> if user is the server owner. | /// <see cref="int.MaxValue"/> if user is the server owner. | ||||
| /// </remarks> | /// </remarks> | ||||
| public int Hierarchy | public int Hierarchy | ||||
| @@ -29,6 +29,10 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } | |||||
| /// <inheritdoc /> | |||||
| public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } | |||||
| /// <inheritdoc /> | |||||
| internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } | internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public UserProperties Flags { get; internal set; } | public UserProperties Flags { get; internal set; } | ||||
| @@ -36,7 +36,7 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public string Nickname | public string Nickname | ||||
| => GuildUser.Nickname; | |||||
| => GuildUser.Nickname; | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public DateTimeOffset? PremiumSince | public DateTimeOffset? PremiumSince | ||||
| @@ -53,6 +53,20 @@ namespace Discord.WebSocket | |||||
| internal set => GuildUser.AvatarId = value; | internal set => GuildUser.AvatarId = value; | ||||
| } | } | ||||
| /// <inheritdoc/> | |||||
| public override string BannerId | |||||
| { | |||||
| get => GuildUser.BannerId; | |||||
| internal set => GuildUser.BannerId = value; | |||||
| } | |||||
| /// <inheritdoc/> | |||||
| public override Color? AccentColor | |||||
| { | |||||
| get => GuildUser.AccentColor; | |||||
| internal set => GuildUser.AccentColor = value; | |||||
| } | |||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| public override ushort DiscriminatorValue | public override ushort DiscriminatorValue | ||||
| { | { | ||||
| @@ -110,6 +124,10 @@ namespace Discord.WebSocket | |||||
| public bool IsStreaming | public bool IsStreaming | ||||
| => GuildUser.IsStreaming; | => GuildUser.IsStreaming; | ||||
| /// <inheritdoc/> | |||||
| public DateTimeOffset? RequestToSpeakTimestamp | |||||
| => GuildUser.RequestToSpeakTimestamp; | |||||
| private SocketGuildUser GuildUser { get; set; } | private SocketGuildUser GuildUser { get; set; } | ||||
| internal SocketThreadUser(SocketGuild guild, SocketThreadChannel thread, SocketGuildUser member) | internal SocketThreadUser(SocketGuild guild, SocketThreadChannel thread, SocketGuildUser member) | ||||
| @@ -19,9 +19,16 @@ namespace Discord.WebSocket | |||||
| public override ushort DiscriminatorValue { get; internal set; } | public override ushort DiscriminatorValue { get; internal set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string AvatarId { get; internal set; } | public override string AvatarId { get; internal set; } | ||||
| /// <inheritdoc /> | |||||
| public override string BannerId { get; internal set; } | |||||
| /// <inheritdoc /> | |||||
| public override Color? AccentColor { get; internal set; } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override bool IsBot { get; internal set; } | public override bool IsBot { get; internal set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override bool IsWebhook => false; | public override bool IsWebhook => false; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -25,6 +25,10 @@ namespace Discord.WebSocket | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public abstract string AvatarId { get; internal set; } | public abstract string AvatarId { get; internal set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public abstract string BannerId { get; internal set; } | |||||
| /// <inheritdoc /> | |||||
| public abstract Color? AccentColor { get; internal set; } | |||||
| /// <inheritdoc /> | |||||
| public abstract bool IsWebhook { get; } | public abstract bool IsWebhook { get; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public UserProperties? PublicFlags { get; private set; } | public UserProperties? PublicFlags { get; private set; } | ||||
| @@ -64,6 +68,16 @@ namespace Discord.WebSocket | |||||
| AvatarId = model.Avatar.Value; | AvatarId = model.Avatar.Value; | ||||
| hasChanges = true; | hasChanges = true; | ||||
| } | } | ||||
| if (model.Banner.IsSpecified && model.Banner.Value != BannerId) | |||||
| { | |||||
| BannerId = model.Banner.Value; | |||||
| hasChanges = true; | |||||
| } | |||||
| if (model.AccentColor.IsSpecified && model.AccentColor.Value != AccentColor?.RawValue) | |||||
| { | |||||
| AccentColor = model.AccentColor.Value; | |||||
| hasChanges = true; | |||||
| } | |||||
| if (model.Discriminator.IsSpecified) | if (model.Discriminator.IsSpecified) | ||||
| { | { | ||||
| var newVal = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); | var newVal = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); | ||||
| @@ -99,6 +113,10 @@ namespace Discord.WebSocket | |||||
| public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | ||||
| => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); | => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); | ||||
| /// <inheritdoc /> | |||||
| public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) | |||||
| => CDN.GetUserBannerUrl(Id, BannerId, size, format); | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string GetDefaultAvatarUrl() | public string GetDefaultAvatarUrl() | ||||
| => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); | => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); | ||||
| @@ -13,7 +13,7 @@ namespace Discord.WebSocket | |||||
| /// <summary> | /// <summary> | ||||
| /// Initializes a default <see cref="SocketVoiceState"/> with everything set to <c>null</c> or <c>false</c>. | /// Initializes a default <see cref="SocketVoiceState"/> with everything set to <c>null</c> or <c>false</c>. | ||||
| /// </summary> | /// </summary> | ||||
| public static readonly SocketVoiceState Default = new SocketVoiceState(null, null, false, false, false, false, false, false); | |||||
| public static readonly SocketVoiceState Default = new SocketVoiceState(null, null, null, false, false, false, false, false, false); | |||||
| [Flags] | [Flags] | ||||
| private enum Flags : byte | private enum Flags : byte | ||||
| @@ -35,6 +35,8 @@ namespace Discord.WebSocket | |||||
| public SocketVoiceChannel VoiceChannel { get; } | public SocketVoiceChannel VoiceChannel { get; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string VoiceSessionId { get; } | public string VoiceSessionId { get; } | ||||
| /// <inheritdoc/> | |||||
| public DateTimeOffset? RequestToSpeakTimestamp { get; private set; } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public bool IsMuted => (_voiceStates & Flags.Muted) != 0; | public bool IsMuted => (_voiceStates & Flags.Muted) != 0; | ||||
| @@ -48,11 +50,13 @@ namespace Discord.WebSocket | |||||
| public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0; | public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public bool IsStreaming => (_voiceStates & Flags.SelfStream) != 0; | public bool IsStreaming => (_voiceStates & Flags.SelfStream) != 0; | ||||
| internal SocketVoiceState(SocketVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isMuted, bool isDeafened, bool isSuppressed, bool isStream) | |||||
| internal SocketVoiceState(SocketVoiceChannel voiceChannel, DateTimeOffset? requestToSpeak, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isMuted, bool isDeafened, bool isSuppressed, bool isStream) | |||||
| { | { | ||||
| VoiceChannel = voiceChannel; | VoiceChannel = voiceChannel; | ||||
| VoiceSessionId = sessionId; | VoiceSessionId = sessionId; | ||||
| RequestToSpeakTimestamp = requestToSpeak; | |||||
| Flags voiceStates = Flags.Normal; | Flags voiceStates = Flags.Normal; | ||||
| if (isSelfMuted) | if (isSelfMuted) | ||||
| @@ -71,7 +75,7 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| internal static SocketVoiceState Create(SocketVoiceChannel voiceChannel, Model model) | internal static SocketVoiceState Create(SocketVoiceChannel voiceChannel, Model model) | ||||
| { | { | ||||
| return new SocketVoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Mute, model.Deaf, model.Suppress, model.SelfStream); | |||||
| return new SocketVoiceState(voiceChannel, model.RequestToSpeakTimestamp.IsSpecified ? model.RequestToSpeakTimestamp.Value : null, model.SessionId, model.SelfMute, model.SelfDeaf, model.Mute, model.Deaf, model.Suppress, model.SelfStream); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -24,6 +24,23 @@ namespace Discord.WebSocket | |||||
| public override ushort DiscriminatorValue { get; internal set; } | public override ushort DiscriminatorValue { get; internal set; } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override string AvatarId { get; internal set; } | public override string AvatarId { get; internal set; } | ||||
| /// <inheritdoc /> | |||||
| /// <exception cref="NotSupportedException">Webhook users does not support banners.</exception> | |||||
| public override string BannerId | |||||
| { | |||||
| get => throw new NotSupportedException("Webhook users does not support banners."); | |||||
| internal set => throw new NotSupportedException("Webhook users does not support banners."); | |||||
| } | |||||
| /// <inheritdoc /> | |||||
| /// <exception cref="NotSupportedException">Webhook users does not support accent colors.</exception> | |||||
| public override Color? AccentColor | |||||
| { | |||||
| get => throw new NotSupportedException("Webhook users does not support accent colors."); | |||||
| internal set => throw new NotSupportedException("Webhook users does not support accent colors."); | |||||
| } | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public override bool IsBot { get; internal set; } | public override bool IsBot { get; internal set; } | ||||
| @@ -138,5 +155,7 @@ namespace Discord.WebSocket | |||||
| string IVoiceState.VoiceSessionId => null; | string IVoiceState.VoiceSessionId => null; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| bool IVoiceState.IsStreaming => false; | bool IVoiceState.IsStreaming => false; | ||||
| /// <inheritdoc /> | |||||
| DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; | |||||
| } | } | ||||
| } | } | ||||
| @@ -6,7 +6,7 @@ | |||||
| <RootNamespace>Discord.Webhook</RootNamespace> | <RootNamespace>Discord.Webhook</RootNamespace> | ||||
| <Description>A core Discord.Net Labs library containing the Webhook client and models.</Description> | <Description>A core Discord.Net Labs library containing the Webhook client and models.</Description> | ||||
| <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> | <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> | ||||
| <Version>2.3.4</Version> | |||||
| <Version>3.0.0-pre</Version> | |||||
| <PackageId>Discord.Net.Labs.Webhook</PackageId> | <PackageId>Discord.Net.Labs.Webhook</PackageId> | ||||
| <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | <PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl> | ||||
| <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | <RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl> | ||||
| @@ -31,7 +31,7 @@ | |||||
| <exception cref="T:System.ArgumentException">Thrown if the <paramref name="webhookUrl"/> is an invalid format.</exception> | <exception cref="T:System.ArgumentException">Thrown if the <paramref name="webhookUrl"/> is an invalid format.</exception> | ||||
| <exception cref="T:System.ArgumentNullException">Thrown if the <paramref name="webhookUrl"/> is null or whitespace.</exception> | <exception cref="T:System.ArgumentNullException">Thrown if the <paramref name="webhookUrl"/> is null or whitespace.</exception> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.Webhook.DiscordWebhookClient.SendMessageAsync(System.String,System.Boolean,System.Collections.Generic.IEnumerable{Discord.Embed},System.String,System.String,Discord.RequestOptions,Discord.AllowedMentions)"> | |||||
| <member name="M:Discord.Webhook.DiscordWebhookClient.SendMessageAsync(System.String,System.Boolean,System.Collections.Generic.IEnumerable{Discord.Embed},System.String,System.String,Discord.RequestOptions,Discord.AllowedMentions,Discord.MessageComponent)"> | |||||
| <summary> Sends a message to the channel for this webhook. </summary> | <summary> Sends a message to the channel for this webhook. </summary> | ||||
| <returns> Returns the ID of the created message. </returns> | <returns> Returns the ID of the created message. </returns> | ||||
| </member> | </member> | ||||
| @@ -99,6 +99,11 @@ | |||||
| Gets or sets the allowed mentions of the message. | Gets or sets the allowed mentions of the message. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="P:Discord.Webhook.WebhookMessageProperties.Components"> | |||||
| <summary> | |||||
| Gets or sets the components that the message should display. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="M:Discord.Webhook.WebhookClientHelper.GetWebhookAsync(Discord.Webhook.DiscordWebhookClient,System.UInt64)"> | <member name="M:Discord.Webhook.WebhookClientHelper.GetWebhookAsync(Discord.Webhook.DiscordWebhookClient,System.UInt64)"> | ||||
| <exception cref="T:System.InvalidOperationException">Could not find a webhook with the supplied credentials.</exception> | <exception cref="T:System.InvalidOperationException">Could not find a webhook with the supplied credentials.</exception> | ||||
| </member> | </member> | ||||
| @@ -88,8 +88,8 @@ namespace Discord.Webhook | |||||
| /// <summary> Sends a message to the channel for this webhook. </summary> | /// <summary> Sends a message to the channel for this webhook. </summary> | ||||
| /// <returns> Returns the ID of the created message. </returns> | /// <returns> Returns the ID of the created message. </returns> | ||||
| public Task<ulong> SendMessageAsync(string text = null, bool isTTS = false, IEnumerable<Embed> embeds = null, | public Task<ulong> SendMessageAsync(string text = null, bool isTTS = false, IEnumerable<Embed> embeds = null, | ||||
| string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null) | |||||
| => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options); | |||||
| string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent component = null) | |||||
| => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, component); | |||||
| /// <summary> | /// <summary> | ||||
| /// Modifies a message posted using this webhook. | /// Modifies a message posted using this webhook. | ||||
| @@ -22,5 +22,9 @@ namespace Discord.Webhook | |||||
| /// Gets or sets the allowed mentions of the message. | /// Gets or sets the allowed mentions of the message. | ||||
| /// </summary> | /// </summary> | ||||
| public Optional<AllowedMentions> AllowedMentions { get; set; } | public Optional<AllowedMentions> AllowedMentions { get; set; } | ||||
| /// <summary> | |||||
| /// Gets or sets the components that the message should display. | |||||
| /// </summary> | |||||
| public Optional<MessageComponent> Components { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -17,6 +17,7 @@ namespace Discord.Webhook | |||||
| public string Name { get; private set; } | public string Name { get; private set; } | ||||
| public string AvatarId { get; private set; } | public string AvatarId { get; private set; } | ||||
| public ulong? GuildId { get; private set; } | public ulong? GuildId { get; private set; } | ||||
| public ulong? ApplicationId { get; private set; } | |||||
| public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | ||||
| @@ -44,6 +45,8 @@ namespace Discord.Webhook | |||||
| GuildId = model.GuildId.Value; | GuildId = model.GuildId.Value; | ||||
| if (model.Name.IsSpecified) | if (model.Name.IsSpecified) | ||||
| Name = model.Name.Value; | Name = model.Name.Value; | ||||
| ApplicationId = model.ApplicationId; | |||||
| } | } | ||||
| public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | ||||
| @@ -21,7 +21,7 @@ namespace Discord.Webhook | |||||
| return RestInternalWebhook.Create(client, model); | return RestInternalWebhook.Create(client, model); | ||||
| } | } | ||||
| public static async Task<ulong> SendMessageAsync(DiscordWebhookClient client, | public static async Task<ulong> SendMessageAsync(DiscordWebhookClient client, | ||||
| string text, bool isTTS, IEnumerable<Embed> embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options) | |||||
| string text, bool isTTS, IEnumerable<Embed> embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, MessageComponent component) | |||||
| { | { | ||||
| var args = new CreateWebhookMessageParams | var args = new CreateWebhookMessageParams | ||||
| { | { | ||||
| @@ -37,6 +37,8 @@ namespace Discord.Webhook | |||||
| args.AvatarUrl = avatarUrl; | args.AvatarUrl = avatarUrl; | ||||
| if (allowedMentions != null) | if (allowedMentions != null) | ||||
| args.AllowedMentions = allowedMentions.ToModel(); | args.AllowedMentions = allowedMentions.ToModel(); | ||||
| if (component != null) | |||||
| args.Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray(); | |||||
| var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false); | var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false); | ||||
| return model.Id; | return model.Id; | ||||
| @@ -83,7 +85,8 @@ namespace Discord.Webhook | |||||
| : Optional.Create<API.Embed[]>(), | : Optional.Create<API.Embed[]>(), | ||||
| AllowedMentions = args.AllowedMentions.IsSpecified | AllowedMentions = args.AllowedMentions.IsSpecified | ||||
| ? args.AllowedMentions.Value.ToModel() | ? args.AllowedMentions.Value.ToModel() | ||||
| : Optional.Create<API.AllowedMentions>() | |||||
| : Optional.Create<API.AllowedMentions>(), | |||||
| Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | |||||
| }; | }; | ||||
| await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options) | await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options) | ||||
| @@ -2,7 +2,7 @@ | |||||
| <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | ||||
| <metadata> | <metadata> | ||||
| <id>Discord.Net.Labs</id> | <id>Discord.Net.Labs</id> | ||||
| <version>2.4.9$suffix$</version> | |||||
| <version>3.0.2-pre$suffix$</version> | |||||
| <title>Discord.Net Labs</title> | <title>Discord.Net Labs</title> | ||||
| <authors>Discord.Net Contributors</authors> | <authors>Discord.Net Contributors</authors> | ||||
| <owners>quinchs</owners> | <owners>quinchs</owners> | ||||
| @@ -14,23 +14,23 @@ | |||||
| <iconUrl>https://avatars.githubusercontent.com/u/84047264</iconUrl> | <iconUrl>https://avatars.githubusercontent.com/u/84047264</iconUrl> | ||||
| <dependencies> | <dependencies> | ||||
| <group targetFramework="net461"> | <group targetFramework="net461"> | ||||
| <dependency id="Discord.Net.Labs.Core" version="2.4.6$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Rest" version="2.4.6$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.WebSocket" version="2.4.8$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Core" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Rest" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.WebSocket" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" /> | <dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" /> | ||||
| <dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" /> | <dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" /> | ||||
| </group> | </group> | ||||
| <group targetFramework="netstandard2.0"> | <group targetFramework="netstandard2.0"> | ||||
| <dependency id="Discord.Net.Labs.Core" version="2.4.6$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Rest" version="2.4.6$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.WebSocket" version="2.4.8$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Core" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Rest" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.WebSocket" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" /> | <dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" /> | ||||
| <dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" /> | <dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" /> | ||||
| </group> | </group> | ||||
| <group targetFramework="netstandard2.1"> | <group targetFramework="netstandard2.1"> | ||||
| <dependency id="Discord.Net.Labs.Core" version="2.4.6$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Rest" version="2.4.6$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.WebSocket" version="2.4.8$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Core" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Rest" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.WebSocket" version="3.0.1-pre$suffix$" /> | |||||
| <dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" /> | <dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" /> | ||||
| <dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" /> | <dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" /> | ||||
| </group> | </group> | ||||
| @@ -91,7 +91,13 @@ namespace Discord | |||||
| AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); | AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); | ||||
| AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); | AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); | ||||
| AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); | AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); | ||||
| AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojis); | |||||
| AssertFlag(() => new GuildPermissions(manageEmojisAndStickers: true), GuildPermission.ManageEmojisAndStickers); | |||||
| AssertFlag(() => new GuildPermissions(useSlashCommands: true), GuildPermission.UseSlashCommands); | |||||
| AssertFlag(() => new GuildPermissions(requestToSpeak: true), GuildPermission.RequestToSpeak); | |||||
| AssertFlag(() => new GuildPermissions(manageThreads: true), GuildPermission.ManageThreads); | |||||
| AssertFlag(() => new GuildPermissions(usePublicThreads: true), GuildPermission.UsePublicThreads); | |||||
| AssertFlag(() => new GuildPermissions(usePrivateThreads: true), GuildPermission.UsePrivateThreads); | |||||
| AssertFlag(() => new GuildPermissions(useExternalStickers: true), GuildPermission.UseExternalStickers); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -161,7 +167,13 @@ namespace Discord | |||||
| AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); | AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); | ||||
| AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); | AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); | ||||
| AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); | AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); | ||||
| AssertUtil(GuildPermission.ManageEmojis, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojis: enable)); | |||||
| AssertUtil(GuildPermission.ManageEmojisAndStickers, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojisAndStickers: enable)); | |||||
| AssertUtil(GuildPermission.UseSlashCommands, x => x.UseSlashCommands, (p, enable) => p.Modify(useSlashCommands: enable)); | |||||
| AssertUtil(GuildPermission.RequestToSpeak, x => x.RequestToSpeak, (p, enable) => p.Modify(requestToSpeak: enable)); | |||||
| AssertUtil(GuildPermission.ManageThreads, x => x.ManageThreads, (p, enable) => p.Modify(manageThreads: enable)); | |||||
| AssertUtil(GuildPermission.UsePublicThreads, x => x.UsePublicThreads, (p, enable) => p.Modify(usePublicThreads: enable)); | |||||
| AssertUtil(GuildPermission.UsePrivateThreads, x => x.UsePrivateThreads, (p, enable) => p.Modify(usePrivateThreads: enable)); | |||||
| AssertUtil(GuildPermission.UseExternalStickers, x => x.UseExternalStickers, (p, enable) => p.Modify(useExternalStickers: enable)); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||