@@ -212,6 +212,16 @@ | |||||
A URL pointing to the Spotify track. | A URL pointing to the Spotify track. | ||||
</returns> | </returns> | ||||
</member> | </member> | ||||
<member name="M:Discord.CDN.GetStickerUrl(System.UInt64,Discord.StickerFormatType)"> | |||||
<summary> | |||||
Gets a stickers url based off the id and format. | |||||
</summary> | |||||
<param name="stickerId">The id of the sticker.</param> | |||||
<param name="format">The format of the sticker</param> | |||||
<returns> | |||||
A URL to the sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="T:Discord.Commands.ICommandContext"> | <member name="T:Discord.Commands.ICommandContext"> | ||||
<summary> | <summary> | ||||
Represents a context of a command. This may include the client, guild, channel, user, and message. | Represents a context of a command. This may include the client, guild, channel, user, and message. | ||||
@@ -3121,6 +3131,14 @@ | |||||
A read-only collection of all custom emotes for this guild. | A read-only collection of all custom emotes for this guild. | ||||
</returns> | </returns> | ||||
</member> | </member> | ||||
<member name="P:Discord.IGuild.Stickers"> | |||||
<summary> | |||||
Gets a collection of all custom stickers for this guild. | |||||
</summary> | |||||
<returns> | |||||
A read-only collection of all custom stickers for this guild. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.IGuild.Features"> | <member name="P:Discord.IGuild.Features"> | ||||
<summary> | <summary> | ||||
Gets a collection of all extra features added to this guild. | Gets a collection of all extra features added to this guild. | ||||
@@ -3914,6 +3932,52 @@ | |||||
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.CreateStickerAsync(System.String,System.String,System.Collections.Generic.IEnumerable{System.String},Discord.Image,Discord.RequestOptions)"> | |||||
<summary> | |||||
Creates a new sticker in this guild. | |||||
</summary> | |||||
<param name="name">The name of the sticker.</param> | |||||
<param name="description">The description of the sticker.</param> | |||||
<param name="tags">The tags of the sticker.</param> | |||||
<param name="image">The image of the new emote.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous creation operation. The task result contains the created sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.IGuild.GetStickerAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a specific sticker within this guild. | |||||
</summary> | |||||
<param name="id">The id of the sticker to get.</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 sticker found with the | |||||
specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.IGuild.GetStickersAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a collection of all stickers within 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 stickers found within the guild. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.IGuild.DeleteStickerAsync(Discord.ICustomSticker,Discord.RequestOptions)"> | |||||
<summary> | |||||
Deletes a sticker within this guild. | |||||
</summary> | |||||
<param name="sticker">The sticker to delete.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous removal operation. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.IGuild.GetApplicationCommandsAsync(Discord.RequestOptions)"> | <member name="M:Discord.IGuild.GetApplicationCommandsAsync(Discord.RequestOptions)"> | ||||
<summary> | <summary> | ||||
Gets this guilds slash commands commands | Gets this guilds slash commands commands | ||||
@@ -7282,7 +7346,14 @@ | |||||
The <see cref="T:Discord.IMessageComponent"/>'s attached to this message | The <see cref="T:Discord.IMessageComponent"/>'s attached to this message | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<!-- Badly formed XML comment ignored for member "P:Discord.IMessage.Stickers" --> | |||||
<member name="P:Discord.IMessage.Stickers"> | |||||
<summary> | |||||
Gets all stickers items included in this message. | |||||
</summary> | |||||
<returns> | |||||
A read-only collection of sticker item objects. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.IMessage.Flags"> | <member name="P:Discord.IMessage.Flags"> | ||||
<summary> | <summary> | ||||
Gets the flags related to this message. | Gets the flags related to this message. | ||||
@@ -7411,75 +7482,6 @@ | |||||
The <see cref="T:Discord.IEmote" /> used in the reaction. | The <see cref="T:Discord.IEmote" /> used in the reaction. | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="T:Discord.ISticker"> | |||||
<summary> | |||||
Represents a discord sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Id"> | |||||
<summary> | |||||
Gets the ID of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A snowflake ID associated with this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.PackId"> | |||||
<summary> | |||||
Gets the ID of the pack of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A snowflake ID associated with the pack of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Name"> | |||||
<summary> | |||||
Gets the name of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the name of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Description"> | |||||
<summary> | |||||
Gets the description of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the description of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Tags"> | |||||
<summary> | |||||
Gets the list of tags of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A read-only list with the tags of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Asset"> | |||||
<summary> | |||||
Gets the asset hash of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the asset hash of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.PreviewAsset"> | |||||
<summary> | |||||
Gets the preview asset hash of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the preview asset hash of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.FormatType"> | |||||
<summary> | |||||
Gets the format type of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see cref="T:Discord.StickerFormatType"/> with the format type of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="T:Discord.ISystemMessage"> | <member name="T:Discord.ISystemMessage"> | ||||
<summary> | <summary> | ||||
Represents a generic message sent by the system. | Represents a generic message sent by the system. | ||||
@@ -9329,6 +9331,214 @@ | |||||
otherwise <see langword="false"/>. | otherwise <see langword="false"/>. | ||||
</returns> | </returns> | ||||
</member> | </member> | ||||
<member name="T:Discord.ICustomSticker"> | |||||
<summary> | |||||
Represents a custom sticker within a guild. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.ICustomSticker.AuthorId"> | |||||
<summary> | |||||
Gets the users id who uploaded the sticker. | |||||
</summary> | |||||
<remarks> | |||||
In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. | |||||
</remarks> | |||||
</member> | |||||
<member name="P:Discord.ICustomSticker.Guild"> | |||||
<summary> | |||||
Gets the guild that this custom sticker is in. | |||||
</summary> | |||||
</member> | |||||
<member name="M:Discord.ICustomSticker.ModifyAsync(System.Action{Discord.StickerProperties},Discord.RequestOptions)"> | |||||
<summary> | |||||
Modifies this sticker. | |||||
</summary> | |||||
<remarks> | |||||
This method modifies this sticker with the specified properties. To see an example of this | |||||
method and what properties are available, please refer to <see cref="T:Discord.StickerProperties"/>. | |||||
<br/> | |||||
<br/> | |||||
The bot needs the MANAGE_EMOJIS_AND_STICKERS permission within the guild in order to modify stickers. | |||||
</remarks> | |||||
<example> | |||||
<para>The following example replaces the name of the sticker with <c>kekw</c>.</para> | |||||
<code language="cs"> | |||||
await sticker.ModifyAsync(x => x.Name = "kekw"); | |||||
</code> | |||||
</example> | |||||
<param name="func">A delegate containing the properties to modify the sticker with.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous modification operation. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.ICustomSticker.DeleteAsync(Discord.RequestOptions)"> | |||||
<summary> | |||||
Deletes the current sticker. | |||||
</summary> | |||||
<remakrs> | |||||
The bot neeeds the MANAGE_EMOJIS_AND_STICKERS permission inside the guild in order to delete stickers. | |||||
</remakrs> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous deletion operation. | |||||
</returns> | |||||
</member> | |||||
<member name="T:Discord.ISticker"> | |||||
<summary> | |||||
Represents a discord sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Id"> | |||||
<summary> | |||||
Gets the ID of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A snowflake ID associated with this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.PackId"> | |||||
<summary> | |||||
Gets the ID of the pack of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A snowflake ID associated with the pack of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Name"> | |||||
<summary> | |||||
Gets the name of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the name of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Description"> | |||||
<summary> | |||||
Gets the description of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the description of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Tags"> | |||||
<summary> | |||||
Gets the list of tags of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A read-only list with the tags of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Asset"> | |||||
<summary> | |||||
Gets the asset hash of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the asset hash of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.PreviewAsset"> | |||||
<summary> | |||||
Gets the preview asset hash of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see langword="string"/> with the preview asset hash of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.ISticker.Format"> | |||||
<summary> | |||||
Gets the format type of this sticker. | |||||
</summary> | |||||
<returns> | |||||
A <see cref="T:Discord.StickerFormatType"/> with the format type of this sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.ISticker.GetStickerUrl"> | |||||
<summary> | |||||
Gets the image url for this sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="T:Discord.IStickerItem"> | |||||
<summary> | |||||
Represents a partial sticker item received with a message. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.IStickerItem.Id"> | |||||
<summary> | |||||
The id of the sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.IStickerItem.Name"> | |||||
<summary> | |||||
The name of the sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.IStickerItem.Format"> | |||||
<summary> | |||||
The format of the sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="T:Discord.StickerPack`1"> | |||||
<summary> | |||||
Represents a discord sticker pack. | |||||
</summary> | |||||
<typeparam name="TSticker">The type of the stickers within the collection</typeparam> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.Id"> | |||||
<summary> | |||||
Gets the id of the sticker pack. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.Stickers"> | |||||
<summary> | |||||
Gets a collection of the stickers in the pack. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.Name"> | |||||
<summary> | |||||
Gets the name of the sticker pack. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.SkuId"> | |||||
<summary> | |||||
Gets the id of the pack's SKU. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.CoverStickerId"> | |||||
<summary> | |||||
Gets the id of a sticker in the pack which is shown as the pack's icon. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.Description"> | |||||
<summary> | |||||
Gets the description of the sticker pack. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerPack`1.BannerAssetId"> | |||||
<summary> | |||||
Gets the id of the sticker pack's banner image | |||||
</summary> | |||||
</member> | |||||
<member name="T:Discord.StickerProperties"> | |||||
<summary> | |||||
Represents a class used to modify stickers. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerProperties.Name"> | |||||
<summary> | |||||
Gets or sets the name of the sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerProperties.Description"> | |||||
<summary> | |||||
Gets or sets the description of the sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.StickerProperties.Tags"> | |||||
<summary> | |||||
Gets or sets the tags of the sticker. | |||||
</summary> | |||||
</member> | |||||
<member name="T:Discord.ITeam"> | <member name="T:Discord.ITeam"> | ||||
<summary> | <summary> | ||||
Represents a Discord Team. | Represents a Discord Team. | ||||
@@ -169,12 +169,13 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
IReadOnlyCollection<IMessageComponent> Components { get; } | IReadOnlyCollection<IMessageComponent> Components { get; } | ||||
/// Gets all stickers included in this message. | |||||
/// <summary> | |||||
/// Gets all stickers items included in this message. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// A read-only collection of sticker objects. | |||||
/// A read-only collection of sticker item objects. | |||||
/// </returns> | /// </returns> | ||||
IReadOnlyCollection<ISticker> Stickers { get; } | |||||
IReadOnlyCollection<IStickerItem> Stickers { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the flags related to this message. | /// Gets the flags related to this message. | ||||
@@ -7,7 +7,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Represents a discord sticker. | /// Represents a discord sticker. | ||||
/// </summary> | /// </summary> | ||||
public interface ISticker | |||||
public interface ISticker : IStickerItem | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Gets the ID of this sticker. | /// Gets the ID of this sticker. | ||||
@@ -64,7 +64,7 @@ namespace Discord | |||||
/// <returns> | /// <returns> | ||||
/// A <see cref="StickerFormatType"/> with the format type of this sticker. | /// A <see cref="StickerFormatType"/> with the format type of this sticker. | ||||
/// </returns> | /// </returns> | ||||
StickerFormatType FormatType { get; } | |||||
StickerFormatType Format { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the image url for this sticker. | /// Gets the image url for this sticker. | ||||
@@ -0,0 +1,29 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents a partial sticker item received with a message. | |||||
/// </summary> | |||||
public interface IStickerItem | |||||
{ | |||||
/// <summary> | |||||
/// The id of the sticker. | |||||
/// </summary> | |||||
ulong Id { get; } | |||||
/// <summary> | |||||
/// The name of the sticker. | |||||
/// </summary> | |||||
string Name { get; } | |||||
/// <summary> | |||||
/// The format of the sticker. | |||||
/// </summary> | |||||
StickerFormatType Format { get; } | |||||
} | |||||
} |
@@ -0,0 +1,63 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Collections.Immutable; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents a discord sticker pack. | |||||
/// </summary> | |||||
/// <typeparam name="TSticker">The type of the stickers within the collection</typeparam> | |||||
public class StickerPack<TSticker> where TSticker : ISticker | |||||
{ | |||||
/// <summary> | |||||
/// Gets the id of the sticker pack. | |||||
/// </summary> | |||||
public ulong Id { get; } | |||||
/// <summary> | |||||
/// Gets a collection of the stickers in the pack. | |||||
/// </summary> | |||||
public IReadOnlyCollection<TSticker> Stickers { get; } | |||||
/// <summary> | |||||
/// Gets the name of the sticker pack. | |||||
/// </summary> | |||||
public string Name { get; } | |||||
/// <summary> | |||||
/// Gets the id of the pack's SKU. | |||||
/// </summary> | |||||
public ulong SkuId { get; } | |||||
/// <summary> | |||||
/// Gets the id of a sticker in the pack which is shown as the pack's icon. | |||||
/// </summary> | |||||
public ulong? CoverStickerId { get; } | |||||
/// <summary> | |||||
/// Gets the description of the sticker pack. | |||||
/// </summary> | |||||
public string Description { get; } | |||||
/// <summary> | |||||
/// Gets the id of the sticker pack's banner image | |||||
/// </summary> | |||||
public ulong BannerAssetId { get; } | |||||
internal StickerPack(string name, ulong id, ulong skuid, ulong? coverStickerId, string description, ulong bannerAssetId, IEnumerable<TSticker> stickers) | |||||
{ | |||||
this.Name = name; | |||||
this.Id = id; | |||||
this.SkuId = skuid; | |||||
this.CoverStickerId = coverStickerId; | |||||
this.Description = description; | |||||
this.BannerAssetId = bannerAssetId; | |||||
this.Stickers = stickers.ToImmutableArray(); | |||||
} | |||||
} | |||||
} |
@@ -21,6 +21,8 @@ namespace Discord.API | |||||
public string PreviewAsset { get; set; } | public string PreviewAsset { get; set; } | ||||
[JsonProperty("format_type")] | [JsonProperty("format_type")] | ||||
public StickerFormatType FormatType { get; set; } | public StickerFormatType FormatType { get; set; } | ||||
[JsonProperty("guild_id")] | |||||
public Optional<ulong> GuildId { get; set; } | |||||
[JsonProperty("user")] | [JsonProperty("user")] | ||||
public Optional<User> User { get; set; } | public Optional<User> User { get; set; } | ||||
} | } | ||||
@@ -3527,6 +3527,50 @@ | |||||
<member name="M:Discord.Rest.RestGuild.DeleteEmoteAsync(Discord.GuildEmote,Discord.RequestOptions)"> | <member name="M:Discord.Rest.RestGuild.DeleteEmoteAsync(Discord.GuildEmote,Discord.RequestOptions)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="M:Discord.Rest.RestGuild.CreateStickerAsync(System.String,System.String,System.Collections.Generic.IEnumerable{System.String},Discord.Image,Discord.RequestOptions)"> | |||||
<summary> | |||||
Creates a new sticker in this guild. | |||||
</summary> | |||||
<param name="name">The name of the sticker.</param> | |||||
<param name="description">The description of the sticker.</param> | |||||
<param name="tags">The tags of the sticker.</param> | |||||
<param name="image">The image of the new emote.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous creation operation. The task result contains the created sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.Rest.RestGuild.GetStickerAsync(System.UInt64,Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a specific sticker within this guild. | |||||
</summary> | |||||
<param name="id">The id of the sticker to get.</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 sticker found with the | |||||
specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.Rest.RestGuild.GetStickersAsync(Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a collection of all stickers within 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 stickers found within the guild. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.Rest.RestGuild.DeleteStickerAsync(Discord.Rest.CustomSticker,Discord.RequestOptions)"> | |||||
<summary> | |||||
Deletes a sticker within this guild. | |||||
</summary> | |||||
<param name="sticker">The sticker to delete.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous removal operation. | |||||
</returns> | |||||
</member> | |||||
<member name="P:Discord.Rest.RestGuild.Discord#IGuild#Available"> | <member name="P:Discord.Rest.RestGuild.Discord#IGuild#Available"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -3970,6 +4014,33 @@ | |||||
<member name="P:Discord.Rest.RestInviteMetadata.CreatedAt"> | <member name="P:Discord.Rest.RestInviteMetadata.CreatedAt"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="T:Discord.Rest.CustomSticker"> | |||||
<summary> | |||||
Represents a Rest-based custom sticker within a guild. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.Rest.CustomSticker.AuthorId"> | |||||
<summary> | |||||
Gets the users id who uploaded the sticker. | |||||
</summary> | |||||
<remarks> | |||||
In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. | |||||
</remarks> | |||||
</member> | |||||
<member name="P:Discord.Rest.CustomSticker.Guild"> | |||||
<summary> | |||||
Gets the guild that this custom sticker is in. | |||||
</summary> | |||||
<remarks> | |||||
<b>Note</b>: This property can be <see langword="null"/> if the sticker wasnt fetched from a guild. | |||||
</remarks> | |||||
</member> | |||||
<member name="M:Discord.Rest.CustomSticker.DeleteAsync(Discord.RequestOptions)"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.Rest.CustomSticker.ModifyAsync(System.Action{Discord.StickerProperties},Discord.RequestOptions)"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="F:Discord.Rest.MessageHelper.InlineCodeRegex"> | <member name="F:Discord.Rest.MessageHelper.InlineCodeRegex"> | ||||
<summary> | <summary> | ||||
Regex used to check if some text is formatted as inline code. | Regex used to check if some text is formatted as inline code. | ||||
@@ -4268,6 +4339,52 @@ | |||||
<inheritdoc /> | <inheritdoc /> | ||||
<exception cref="T:System.InvalidOperationException">This operation may only be called on a <see cref="T:Discord.INewsChannel"/> channel.</exception> | <exception cref="T:System.InvalidOperationException">This operation may only be called on a <see cref="T:Discord.INewsChannel"/> channel.</exception> | ||||
</member> | </member> | ||||
<member name="T:Discord.Rest.Sticker"> | |||||
<inheritdoc cref="T:Discord.ISticker"/> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.PackId"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.Name"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.Description"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.Tags"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.Asset"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.PreviewAsset"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Rest.Sticker.Format"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="M:Discord.Rest.Sticker.GetStickerUrl"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="T:Discord.Rest.StickerItem"> | |||||
<summary> | |||||
Represents a partial sticker received in a message. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.Rest.StickerItem.Name"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.Rest.StickerItem.Format"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.Rest.StickerItem.ResolveStickerAsync"> | |||||
<summary> | |||||
Resolves this sticker item by fetching the <see cref="T:Discord.Rest.Sticker"/> from the API. | |||||
</summary> | |||||
<returns> | |||||
A task representing the download operation, the result of the task is a sticker object. | |||||
</returns> | |||||
</member> | |||||
<member name="T:Discord.Rest.RestApplication"> | <member name="T:Discord.Rest.RestApplication"> | ||||
<summary> | <summary> | ||||
Represents a REST-based entity that contains information about a Discord application created via the developer portal. | Represents a REST-based entity that contains information about a Discord application created via the developer portal. | ||||
@@ -4870,32 +4987,5 @@ | |||||
A string containing the filename of this attachment. | A string containing the filename of this attachment. | ||||
</returns> | </returns> | ||||
</member> | </member> | ||||
<member name="T:Discord.Sticker"> | |||||
<inheritdoc cref="T:Discord.ISticker"/> | |||||
</member> | |||||
<member name="P:Discord.Sticker.Id"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.PackId"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.Name"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.Description"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.Tags"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.Asset"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.PreviewAsset"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="P:Discord.Sticker.FormatType"> | |||||
<inheritdoc /> | |||||
</member> | |||||
</members> | </members> | ||||
</doc> | </doc> |
@@ -559,7 +559,7 @@ namespace Discord.Rest | |||||
return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false); | return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task<API.Sticker> ModifyStickerAsync(BaseDiscordClient client, IGuild guild, ISticker sticker, Action<StickerProperties> func, | |||||
public static async Task<API.Sticker> ModifyStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, Action<StickerProperties> func, | |||||
RequestOptions options = null) | RequestOptions options = null) | ||||
{ | { | ||||
if (func == null) | if (func == null) | ||||
@@ -577,10 +577,10 @@ namespace Discord.Rest | |||||
Optional<string>.Unspecified | Optional<string>.Unspecified | ||||
}; | }; | ||||
return await client.ApiClient.ModifyStickerAsync(apiArgs, guild.Id, sticker.Id, options).ConfigureAwait(false); | |||||
return await client.ApiClient.ModifyStickerAsync(apiArgs, guildId, sticker.Id, options).ConfigureAwait(false); | |||||
} | } | ||||
public static async Task DeleteStickerAsync(BaseDiscordClient client, IGuild guild, ISticker sticker, RequestOptions options = null) | |||||
=> await client.ApiClient.DeleteStickerAsync(guild.Id, sticker.Id, options).ConfigureAwait(false); | |||||
public static async Task DeleteStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, RequestOptions options = null) | |||||
=> await client.ApiClient.DeleteStickerAsync(guildId, sticker.Id, options).ConfigureAwait(false); | |||||
} | } | ||||
} | } |
@@ -19,6 +19,7 @@ namespace Discord.Rest | |||||
{ | { | ||||
private ImmutableDictionary<ulong, RestRole> _roles; | private ImmutableDictionary<ulong, RestRole> _roles; | ||||
private ImmutableArray<GuildEmote> _emotes; | private ImmutableArray<GuildEmote> _emotes; | ||||
private ImmutableArray<CustomSticker> _stickers; | |||||
private ImmutableArray<string> _features; | private ImmutableArray<string> _features; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -112,6 +113,7 @@ namespace Discord.Rest | |||||
public IReadOnlyCollection<RestRole> Roles => _roles.ToReadOnlyCollection(); | public IReadOnlyCollection<RestRole> Roles => _roles.ToReadOnlyCollection(); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IReadOnlyCollection<GuildEmote> Emotes => _emotes; | public IReadOnlyCollection<GuildEmote> Emotes => _emotes; | ||||
public IReadOnlyCollection<CustomSticker> Stickers => _stickers; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IReadOnlyCollection<string> Features => _features; | public IReadOnlyCollection<string> Features => _features; | ||||
@@ -190,6 +192,23 @@ namespace Discord.Rest | |||||
} | } | ||||
_roles = roles.ToImmutable(); | _roles = roles.ToImmutable(); | ||||
if (model.Stickers != null) | |||||
{ | |||||
var stickers = new ImmutableArray<CustomSticker>(); | |||||
for (int i = 0; i < model.Stickers.Length; i++) | |||||
{ | |||||
var sticker = model.Stickers[i]; | |||||
var entity = CustomSticker.Create(Discord, sticker, this, sticker.User.IsSpecified ? sticker.User.Value.Id : null); | |||||
stickers.Add(entity); | |||||
} | |||||
_stickers = stickers; | |||||
} | |||||
else | |||||
_stickers = new ImmutableArray<CustomSticker>(); | |||||
Available = true; | Available = true; | ||||
} | } | ||||
internal void Update(WidgetModel model) | internal void Update(WidgetModel model) | ||||
@@ -908,6 +927,78 @@ namespace Discord.Rest | |||||
public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) | public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) | ||||
=> GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); | => GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); | ||||
//Stickers | |||||
/// <summary> | |||||
/// Creates a new sticker in this guild. | |||||
/// </summary> | |||||
/// <param name="name">The name of the sticker.</param> | |||||
/// <param name="description">The description of the sticker.</param> | |||||
/// <param name="tags">The tags of the sticker.</param> | |||||
/// <param name="image">The image of the new emote.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous creation operation. The task result contains the created sticker. | |||||
/// </returns> | |||||
public async Task<CustomSticker> CreateStickerAsync(string name, string description, IEnumerable<string> tags, Image image, RequestOptions options = null) | |||||
{ | |||||
var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, image, options).ConfigureAwait(false); | |||||
return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); | |||||
} | |||||
/// <summary> | |||||
/// Gets a specific sticker within this guild. | |||||
/// </summary> | |||||
/// <param name="id">The id of the sticker to get.</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 sticker found with the | |||||
/// specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
/// </returns> | |||||
public async Task<CustomSticker> GetStickerAsync(ulong id, RequestOptions options = null) | |||||
{ | |||||
var model = await Discord.ApiClient.GetGuildStickerAsync(this.Id, id, options).ConfigureAwait(false); | |||||
if (model == null) | |||||
return null; | |||||
return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); | |||||
} | |||||
/// <summary> | |||||
/// Gets a collection of all stickers within 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 stickers found within the guild. | |||||
/// </returns> | |||||
public async Task<IReadOnlyCollection<CustomSticker>> GetStickersAsync(RequestOptions options = null) | |||||
{ | |||||
var models = await Discord.ApiClient.ListGuildStickersAsync(this.Id, options).ConfigureAwait(false); | |||||
if (models.Length == 0) | |||||
return null; | |||||
List<CustomSticker> stickers = new List<CustomSticker>(); | |||||
foreach(var model in models) | |||||
{ | |||||
var entity = CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); | |||||
stickers.Add(entity); | |||||
} | |||||
return stickers.ToImmutableArray(); | |||||
} | |||||
/// <summary> | |||||
/// Deletes a sticker within this guild. | |||||
/// </summary> | |||||
/// <param name="sticker">The sticker to delete.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous removal operation. | |||||
/// </returns> | |||||
public Task DeleteStickerAsync(CustomSticker sticker, RequestOptions options = null) | |||||
=> sticker.DeleteAsync(options); | |||||
//IGuild | //IGuild | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
bool IGuild.Available => Available; | bool IGuild.Available => Available; | ||||
@@ -918,6 +1009,8 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IReadOnlyCollection<IRole> IGuild.Roles => Roles; | IReadOnlyCollection<IRole> IGuild.Roles => Roles; | ||||
IReadOnlyCollection<ICustomSticker> IGuild.Stickers => Stickers; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IReadOnlyCollection<IBan>> IGuild.GetBansAsync(RequestOptions options) | async Task<IReadOnlyCollection<IBan>> IGuild.GetBansAsync(RequestOptions options) | ||||
=> await GetBansAsync(options).ConfigureAwait(false); | => await GetBansAsync(options).ConfigureAwait(false); | ||||
@@ -1169,5 +1262,23 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IReadOnlyCollection<IApplicationCommand>> IGuild.GetApplicationCommandsAsync (RequestOptions options) | async Task<IReadOnlyCollection<IApplicationCommand>> IGuild.GetApplicationCommandsAsync (RequestOptions options) | ||||
=> await GetApplicationCommandsAsync(options).ConfigureAwait(false); | => await GetApplicationCommandsAsync(options).ConfigureAwait(false); | ||||
async Task<ICustomSticker> IGuild.CreateStickerAsync(string name, string description, IEnumerable<string> tags, Image image, RequestOptions options) | |||||
=> await CreateStickerAsync(name, description, tags, image, options); | |||||
async Task<ICustomSticker> IGuild.GetStickerAsync(ulong id, CacheMode mode, RequestOptions options) | |||||
{ | |||||
if (mode != CacheMode.AllowDownload) | |||||
return null; | |||||
return await GetStickerAsync(id, options); | |||||
} | |||||
async Task<IReadOnlyCollection<ICustomSticker>> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options) | |||||
{ | |||||
if (mode != CacheMode.AllowDownload) | |||||
return null; | |||||
return await GetStickersAsync(options); | |||||
} | |||||
Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options) | |||||
=> sticker.DeleteAsync(); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,73 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Model = Discord.API.Sticker; | |||||
namespace Discord.Rest | |||||
{ | |||||
/// <summary> | |||||
/// Represents a Rest-based custom sticker within a guild. | |||||
/// </summary> | |||||
public class CustomSticker : Sticker, ICustomSticker | |||||
{ | |||||
/// <summary> | |||||
/// Gets the users id who uploaded the sticker. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. | |||||
/// </remarks> | |||||
public ulong? AuthorId { get; private set; } | |||||
/// <summary> | |||||
/// Gets the guild that this custom sticker is in. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// <b>Note</b>: This property can be <see langword="null"/> if the sticker wasnt fetched from a guild. | |||||
/// </remarks> | |||||
public RestGuild Guild { get; private set; } | |||||
private ulong GuildId { get; set; } | |||||
internal CustomSticker(BaseDiscordClient client, ulong id, RestGuild guild, ulong? authorId = null) | |||||
: base(client, id) | |||||
{ | |||||
this.AuthorId = authorId; | |||||
this.Guild = guild; | |||||
} | |||||
internal CustomSticker(BaseDiscordClient client, ulong id, ulong guildId, ulong? authorId = null) | |||||
: base(client, id) | |||||
{ | |||||
this.AuthorId = authorId; | |||||
this.GuildId = guildId; | |||||
} | |||||
internal static CustomSticker Create(BaseDiscordClient client, Model model, RestGuild guild, ulong? authorId = null) | |||||
{ | |||||
var entity = new CustomSticker(client, model.Id, guild, authorId); | |||||
entity.Update(model); | |||||
return entity; | |||||
} | |||||
internal static CustomSticker Create(BaseDiscordClient client, Model model, ulong guildId, ulong? authorId = null) | |||||
{ | |||||
var entity = new CustomSticker(client, model.Id, guildId, authorId); | |||||
entity.Update(model); | |||||
return entity; | |||||
} | |||||
/// <inheritdoc/> | |||||
public Task DeleteAsync(RequestOptions options = null) | |||||
=> GuildHelper.DeleteStickerAsync(Discord, GuildId, this, options); | |||||
/// <inheritdoc/> | |||||
public async Task ModifyAsync(Action<StickerProperties> func, RequestOptions options = null) | |||||
{ | |||||
var model = await GuildHelper.ModifyStickerAsync(Discord, GuildId, this, func, options); | |||||
Update(model); | |||||
} | |||||
IGuild ICustomSticker.Guild => Guild; | |||||
} | |||||
} |
@@ -60,7 +60,7 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public virtual IReadOnlyCollection<ITag> Tags => ImmutableArray.Create<ITag>(); | public virtual IReadOnlyCollection<ITag> Tags => ImmutableArray.Create<ITag>(); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public virtual IReadOnlyCollection<Sticker> Stickers => ImmutableArray.Create<Sticker>(); | |||||
public virtual IReadOnlyCollection<StickerItem> Stickers => ImmutableArray.Create<StickerItem>(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); | public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); | ||||
@@ -236,7 +236,7 @@ namespace Discord.Rest | |||||
IReadOnlyCollection<IMessageComponent> IMessage.Components => Components; | IReadOnlyCollection<IMessageComponent> IMessage.Components => Components; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IReadOnlyCollection<ISticker> IMessage.Stickers => Stickers; | |||||
IReadOnlyCollection<IStickerItem> IMessage.Stickers => Stickers; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); | public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); | ||||
@@ -21,7 +21,7 @@ namespace Discord.Rest | |||||
private ImmutableArray<ITag> _tags = ImmutableArray.Create<ITag>(); | private ImmutableArray<ITag> _tags = ImmutableArray.Create<ITag>(); | ||||
private ImmutableArray<ulong> _roleMentionIds = ImmutableArray.Create<ulong>(); | private ImmutableArray<ulong> _roleMentionIds = ImmutableArray.Create<ulong>(); | ||||
private ImmutableArray<RestUser> _userMentions = ImmutableArray.Create<RestUser>(); | private ImmutableArray<RestUser> _userMentions = ImmutableArray.Create<RestUser>(); | ||||
private ImmutableArray<Sticker> _stickers = ImmutableArray.Create<Sticker>(); | |||||
private ImmutableArray<StickerItem> _stickers = ImmutableArray.Create<StickerItem>(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override bool IsTTS => _isTTS; | public override bool IsTTS => _isTTS; | ||||
@@ -46,7 +46,7 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<ITag> Tags => _tags; | public override IReadOnlyCollection<ITag> Tags => _tags; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<Sticker> Stickers => _stickers; | |||||
public override IReadOnlyCollection<StickerItem> Stickers => _stickers; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IUserMessage ReferencedMessage => _referencedMessage; | public IUserMessage ReferencedMessage => _referencedMessage; | ||||
@@ -136,18 +136,18 @@ namespace Discord.Rest | |||||
_referencedMessage = RestUserMessage.Create(Discord, Channel, refMsgAuthor, refMsg); | _referencedMessage = RestUserMessage.Create(Discord, Channel, refMsgAuthor, refMsg); | ||||
} | } | ||||
if (model.Stickers.IsSpecified) | |||||
if (model.StickerItems.IsSpecified) | |||||
{ | { | ||||
var value = model.Stickers.Value; | |||||
var value = model.StickerItems.Value; | |||||
if (value.Length > 0) | if (value.Length > 0) | ||||
{ | { | ||||
var stickers = ImmutableArray.CreateBuilder<Sticker>(value.Length); | |||||
var stickers = ImmutableArray.CreateBuilder<StickerItem>(value.Length); | |||||
for (int i = 0; i < value.Length; i++) | for (int i = 0; i < value.Length; i++) | ||||
stickers.Add(Sticker.Create(value[i])); | |||||
stickers.Add(new StickerItem(Discord, value[i])); | |||||
_stickers = stickers.ToImmutable(); | _stickers = stickers.ToImmutable(); | ||||
} | } | ||||
else | else | ||||
_stickers = ImmutableArray.Create<Sticker>(); | |||||
_stickers = ImmutableArray.Create<StickerItem>(); | |||||
} | } | ||||
} | } | ||||
@@ -3,45 +3,49 @@ using System.Diagnostics; | |||||
using System.Linq; | using System.Linq; | ||||
using Model = Discord.API.Sticker; | using Model = Discord.API.Sticker; | ||||
namespace Discord | |||||
namespace Discord.Rest | |||||
{ | { | ||||
/// <inheritdoc cref="ISticker"/> | /// <inheritdoc cref="ISticker"/> | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class Sticker : ISticker | |||||
public class Sticker : RestEntity<ulong>, ISticker | |||||
{ | { | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong Id { get; } | |||||
public ulong PackId { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong PackId { get; } | |||||
public string Name { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string Name { get; } | |||||
public string Description { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string Description { get; } | |||||
public IReadOnlyCollection<string> Tags { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IReadOnlyCollection<string> Tags { get; } | |||||
public string Asset { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string Asset { get; } | |||||
public string PreviewAsset { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string PreviewAsset { get; } | |||||
/// <inheritdoc /> | |||||
public StickerFormatType FormatType { get; } | |||||
public StickerFormatType Format { get; internal set; } | |||||
/// <inheritdoc/> | |||||
public string GetStickerUrl() | |||||
=> CDN.GetStickerUrl(this.Id, this.Format); | |||||
internal Sticker(ulong id, ulong packId, string name, string description, string[] tags, string asset, string previewAsset, StickerFormatType formatType) | |||||
internal Sticker(BaseDiscordClient client, ulong id) | |||||
: base(client, id) { } | |||||
internal static Sticker Create(BaseDiscordClient client, Model model) | |||||
{ | { | ||||
Id = id; | |||||
PackId = packId; | |||||
Name = name; | |||||
Description = description; | |||||
Tags = tags.ToReadOnlyCollection(); | |||||
Asset = asset; | |||||
PreviewAsset = previewAsset; | |||||
FormatType = formatType; | |||||
var entity = new Sticker(client, model.Id); | |||||
entity.Update(model); | |||||
return entity; | |||||
} | } | ||||
internal static Sticker Create(Model model) | |||||
internal void Update(Model model) | |||||
{ | { | ||||
return new Sticker(model.Id, model.PackId, model.Name, model.Desription, | |||||
model.Tags.IsSpecified ? model.Tags.Value.Split(',').Select(x => x.Trim()).ToArray() : new string[0], | |||||
model.Asset, model.PreviewAsset, model.FormatType); | |||||
PackId = model.PackId; | |||||
Name = model.Name; | |||||
Description = model.Desription; | |||||
Tags = model.Tags.IsSpecified ? model.Tags.Value.Split(',').Select(x => x.Trim()).ToArray() : new string[0]; | |||||
Asset = model.Asset; | |||||
PreviewAsset = model.PreviewAsset; | |||||
Format = model.FormatType; | |||||
} | } | ||||
private string DebuggerDisplay => $"{Name} ({Id})"; | private string DebuggerDisplay => $"{Name} ({Id})"; | ||||
@@ -10,17 +10,13 @@ namespace Discord.Rest | |||||
/// <summary> | /// <summary> | ||||
/// Represents a partial sticker received in a message. | /// Represents a partial sticker received in a message. | ||||
/// </summary> | /// </summary> | ||||
public class StickerItem : RestEntity<ulong> | |||||
public class StickerItem : RestEntity<ulong>, IStickerItem | |||||
{ | { | ||||
/// <summary> | |||||
/// The name of this sticker. | |||||
/// </summary> | |||||
public readonly string Name; | |||||
/// <inheritdoc/> | |||||
public string Name { get; } | |||||
/// <summary> | |||||
/// The format of this sticker. | |||||
/// </summary> | |||||
public readonly StickerFormatType Format; | |||||
/// <inheritdoc/> | |||||
public StickerFormatType Format { get; } | |||||
internal StickerItem(BaseDiscordClient client, Model model) | internal StickerItem(BaseDiscordClient client, Model model) | ||||
: base(client, model.Id) | : base(client, model.Id) | ||||
@@ -40,7 +36,10 @@ namespace Discord.Rest | |||||
{ | { | ||||
var model = await Discord.ApiClient.GetStickerAsync(this.Id); | var model = await Discord.ApiClient.GetStickerAsync(this.Id); | ||||
return Sticker.Create(model); | |||||
if (model.GuildId.IsSpecified) | |||||
return CustomSticker.Create(Discord, model, model.GuildId.Value, model.User.IsSpecified ? model.User.Value.Id : null); | |||||
else | |||||
return Sticker.Create(Discord, model); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -44,6 +44,10 @@ namespace Discord.WebSocket | |||||
internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | ||||
/// <summary> | |||||
/// Gets a collection of default stickers. | |||||
/// </summary> | |||||
public abstract IReadOnlyCollection<StickerPack<SocketSticker>> DefaultStickerPacks { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the current logged-in user. | /// Gets the current logged-in user. | ||||
/// </summary> | /// </summary> | ||||
@@ -268,6 +272,16 @@ namespace Discord.WebSocket | |||||
/// </returns> | /// </returns> | ||||
public Task<RestInviteMetadata> GetInviteAsync(string inviteId, RequestOptions options = null) | public Task<RestInviteMetadata> GetInviteAsync(string inviteId, RequestOptions options = null) | ||||
=> ClientHelper.GetInviteAsync(this, inviteId, options ?? RequestOptions.Default); | => ClientHelper.GetInviteAsync(this, inviteId, options ?? RequestOptions.Default); | ||||
/// <summary> | |||||
/// Gets a sticker. | |||||
/// </summary> | |||||
/// <param name="mode">Whether or not to allow downloading from the api.</param> | |||||
/// <param name="id">The id of the sticker to get.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A <see cref="SocketSticker"/> if found, otherwise <see langword="null"/>. | |||||
/// </returns> | |||||
public abstract Task<SocketSticker> GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
// IDiscordClient | // IDiscordClient | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -20,7 +20,7 @@ | |||||
<FileVersion>3.0.1</FileVersion> | <FileVersion>3.0.1</FileVersion> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | ||||
<DefineConstants>TRACE;</DefineConstants> | |||||
<DefineConstants>TRACE;DEBUG;DEBUG_PACKETS</DefineConstants> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -118,6 +118,11 @@ | |||||
Provides access to a REST-only client with a shared state from this client. | Provides access to a REST-only client with a shared state from this client. | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="P:Discord.WebSocket.BaseSocketClient.DefaultStickerPacks"> | |||||
<summary> | |||||
Gets a collection of default stickers. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.BaseSocketClient.CurrentUser"> | <member name="P:Discord.WebSocket.BaseSocketClient.CurrentUser"> | ||||
<summary> | <summary> | ||||
Gets the current logged-in user. | Gets the current logged-in user. | ||||
@@ -349,6 +354,17 @@ | |||||
A task that represents the asynchronous get operation. The task result contains the invite information. | A task that represents the asynchronous get operation. The task result contains the invite information. | ||||
</returns> | </returns> | ||||
</member> | </member> | ||||
<member name="M:Discord.WebSocket.BaseSocketClient.GetStickerAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a sticker. | |||||
</summary> | |||||
<param name="mode">Whether or not to allow downloading from the api.</param> | |||||
<param name="id">The id of the sticker to get.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A <see cref="T:Discord.WebSocket.SocketSticker"/> if found, otherwise <see langword="null"/>. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.BaseSocketClient.Discord#IDiscordClient#GetApplicationInfoAsync(Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.BaseSocketClient.Discord#IDiscordClient#GetApplicationInfoAsync(Discord.RequestOptions)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -820,6 +836,9 @@ | |||||
<member name="P:Discord.WebSocket.DiscordShardedClient.Activity"> | <member name="P:Discord.WebSocket.DiscordShardedClient.Activity"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="P:Discord.WebSocket.DiscordShardedClient.DefaultStickerPacks"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.DiscordShardedClient.Guilds"> | <member name="P:Discord.WebSocket.DiscordShardedClient.Guilds"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -858,6 +877,9 @@ | |||||
<member name="M:Discord.WebSocket.DiscordShardedClient.GetChannel(System.UInt64)"> | <member name="M:Discord.WebSocket.DiscordShardedClient.GetChannel(System.UInt64)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="M:Discord.WebSocket.DiscordShardedClient.GetStickerAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.DiscordShardedClient.GetUser(System.UInt64)"> | <member name="M:Discord.WebSocket.DiscordShardedClient.GetUser(System.UInt64)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -959,6 +981,9 @@ | |||||
<member name="P:Discord.WebSocket.DiscordSocketClient.Guilds"> | <member name="P:Discord.WebSocket.DiscordSocketClient.Guilds"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="P:Discord.WebSocket.DiscordSocketClient.DefaultStickerPacks"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.DiscordSocketClient.PrivateChannels"> | <member name="P:Discord.WebSocket.DiscordSocketClient.PrivateChannels"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -1083,6 +1108,16 @@ | |||||
Clears cached users from the client. | Clears cached users from the client. | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="M:Discord.WebSocket.DiscordSocketClient.GetStickerAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.DiscordSocketClient.GetSticker(System.UInt64)"> | |||||
<summary> | |||||
Gets a sticker. | |||||
</summary> | |||||
<param name="id">The unique identifier of the sticker.</param> | |||||
<returns>A sticker if found, otherwise <see langword="null"/>.</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.DiscordSocketClient.GetVoiceRegionsAsync(Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.DiscordSocketClient.GetVoiceRegionsAsync(Discord.RequestOptions)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -3030,6 +3065,11 @@ | |||||
<member name="P:Discord.WebSocket.SocketGuild.Emotes"> | <member name="P:Discord.WebSocket.SocketGuild.Emotes"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="P:Discord.WebSocket.SocketGuild.Stickers"> | |||||
<summary> | |||||
Gets a collection of all custom stickers for this guild. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketGuild.Features"> | <member name="P:Discord.WebSocket.SocketGuild.Features"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -3438,6 +3478,59 @@ | |||||
<member name="M:Discord.WebSocket.SocketGuild.DeleteEmoteAsync(Discord.GuildEmote,Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.DeleteEmoteAsync(Discord.GuildEmote,Discord.RequestOptions)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="M:Discord.WebSocket.SocketGuild.GetStickerAsync(System.UInt64,Discord.CacheMode,Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a specific sticker within this guild. | |||||
</summary> | |||||
<param name="id">The id of the sticker to get.</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 sticker found with the | |||||
specified <paramref name="id"/>; <see langword="null" /> if none is found. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketGuild.GetSticker(System.UInt64)"> | |||||
<summary> | |||||
Gets a specific sticker within this guild. | |||||
</summary> | |||||
<param name="id">The id of the sticker to get.</param> | |||||
<returns>A sticker, if none is found then <see langword="null"/>.</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketGuild.GetStickersAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
<summary> | |||||
Gets a collection of all stickers within 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 stickers found within the guild. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketGuild.CreateStickerAsync(System.String,System.String,System.Collections.Generic.IEnumerable{System.String},Discord.Image,Discord.RequestOptions)"> | |||||
<summary> | |||||
Creates a new sticker in this guild. | |||||
</summary> | |||||
<param name="name">The name of the sticker.</param> | |||||
<param name="description">The description of the sticker.</param> | |||||
<param name="tags">The tags of the sticker.</param> | |||||
<param name="image">The image of the new emote.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous creation operation. The task result contains the created sticker. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketGuild.DeleteStickerAsync(Discord.WebSocket.SocketCustomSticker,Discord.RequestOptions)"> | |||||
<summary> | |||||
Deletes a sticker within this guild. | |||||
</summary> | |||||
<param name="sticker">The sticker to delete.</param> | |||||
<param name="options">The options to be used when sending the request.</param> | |||||
<returns> | |||||
A task that represents the asynchronous removal operation. | |||||
</returns> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketGuild.ToString"> | <member name="M:Discord.WebSocket.SocketGuild.ToString"> | ||||
<summary> | <summary> | ||||
Gets the name of the guild. | Gets the name of the guild. | ||||
@@ -3479,6 +3572,9 @@ | |||||
<member name="P:Discord.WebSocket.SocketGuild.Discord#IGuild#ApproximatePresenceCount"> | <member name="P:Discord.WebSocket.SocketGuild.Discord#IGuild#ApproximatePresenceCount"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="P:Discord.WebSocket.SocketGuild.Discord#IGuild#Stickers"> | |||||
<inheritdoc /> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetBansAsync(Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketGuild.Discord#IGuild#GetBansAsync(Discord.RequestOptions)"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
@@ -4417,6 +4513,83 @@ | |||||
<member name="P:Discord.WebSocket.SocketEntity`1.Id"> | <member name="P:Discord.WebSocket.SocketEntity`1.Id"> | ||||
<inheritdoc /> | <inheritdoc /> | ||||
</member> | </member> | ||||
<member name="P:Discord.WebSocket.SocketCustomSticker.Author"> | |||||
<summary> | |||||
Gets the user that uploaded the guild sticker. | |||||
</summary> | |||||
<remarks> | |||||
<note> | |||||
This may return <see langword="null"/> in the WebSocket implementation due to incomplete user collection in | |||||
large guilds, or the bot doesnt have the MANAGE_EMOJIS_AND_STICKERS permission. | |||||
</note> | |||||
</remarks> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketCustomSticker.Guild"> | |||||
<summary> | |||||
Gets the guild the sticker lives in. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketCustomSticker.AuthorId"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketCustomSticker.ModifyAsync(System.Action{Discord.StickerProperties},Discord.RequestOptions)"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketCustomSticker.DeleteAsync(Discord.RequestOptions)"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.PackId"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.Name"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.Description"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.Tags"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.Asset"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.PreviewAsset"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketSticker.Format"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketSticker.GetStickerUrl"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="T:Discord.WebSocket.SocketUnknownSticker"> | |||||
<summary> | |||||
Represents an unknown sticker received over the gateway. | |||||
</summary> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketUnknownSticker.Asset"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketUnknownSticker.Tags"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketUnknownSticker.Description"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketUnknownSticker.PackId"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="P:Discord.WebSocket.SocketUnknownSticker.PreviewAsset"> | |||||
<inheritdoc/> | |||||
</member> | |||||
<member name="M:Discord.WebSocket.SocketUnknownSticker.ResolveAsync(Discord.CacheMode,Discord.RequestOptions)"> | |||||
<summary> | |||||
Attempts to try to find the sticker. | |||||
</summary> | |||||
<returns> | |||||
The sticker representing this unknown stickers Id, if none is found then <see langword="null"/>. | |||||
</returns> | |||||
</member> | |||||
<member name="T:Discord.WebSocket.SocketGroupUser"> | <member name="T:Discord.WebSocket.SocketGroupUser"> | ||||
<summary> | <summary> | ||||
Represents a WebSocket-based group user. | Represents a WebSocket-based group user. | ||||
@@ -6,6 +6,7 @@ using System.IO; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using System.Threading; | using System.Threading; | ||||
using System.Collections.Immutable; | |||||
namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
{ | { | ||||
@@ -16,6 +17,7 @@ namespace Discord.WebSocket | |||||
private readonly bool _automaticShards; | private readonly bool _automaticShards; | ||||
private int[] _shardIds; | private int[] _shardIds; | ||||
private DiscordSocketClient[] _shards; | private DiscordSocketClient[] _shards; | ||||
private ImmutableArray<StickerPack<SocketSticker>> _defaultStickers; | |||||
private int _totalShards; | private int _totalShards; | ||||
private SemaphoreSlim[] _identifySemaphores; | private SemaphoreSlim[] _identifySemaphores; | ||||
private object _semaphoreResetLock; | private object _semaphoreResetLock; | ||||
@@ -40,6 +42,10 @@ namespace Discord.WebSocket | |||||
return base.ApiClient; | return base.ApiClient; | ||||
} | } | ||||
} | } | ||||
/// <inheritdoc/> | |||||
public override IReadOnlyCollection<StickerPack<SocketSticker>> DefaultStickerPacks | |||||
=> _defaultStickers.ToReadOnlyCollection(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<SocketGuild> Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); | public override IReadOnlyCollection<SocketGuild> Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -77,6 +83,7 @@ namespace Discord.WebSocket | |||||
_shardIdsToIndex = new Dictionary<int, int>(); | _shardIdsToIndex = new Dictionary<int, int>(); | ||||
config.DisplayInitialLog = false; | config.DisplayInitialLog = false; | ||||
_baseConfig = config; | _baseConfig = config; | ||||
_defaultStickers = new ImmutableArray<StickerPack<SocketSticker>>(); | |||||
if (config.TotalShards == null) | if (config.TotalShards == null) | ||||
_automaticShards = true; | _automaticShards = true; | ||||
@@ -155,6 +162,10 @@ namespace Discord.WebSocket | |||||
//Assume thread safe: already in a connection lock | //Assume thread safe: already in a connection lock | ||||
for (int i = 0; i < _shards.Length; i++) | for (int i = 0; i < _shards.Length; i++) | ||||
await _shards[i].LoginAsync(tokenType, token); | await _shards[i].LoginAsync(tokenType, token); | ||||
if(this._defaultStickers.Length == 0) | |||||
await DownloadDefaultStickersAsync().ConfigureAwait(false); | |||||
} | } | ||||
internal override async Task OnLogoutAsync() | internal override async Task OnLogoutAsync() | ||||
{ | { | ||||
@@ -247,6 +258,63 @@ namespace Discord.WebSocket | |||||
result += _shards[i].Guilds.Count; | result += _shards[i].Guilds.Count; | ||||
return result; | return result; | ||||
} | } | ||||
/// <inheritdoc/> | |||||
public override async Task<SocketSticker> GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
var sticker = _defaultStickers.FirstOrDefault(x => x.Stickers.Any(y => y.Id == id))?.Stickers.FirstOrDefault(x => x.Id == id); | |||||
if (sticker != null) | |||||
return sticker; | |||||
foreach (var guild in Guilds) | |||||
{ | |||||
sticker = await guild.GetStickerAsync(id, CacheMode.CacheOnly).ConfigureAwait(false); | |||||
if (sticker != null) | |||||
return sticker; | |||||
} | |||||
if (mode == CacheMode.CacheOnly) | |||||
return null; | |||||
var model = await ApiClient.GetStickerAsync(id, options).ConfigureAwait(false); | |||||
if (model == null) | |||||
return null; | |||||
if (model.GuildId.IsSpecified) | |||||
{ | |||||
var guild = GetGuild(model.GuildId.Value); | |||||
sticker = guild.AddOrUpdateSticker(model); | |||||
return sticker; | |||||
} | |||||
else | |||||
{ | |||||
return SocketSticker.Create(_shards[0], model); | |||||
} | |||||
} | |||||
private async Task DownloadDefaultStickersAsync() | |||||
{ | |||||
var models = await ApiClient.ListNitroStickerPacksAsync().ConfigureAwait(false); | |||||
foreach(var model in models.StickerPacks) | |||||
{ | |||||
var stickers = model.Stickers.Select(x => SocketSticker.Create(_shards[0], x)); | |||||
var pack = new StickerPack<SocketSticker>( | |||||
model.Name, | |||||
model.Id, | |||||
model.SkuId, | |||||
model.CoverStickerId.ToNullable(), | |||||
model.Description, | |||||
model.BannerAssetId, | |||||
stickers | |||||
); | |||||
_defaultStickers.Add(pack); | |||||
} | |||||
} | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override SocketUser GetUser(ulong id) | public override SocketUser GetUser(ulong id) | ||||
@@ -44,6 +44,7 @@ namespace Discord.WebSocket | |||||
private RestApplication _applicationInfo; | private RestApplication _applicationInfo; | ||||
private bool _isDisposed; | private bool _isDisposed; | ||||
private GatewayIntents _gatewayIntents; | private GatewayIntents _gatewayIntents; | ||||
private ImmutableArray<StickerPack<SocketSticker>> _defaultStickers; | |||||
/// <summary> | /// <summary> | ||||
/// Provides access to a REST-only client with a shared state from this client. | /// Provides access to a REST-only client with a shared state from this client. | ||||
@@ -76,6 +77,17 @@ namespace Discord.WebSocket | |||||
internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<SocketGuild> Guilds => State.Guilds; | public override IReadOnlyCollection<SocketGuild> Guilds => State.Guilds; | ||||
/// <inheritdoc/> | |||||
public override IReadOnlyCollection<StickerPack<SocketSticker>> DefaultStickerPacks | |||||
{ | |||||
get | |||||
{ | |||||
if (this._shardedClient != null) | |||||
return this._shardedClient.DefaultStickerPacks; | |||||
else | |||||
return _defaultStickers.ToReadOnlyCollection(); | |||||
} | |||||
} | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels => State.PrivateChannels; | public override IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels => State.PrivateChannels; | ||||
/// <summary> | /// <summary> | ||||
@@ -137,6 +149,7 @@ namespace Discord.WebSocket | |||||
Rest = new DiscordSocketRestClient(config, ApiClient); | Rest = new DiscordSocketRestClient(config, ApiClient); | ||||
_heartbeatTimes = new ConcurrentQueue<long>(); | _heartbeatTimes = new ConcurrentQueue<long>(); | ||||
_gatewayIntents = config.GatewayIntents; | _gatewayIntents = config.GatewayIntents; | ||||
_defaultStickers = new ImmutableArray<StickerPack<SocketSticker>>(); | |||||
_stateLock = new SemaphoreSlim(1, 1); | _stateLock = new SemaphoreSlim(1, 1); | ||||
_gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); | _gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); | ||||
@@ -195,6 +208,31 @@ namespace Discord.WebSocket | |||||
base.Dispose(disposing); | base.Dispose(disposing); | ||||
} | } | ||||
internal override async Task OnLoginAsync(TokenType tokenType, string token) | |||||
{ | |||||
if(this._shardedClient != null && this._defaultStickers.Length == 0) | |||||
{ | |||||
var models = await ApiClient.ListNitroStickerPacksAsync().ConfigureAwait(false); | |||||
foreach (var model in models.StickerPacks) | |||||
{ | |||||
var stickers = model.Stickers.Select(x => SocketSticker.Create(this, x)); | |||||
var pack = new StickerPack<SocketSticker>( | |||||
model.Name, | |||||
model.Id, | |||||
model.SkuId, | |||||
model.CoverStickerId.ToNullable(), | |||||
model.Description, | |||||
model.BannerAssetId, | |||||
stickers | |||||
); | |||||
_defaultStickers.Add(pack); | |||||
} | |||||
} | |||||
} | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
internal override async Task OnLogoutAsync() | internal override async Task OnLogoutAsync() | ||||
{ | { | ||||
@@ -368,6 +406,51 @@ namespace Discord.WebSocket | |||||
internal void RemoveUser(ulong id) | internal void RemoveUser(ulong id) | ||||
=> State.RemoveUser(id); | => State.RemoveUser(id); | ||||
/// <inheritdoc/> | |||||
public override async Task<SocketSticker> GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
var sticker = _defaultStickers.FirstOrDefault(x => x.Stickers.Any(y => y.Id == id))?.Stickers.FirstOrDefault(x => x.Id == id); | |||||
if (sticker != null) | |||||
return sticker; | |||||
foreach(var guild in Guilds) | |||||
{ | |||||
sticker = await guild.GetStickerAsync(id, CacheMode.CacheOnly).ConfigureAwait(false); | |||||
if (sticker != null) | |||||
return sticker; | |||||
} | |||||
if (mode == CacheMode.CacheOnly) | |||||
return null; | |||||
var model = await ApiClient.GetStickerAsync(id, options).ConfigureAwait(false); | |||||
if(model == null) | |||||
return null; | |||||
if (model.GuildId.IsSpecified) | |||||
{ | |||||
var guild = State.GetGuild(model.GuildId.Value); | |||||
sticker = guild.AddOrUpdateSticker(model); | |||||
return sticker; | |||||
} | |||||
else | |||||
{ | |||||
return SocketSticker.Create(this, model); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Gets a sticker. | |||||
/// </summary> | |||||
/// <param name="id">The unique identifier of the sticker.</param> | |||||
/// <returns>A sticker if found, otherwise <see langword="null"/>.</returns> | |||||
public SocketSticker GetSticker(ulong id) | |||||
=> GetStickerAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override async ValueTask<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) | public override async ValueTask<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) | ||||
{ | { | ||||
@@ -533,6 +533,8 @@ namespace Discord.WebSocket | |||||
stickers.TryAdd(sticker.Id, entity); | stickers.TryAdd(sticker.Id, entity); | ||||
} | } | ||||
_stickers = stickers; | |||||
} | } | ||||
else | else | ||||
_stickers = new ConcurrentDictionary<ulong, SocketCustomSticker>(ConcurrentHashSet.DefaultConcurrencyLevel, 7); | _stickers = new ConcurrentDictionary<ulong, SocketCustomSticker>(ConcurrentHashSet.DefaultConcurrencyLevel, 7); | ||||
@@ -1192,6 +1194,13 @@ namespace Discord.WebSocket | |||||
return AddOrUpdateSticker(model); | return AddOrUpdateSticker(model); | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Gets a specific sticker within this guild. | |||||
/// </summary> | |||||
/// <param name="id">The id of the sticker to get.</param> | |||||
/// <returns>A sticker, if none is found then <see langword="null"/>.</returns> | |||||
public SocketCustomSticker GetSticker(ulong id) | |||||
=> GetStickerAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult(); | |||||
/// <summary> | |||||
/// Gets a collection of all stickers within this guild. | /// Gets a collection of all stickers within 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> | ||||
@@ -1629,7 +1638,8 @@ namespace Discord.WebSocket | |||||
=> await GetStickerAsync(id, mode, options); | => await GetStickerAsync(id, mode, options); | ||||
async Task<IReadOnlyCollection<ICustomSticker>> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options) | async Task<IReadOnlyCollection<ICustomSticker>> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options) | ||||
=> await GetStickersAsync(mode, options); | => await GetStickersAsync(mode, options); | ||||
Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options) => throw new NotImplementedException(); | |||||
Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options) | |||||
=> DeleteStickerAsync(_stickers[sticker.Id], options); | |||||
void IDisposable.Dispose() | void IDisposable.Dispose() | ||||
{ | { | ||||
@@ -106,7 +106,7 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public virtual IReadOnlyCollection<ITag> Tags => ImmutableArray.Create<ITag>(); | public virtual IReadOnlyCollection<ITag> Tags => ImmutableArray.Create<ITag>(); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public virtual IReadOnlyCollection<Sticker> Stickers => ImmutableArray.Create<Sticker>(); | |||||
public virtual IReadOnlyCollection<SocketSticker> Stickers => ImmutableArray.Create<SocketSticker>(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.GroupBy(r => r.Emote).ToDictionary(x => x.Key, x => new ReactionMetadata { ReactionCount = x.Count(), IsMe = x.Any(y => y.UserId == Discord.CurrentUser.Id) }); | public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.GroupBy(r => r.Emote).ToDictionary(x => x.Key, x => new ReactionMetadata { ReactionCount = x.Count(), IsMe = x.Any(y => y.UserId == Discord.CurrentUser.Id) }); | ||||
@@ -261,7 +261,7 @@ namespace Discord.WebSocket | |||||
IReadOnlyCollection<IMessageComponent> IMessage.Components => Components; | IReadOnlyCollection<IMessageComponent> IMessage.Components => Components; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IReadOnlyCollection<ISticker> IMessage.Stickers => Stickers; | |||||
IReadOnlyCollection<IStickerItem> IMessage.Stickers => Stickers; | |||||
internal void AddReaction(SocketReaction reaction) | internal void AddReaction(SocketReaction reaction) | ||||
{ | { | ||||
@@ -23,7 +23,7 @@ namespace Discord.WebSocket | |||||
private ImmutableArray<ITag> _tags = ImmutableArray.Create<ITag>(); | private ImmutableArray<ITag> _tags = ImmutableArray.Create<ITag>(); | ||||
private ImmutableArray<SocketRole> _roleMentions = ImmutableArray.Create<SocketRole>(); | private ImmutableArray<SocketRole> _roleMentions = ImmutableArray.Create<SocketRole>(); | ||||
private ImmutableArray<SocketUser> _userMentions = ImmutableArray.Create<SocketUser>(); | private ImmutableArray<SocketUser> _userMentions = ImmutableArray.Create<SocketUser>(); | ||||
private ImmutableArray<Sticker> _stickers = ImmutableArray.Create<Sticker>(); | |||||
private ImmutableArray<SocketSticker> _stickers = ImmutableArray.Create<SocketSticker>(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override bool IsTTS => _isTTS; | public override bool IsTTS => _isTTS; | ||||
@@ -48,7 +48,7 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<SocketUser> MentionedUsers => _userMentions; | public override IReadOnlyCollection<SocketUser> MentionedUsers => _userMentions; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<Sticker> Stickers => _stickers; | |||||
public override IReadOnlyCollection<SocketSticker> Stickers => _stickers; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IUserMessage ReferencedMessage => _referencedMessage; | public IUserMessage ReferencedMessage => _referencedMessage; | ||||
@@ -162,18 +162,35 @@ namespace Discord.WebSocket | |||||
_referencedMessage = SocketUserMessage.Create(Discord, state, refMsgAuthor, Channel, refMsg); | _referencedMessage = SocketUserMessage.Create(Discord, state, refMsgAuthor, Channel, refMsg); | ||||
} | } | ||||
if (model.Stickers.IsSpecified) | |||||
if (model.StickerItems.IsSpecified) | |||||
{ | { | ||||
var value = model.Stickers.Value; | |||||
var value = model.StickerItems.Value; | |||||
if (value.Length > 0) | if (value.Length > 0) | ||||
{ | { | ||||
var stickers = ImmutableArray.CreateBuilder<Sticker>(value.Length); | |||||
var stickers = ImmutableArray.CreateBuilder<SocketSticker>(value.Length); | |||||
for (int i = 0; i < value.Length; i++) | for (int i = 0; i < value.Length; i++) | ||||
stickers.Add(Sticker.Create(value[i])); | |||||
{ | |||||
var stickerItem = value[i]; | |||||
SocketSticker sticker = null; | |||||
if (guild != null) | |||||
{ | |||||
sticker = guild.GetSticker(stickerItem.Id); | |||||
} | |||||
if(sticker == null) | |||||
{ | |||||
sticker = Discord.GetSticker(stickerItem.Id); | |||||
} | |||||
// if its still null, create an unknown | |||||
sticker = SocketUnknownSticker.Create(Discord, stickerItem); | |||||
} | |||||
_stickers = stickers.ToImmutable(); | _stickers = stickers.ToImmutable(); | ||||
} | } | ||||
else | else | ||||
_stickers = ImmutableArray.Create<Sticker>(); | |||||
_stickers = ImmutableArray.Create<SocketSticker>(); | |||||
} | } | ||||
} | } | ||||
@@ -51,7 +51,7 @@ namespace Discord.WebSocket | |||||
if(!Guild.CurrentUser.GuildPermissions.Has(GuildPermission.ManageEmojisAndStickers)) | if(!Guild.CurrentUser.GuildPermissions.Has(GuildPermission.ManageEmojisAndStickers)) | ||||
throw new InvalidOperationException($"Missing permission {nameof(GuildPermission.ManageEmojisAndStickers)}"); | throw new InvalidOperationException($"Missing permission {nameof(GuildPermission.ManageEmojisAndStickers)}"); | ||||
var model = await GuildHelper.ModifyStickerAsync(this.Discord, this.Guild, this, func, options); | |||||
var model = await GuildHelper.ModifyStickerAsync(this.Discord, this.Guild.Id, this, func, options); | |||||
this.Update(model); | this.Update(model); | ||||
} | } | ||||
@@ -59,7 +59,7 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public async Task DeleteAsync(RequestOptions options = null) | public async Task DeleteAsync(RequestOptions options = null) | ||||
{ | { | ||||
await GuildHelper.DeleteStickerAsync(Discord, Guild, this, options); | |||||
await GuildHelper.DeleteStickerAsync(Discord, this.Guild.Id, this, options); | |||||
Guild.RemoveSticker(this.Id); | Guild.RemoveSticker(this.Id); | ||||
} | } | ||||
@@ -12,36 +12,42 @@ namespace Discord.WebSocket | |||||
public class SocketSticker : SocketEntity<ulong>, ISticker | public class SocketSticker : SocketEntity<ulong>, ISticker | ||||
{ | { | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public ulong PackId { get; private set; } | |||||
public virtual ulong PackId { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Name { get; private set; } | |||||
public string Name { get; internal set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Description { get; private set; } | |||||
public virtual string Description { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public IReadOnlyCollection<string> Tags { get; private set; } | |||||
public virtual IReadOnlyCollection<string> Tags { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Asset { get; private set; } | |||||
public virtual string Asset { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string PreviewAsset { get; private set; } | |||||
public virtual string PreviewAsset { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public StickerFormatType FormatType { get; private set; } | |||||
public StickerFormatType Format { get; internal set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string GetStickerUrl() | public string GetStickerUrl() | ||||
=> CDN.GetStickerUrl(this.Id, this.FormatType); | |||||
=> CDN.GetStickerUrl(this.Id, this.Format); | |||||
internal SocketSticker(DiscordSocketClient client, ulong id) | internal SocketSticker(DiscordSocketClient client, ulong id) | ||||
: base(client, id) { } | : base(client, id) { } | ||||
internal static SocketSticker Create(DiscordSocketClient client, Model model) | internal static SocketSticker Create(DiscordSocketClient client, Model model) | ||||
{ | { | ||||
var entity = new SocketSticker(client, model.Id); | |||||
SocketSticker entity; | |||||
if (model.GuildId.IsSpecified) | |||||
entity = new SocketCustomSticker(client, model.Id, client.GetGuild(model.GuildId.Value), model.User.IsSpecified ? model.User.Value.Id : null); | |||||
else | |||||
entity = new SocketSticker(client, model.Id); | |||||
entity.Update(model); | entity.Update(model); | ||||
return entity; | return entity; | ||||
} | } | ||||
@@ -53,7 +59,7 @@ namespace Discord.WebSocket | |||||
this.PackId = model.PackId; | this.PackId = model.PackId; | ||||
this.Asset = model.Asset; | this.Asset = model.Asset; | ||||
this.PreviewAsset = model.PreviewAsset; | this.PreviewAsset = model.PreviewAsset; | ||||
this.FormatType = model.FormatType; | |||||
this.Format = model.FormatType; | |||||
if (model.Tags.IsSpecified) | if (model.Tags.IsSpecified) | ||||
{ | { |
@@ -0,0 +1,60 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Model = Discord.API.StickerItem; | |||||
namespace Discord.WebSocket | |||||
{ | |||||
/// <summary> | |||||
/// Represents an unknown sticker received over the gateway. | |||||
/// </summary> | |||||
public class SocketUnknownSticker : SocketSticker | |||||
{ | |||||
/// <inheritdoc/> | |||||
public override string Asset | |||||
=> null; | |||||
/// <inheritdoc/> | |||||
public override IReadOnlyCollection<string> Tags | |||||
=> null; | |||||
/// <inheritdoc/> | |||||
public override string Description | |||||
=> null; | |||||
/// <inheritdoc/> | |||||
public override ulong PackId | |||||
=> 0; | |||||
/// <inheritdoc/> | |||||
public override string PreviewAsset | |||||
=> null; | |||||
internal SocketUnknownSticker(DiscordSocketClient client, ulong id) | |||||
: base(client, id) { } | |||||
internal static SocketUnknownSticker Create(DiscordSocketClient client, Model model) | |||||
{ | |||||
var entity = new SocketUnknownSticker(client, model.Id); | |||||
entity.Update(model); | |||||
return entity; | |||||
} | |||||
internal void Update(Model model) | |||||
{ | |||||
this.Name = model.Name; | |||||
this.Format = model.FormatType; | |||||
} | |||||
/// <summary> | |||||
/// Attempts to try to find the sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// The sticker representing this unknown stickers Id, if none is found then <see langword="null"/>. | |||||
/// </returns> | |||||
public Task<SocketSticker> ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
=> Discord.GetStickerAsync(this.Id, mode, options); | |||||
} | |||||
} |