diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 94b0c5cf6..989f35ec1 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -212,6 +212,16 @@ A URL pointing to the Spotify track. + + + Gets a stickers url based off the id and format. + + The id of the sticker. + The format of the sticker + + A URL to the sticker. + + 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. + + + Gets a collection of all custom stickers for this guild. + + + A read-only collection of all custom stickers for 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. + + + Creates a new sticker in this guild. + + The name of the sticker. + The description of the sticker. + The tags of the sticker. + The image of the new emote. + The options to be used when sending the request. + + A task that represents the asynchronous creation operation. The task result contains the created sticker. + + + + + Gets a specific sticker within this guild. + + The id of the sticker to get. + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains the sticker found with the + specified ; if none is found. + + + + + Gets a collection of all stickers within this guild. + + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection + of stickers found within the guild. + + + + + Deletes a sticker within this guild. + + The sticker to delete. + The options to be used when sending the request. + + A task that represents the asynchronous removal operation. + + Gets this guilds slash commands commands @@ -7282,7 +7346,14 @@ The 's attached to this message - + + + Gets all stickers items included in this message. + + + A read-only collection of sticker item objects. + + Gets the flags related to this message. @@ -7411,75 +7482,6 @@ The used in the reaction. - - - Represents a discord sticker. - - - - - Gets the ID of this sticker. - - - A snowflake ID associated with this sticker. - - - - - Gets the ID of the pack of this sticker. - - - A snowflake ID associated with the pack of this sticker. - - - - - Gets the name of this sticker. - - - A with the name of this sticker. - - - - - Gets the description of this sticker. - - - A with the description of this sticker. - - - - - Gets the list of tags of this sticker. - - - A read-only list with the tags of this sticker. - - - - - Gets the asset hash of this sticker. - - - A with the asset hash of this sticker. - - - - - Gets the preview asset hash of this sticker. - - - A with the preview asset hash of this sticker. - - - - - Gets the format type of this sticker. - - - A with the format type of this sticker. - - Represents a generic message sent by the system. @@ -9329,6 +9331,214 @@ otherwise . + + + Represents a custom sticker within a guild. + + + + + Gets the users id who uploaded the sticker. + + + In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. + + + + + Gets the guild that this custom sticker is in. + + + + + Modifies this sticker. + + + This method modifies this sticker with the specified properties. To see an example of this + method and what properties are available, please refer to . +
+
+ The bot needs the MANAGE_EMOJIS_AND_STICKERS permission within the guild in order to modify stickers. +
+ + The following example replaces the name of the sticker with kekw. + + await sticker.ModifyAsync(x => x.Name = "kekw"); + + + A delegate containing the properties to modify the sticker with. + The options to be used when sending the request. + + A task that represents the asynchronous modification operation. + +
+ + + Deletes the current sticker. + + + The bot neeeds the MANAGE_EMOJIS_AND_STICKERS permission inside the guild in order to delete stickers. + + The options to be used when sending the request. + + A task that represents the asynchronous deletion operation. + + + + + Represents a discord sticker. + + + + + Gets the ID of this sticker. + + + A snowflake ID associated with this sticker. + + + + + Gets the ID of the pack of this sticker. + + + A snowflake ID associated with the pack of this sticker. + + + + + Gets the name of this sticker. + + + A with the name of this sticker. + + + + + Gets the description of this sticker. + + + A with the description of this sticker. + + + + + Gets the list of tags of this sticker. + + + A read-only list with the tags of this sticker. + + + + + Gets the asset hash of this sticker. + + + A with the asset hash of this sticker. + + + + + Gets the preview asset hash of this sticker. + + + A with the preview asset hash of this sticker. + + + + + Gets the format type of this sticker. + + + A with the format type of this sticker. + + + + + Gets the image url for this sticker. + + + + + Represents a partial sticker item received with a message. + + + + + The id of the sticker. + + + + + The name of the sticker. + + + + + The format of the sticker. + + + + + Represents a discord sticker pack. + + The type of the stickers within the collection + + + + Gets the id of the sticker pack. + + + + + Gets a collection of the stickers in the pack. + + + + + Gets the name of the sticker pack. + + + + + Gets the id of the pack's SKU. + + + + + Gets the id of a sticker in the pack which is shown as the pack's icon. + + + + + Gets the description of the sticker pack. + + + + + Gets the id of the sticker pack's banner image + + + + + Represents a class used to modify stickers. + + + + + Gets or sets the name of the sticker. + + + + + Gets or sets the description of the sticker. + + + + + Gets or sets the tags of the sticker. + + Represents a Discord Team. diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs index f80abbe38..39419f068 100644 --- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs @@ -169,12 +169,13 @@ namespace Discord /// IReadOnlyCollection Components { get; } - /// Gets all stickers included in this message. + /// + /// Gets all stickers items included in this message. /// /// - /// A read-only collection of sticker objects. + /// A read-only collection of sticker item objects. /// - IReadOnlyCollection Stickers { get; } + IReadOnlyCollection Stickers { get; } /// /// Gets the flags related to this message. diff --git a/src/Discord.Net.Core/Entities/Stickers/ISticker.cs b/src/Discord.Net.Core/Entities/Stickers/ISticker.cs index eca613051..e16e03990 100644 --- a/src/Discord.Net.Core/Entities/Stickers/ISticker.cs +++ b/src/Discord.Net.Core/Entities/Stickers/ISticker.cs @@ -7,7 +7,7 @@ namespace Discord /// /// Represents a discord sticker. /// - public interface ISticker + public interface ISticker : IStickerItem { /// /// Gets the ID of this sticker. @@ -64,7 +64,7 @@ namespace Discord /// /// A with the format type of this sticker. /// - StickerFormatType FormatType { get; } + StickerFormatType Format { get; } /// /// Gets the image url for this sticker. diff --git a/src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs b/src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs new file mode 100644 index 000000000..3825a2702 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a partial sticker item received with a message. + /// + public interface IStickerItem + { + /// + /// The id of the sticker. + /// + ulong Id { get; } + + /// + /// The name of the sticker. + /// + string Name { get; } + + /// + /// The format of the sticker. + /// + StickerFormatType Format { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Stickers/StickerPack.cs b/src/Discord.Net.Core/Entities/Stickers/StickerPack.cs new file mode 100644 index 000000000..b0750efc1 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/StickerPack.cs @@ -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 +{ + /// + /// Represents a discord sticker pack. + /// + /// The type of the stickers within the collection + public class StickerPack where TSticker : ISticker + { + /// + /// Gets the id of the sticker pack. + /// + public ulong Id { get; } + + /// + /// Gets a collection of the stickers in the pack. + /// + public IReadOnlyCollection Stickers { get; } + + /// + /// Gets the name of the sticker pack. + /// + public string Name { get; } + + /// + /// Gets the id of the pack's SKU. + /// + public ulong SkuId { get; } + + /// + /// Gets the id of a sticker in the pack which is shown as the pack's icon. + /// + public ulong? CoverStickerId { get; } + + /// + /// Gets the description of the sticker pack. + /// + public string Description { get; } + + /// + /// Gets the id of the sticker pack's banner image + /// + public ulong BannerAssetId { get; } + + internal StickerPack(string name, ulong id, ulong skuid, ulong? coverStickerId, string description, ulong bannerAssetId, IEnumerable stickers) + { + this.Name = name; + this.Id = id; + this.SkuId = skuid; + this.CoverStickerId = coverStickerId; + this.Description = description; + this.BannerAssetId = bannerAssetId; + + this.Stickers = stickers.ToImmutableArray(); + } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Sticker.cs b/src/Discord.Net.Rest/API/Common/Sticker.cs index 31bd97370..da171a802 100644 --- a/src/Discord.Net.Rest/API/Common/Sticker.cs +++ b/src/Discord.Net.Rest/API/Common/Sticker.cs @@ -21,6 +21,8 @@ namespace Discord.API public string PreviewAsset { get; set; } [JsonProperty("format_type")] public StickerFormatType FormatType { get; set; } + [JsonProperty("guild_id")] + public Optional GuildId { get; set; } [JsonProperty("user")] public Optional User { get; set; } } diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index 8aa36360f..4cb5f6e02 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -3527,6 +3527,50 @@ + + + Creates a new sticker in this guild. + + The name of the sticker. + The description of the sticker. + The tags of the sticker. + The image of the new emote. + The options to be used when sending the request. + + A task that represents the asynchronous creation operation. The task result contains the created sticker. + + + + + Gets a specific sticker within this guild. + + The id of the sticker to get. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains the sticker found with the + specified ; if none is found. + + + + + Gets a collection of all stickers within this guild. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection + of stickers found within the guild. + + + + + Deletes a sticker within this guild. + + The sticker to delete. + The options to be used when sending the request. + + A task that represents the asynchronous removal operation. + + @@ -3970,6 +4014,33 @@ + + + Represents a Rest-based custom sticker within a guild. + + + + + Gets the users id who uploaded the sticker. + + + In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. + + + + + Gets the guild that this custom sticker is in. + + + Note: This property can be if the sticker wasnt fetched from a guild. + + + + + + + + Regex used to check if some text is formatted as inline code. @@ -4268,6 +4339,52 @@ This operation may only be called on a channel. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents a partial sticker received in a message. + + + + + + + + + + + Resolves this sticker item by fetching the from the API. + + + A task representing the download operation, the result of the task is a sticker object. + + 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. - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 820461e9a..bedb9de2f 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -559,7 +559,7 @@ namespace Discord.Rest return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false); } - public static async Task ModifyStickerAsync(BaseDiscordClient client, IGuild guild, ISticker sticker, Action func, + public static async Task ModifyStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, Action func, RequestOptions options = null) { if (func == null) @@ -577,10 +577,10 @@ namespace Discord.Rest Optional.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); } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 126a211c8..e87e24b25 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -19,6 +19,7 @@ namespace Discord.Rest { private ImmutableDictionary _roles; private ImmutableArray _emotes; + private ImmutableArray _stickers; private ImmutableArray _features; /// @@ -112,6 +113,7 @@ namespace Discord.Rest public IReadOnlyCollection Roles => _roles.ToReadOnlyCollection(); /// public IReadOnlyCollection Emotes => _emotes; + public IReadOnlyCollection Stickers => _stickers; /// public IReadOnlyCollection Features => _features; @@ -190,6 +192,23 @@ namespace Discord.Rest } _roles = roles.ToImmutable(); + if (model.Stickers != null) + { + var stickers = new ImmutableArray(); + 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(); + Available = true; } internal void Update(WidgetModel model) @@ -908,6 +927,78 @@ namespace Discord.Rest public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) => GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); + //Stickers + /// + /// Creates a new sticker in this guild. + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The image of the new emote. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public async Task CreateStickerAsync(string name, string description, IEnumerable 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); + } + /// + /// Gets a specific sticker within this guild. + /// + /// The id of the sticker to get. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the sticker found with the + /// specified ; if none is found. + /// + public async Task 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); + } + /// + /// Gets a collection of all stickers within this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection + /// of stickers found within the guild. + /// + public async Task> GetStickersAsync(RequestOptions options = null) + { + var models = await Discord.ApiClient.ListGuildStickersAsync(this.Id, options).ConfigureAwait(false); + + if (models.Length == 0) + return null; + + List stickers = new List(); + + 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(); + } + /// + /// Deletes a sticker within this guild. + /// + /// The sticker to delete. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous removal operation. + /// + public Task DeleteStickerAsync(CustomSticker sticker, RequestOptions options = null) + => sticker.DeleteAsync(options); + //IGuild /// bool IGuild.Available => Available; @@ -918,6 +1009,8 @@ namespace Discord.Rest /// IReadOnlyCollection IGuild.Roles => Roles; + IReadOnlyCollection IGuild.Stickers => Stickers; + /// async Task> IGuild.GetBansAsync(RequestOptions options) => await GetBansAsync(options).ConfigureAwait(false); @@ -1169,5 +1262,23 @@ namespace Discord.Rest /// async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options) + => await CreateStickerAsync(name, description, tags, image, options); + async Task IGuild.GetStickerAsync(ulong id, CacheMode mode, RequestOptions options) + { + if (mode != CacheMode.AllowDownload) + return null; + + return await GetStickerAsync(id, options); + } + async Task> 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(); } } diff --git a/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs b/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs new file mode 100644 index 000000000..41462572c --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs @@ -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 +{ + /// + /// Represents a Rest-based custom sticker within a guild. + /// + public class CustomSticker : Sticker, ICustomSticker + { + /// + /// Gets the users id who uploaded the sticker. + /// + /// + /// In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. + /// + public ulong? AuthorId { get; private set; } + + /// + /// Gets the guild that this custom sticker is in. + /// + /// + /// Note: This property can be if the sticker wasnt fetched from a guild. + /// + 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; + } + + /// + public Task DeleteAsync(RequestOptions options = null) + => GuildHelper.DeleteStickerAsync(Discord, GuildId, this, options); + + /// + public async Task ModifyAsync(Action func, RequestOptions options = null) + { + var model = await GuildHelper.ModifyStickerAsync(Discord, GuildId, this, func, options); + Update(model); + } + + IGuild ICustomSticker.Guild => Guild; + } +} diff --git a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs index c9aba15f8..cc77beba2 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs @@ -60,7 +60,7 @@ namespace Discord.Rest /// public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); /// - public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); + public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); /// public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); @@ -236,7 +236,7 @@ namespace Discord.Rest IReadOnlyCollection IMessage.Components => Components; /// - IReadOnlyCollection IMessage.Stickers => Stickers; + IReadOnlyCollection IMessage.Stickers => Stickers; /// public IReadOnlyDictionary Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs index aa6b44da6..e6f3ac30d 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs @@ -21,7 +21,7 @@ namespace Discord.Rest private ImmutableArray _tags = ImmutableArray.Create(); private ImmutableArray _roleMentionIds = ImmutableArray.Create(); private ImmutableArray _userMentions = ImmutableArray.Create(); - private ImmutableArray _stickers = ImmutableArray.Create(); + private ImmutableArray _stickers = ImmutableArray.Create(); /// public override bool IsTTS => _isTTS; @@ -46,7 +46,7 @@ namespace Discord.Rest /// public override IReadOnlyCollection Tags => _tags; /// - public override IReadOnlyCollection Stickers => _stickers; + public override IReadOnlyCollection Stickers => _stickers; /// public IUserMessage ReferencedMessage => _referencedMessage; @@ -136,18 +136,18 @@ namespace Discord.Rest _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) { - var stickers = ImmutableArray.CreateBuilder(value.Length); + var stickers = ImmutableArray.CreateBuilder(value.Length); for (int i = 0; i < value.Length; i++) - stickers.Add(Sticker.Create(value[i])); + stickers.Add(new StickerItem(Discord, value[i])); _stickers = stickers.ToImmutable(); } else - _stickers = ImmutableArray.Create(); + _stickers = ImmutableArray.Create(); } } diff --git a/src/Discord.Net.Rest/Entities/Messages/Sticker.cs b/src/Discord.Net.Rest/Entities/Messages/Sticker.cs index aa4960f5b..6a5d35a3b 100644 --- a/src/Discord.Net.Rest/Entities/Messages/Sticker.cs +++ b/src/Discord.Net.Rest/Entities/Messages/Sticker.cs @@ -3,45 +3,49 @@ using System.Diagnostics; using System.Linq; using Model = Discord.API.Sticker; -namespace Discord +namespace Discord.Rest { /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class Sticker : ISticker + public class Sticker : RestEntity, ISticker { /// - public ulong Id { get; } + public ulong PackId { get; internal set; } /// - public ulong PackId { get; } + public string Name { get; internal set; } /// - public string Name { get; } + public string Description { get; internal set; } /// - public string Description { get; } + public IReadOnlyCollection Tags { get; internal set; } /// - public IReadOnlyCollection Tags { get; } + public string Asset { get; internal set; } /// - public string Asset { get; } + public string PreviewAsset { get; internal set; } /// - public string PreviewAsset { get; } - /// - public StickerFormatType FormatType { get; } + public StickerFormatType Format { get; internal set; } + + /// + 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})"; diff --git a/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs b/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs index 61284e604..dade33bb9 100644 --- a/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs +++ b/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs @@ -10,17 +10,13 @@ namespace Discord.Rest /// /// Represents a partial sticker received in a message. /// - public class StickerItem : RestEntity + public class StickerItem : RestEntity, IStickerItem { - /// - /// The name of this sticker. - /// - public readonly string Name; + /// + public string Name { get; } - /// - /// The format of this sticker. - /// - public readonly StickerFormatType Format; + /// + public StickerFormatType Format { get; } internal StickerItem(BaseDiscordClient client, Model model) : base(client, model.Id) @@ -40,7 +36,10 @@ namespace Discord.Rest { 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); } } } diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.cs b/src/Discord.Net.WebSocket/BaseSocketClient.cs index 1cfe6c8bf..e8c5ca6ca 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.cs @@ -44,6 +44,10 @@ namespace Discord.WebSocket internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; + /// + /// Gets a collection of default stickers. + /// + public abstract IReadOnlyCollection> DefaultStickerPacks { get; } /// /// Gets the current logged-in user. /// @@ -268,6 +272,16 @@ namespace Discord.WebSocket /// public Task GetInviteAsync(string inviteId, RequestOptions options = null) => ClientHelper.GetInviteAsync(this, inviteId, options ?? RequestOptions.Default); + /// + /// Gets a sticker. + /// + /// Whether or not to allow downloading from the api. + /// The id of the sticker to get. + /// The options to be used when sending the request. + /// + /// A if found, otherwise . + /// + public abstract Task GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); // IDiscordClient /// diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj index 167ccebb0..bcaf81f31 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj @@ -20,7 +20,7 @@ 3.0.1 - TRACE; + TRACE;DEBUG;DEBUG_PACKETS diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index 61e22ffaa..60a45c005 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -118,6 +118,11 @@ Provides access to a REST-only client with a shared state from this client. + + + Gets a collection of default stickers. + + 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. + + + Gets a sticker. + + Whether or not to allow downloading from the api. + The id of the sticker to get. + The options to be used when sending the request. + + A if found, otherwise . + + @@ -820,6 +836,9 @@ + + + @@ -858,6 +877,9 @@ + + + @@ -959,6 +981,9 @@ + + + @@ -1083,6 +1108,16 @@ Clears cached users from the client. + + + + + + Gets a sticker. + + The unique identifier of the sticker. + A sticker if found, otherwise . + @@ -3030,6 +3065,11 @@ + + + Gets a collection of all custom stickers for this guild. + + @@ -3438,6 +3478,59 @@ + + + Gets a specific sticker within this guild. + + The id of the sticker to get. + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains the sticker found with the + specified ; if none is found. + + + + + Gets a specific sticker within this guild. + + The id of the sticker to get. + A sticker, if none is found then . + + + + Gets a collection of all stickers within this guild. + + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection + of stickers found within the guild. + + + + + Creates a new sticker in this guild. + + The name of the sticker. + The description of the sticker. + The tags of the sticker. + The image of the new emote. + The options to be used when sending the request. + + A task that represents the asynchronous creation operation. The task result contains the created sticker. + + + + + Deletes a sticker within this guild. + + The sticker to delete. + The options to be used when sending the request. + + A task that represents the asynchronous removal operation. + + Gets the name of the guild. @@ -3479,6 +3572,9 @@ + + + @@ -4417,6 +4513,83 @@ + + + Gets the user that uploaded the guild sticker. + + + + This may return in the WebSocket implementation due to incomplete user collection in + large guilds, or the bot doesnt have the MANAGE_EMOJIS_AND_STICKERS permission. + + + + + + Gets the guild the sticker lives in. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents an unknown sticker received over the gateway. + + + + + + + + + + + + + + + + + + + + Attempts to try to find the sticker. + + + The sticker representing this unknown stickers Id, if none is found then . + + Represents a WebSocket-based group user. diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index 450145f1c..30ec5ef19 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using System.Threading; +using System.Collections.Immutable; namespace Discord.WebSocket { @@ -16,6 +17,7 @@ namespace Discord.WebSocket private readonly bool _automaticShards; private int[] _shardIds; private DiscordSocketClient[] _shards; + private ImmutableArray> _defaultStickers; private int _totalShards; private SemaphoreSlim[] _identifySemaphores; private object _semaphoreResetLock; @@ -40,6 +42,10 @@ namespace Discord.WebSocket return base.ApiClient; } } + /// + public override IReadOnlyCollection> DefaultStickerPacks + => _defaultStickers.ToReadOnlyCollection(); + /// public override IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); /// @@ -77,6 +83,7 @@ namespace Discord.WebSocket _shardIdsToIndex = new Dictionary(); config.DisplayInitialLog = false; _baseConfig = config; + _defaultStickers = new ImmutableArray>(); if (config.TotalShards == null) _automaticShards = true; @@ -155,6 +162,10 @@ namespace Discord.WebSocket //Assume thread safe: already in a connection lock for (int i = 0; i < _shards.Length; i++) await _shards[i].LoginAsync(tokenType, token); + + if(this._defaultStickers.Length == 0) + await DownloadDefaultStickersAsync().ConfigureAwait(false); + } internal override async Task OnLogoutAsync() { @@ -247,6 +258,63 @@ namespace Discord.WebSocket result += _shards[i].Guilds.Count; return result; } + /// + public override async Task 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( + model.Name, + model.Id, + model.SkuId, + model.CoverStickerId.ToNullable(), + model.Description, + model.BannerAssetId, + stickers + ); + + _defaultStickers.Add(pack); + } + } /// public override SocketUser GetUser(ulong id) diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 52a5d309d..789f4aa53 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -44,6 +44,7 @@ namespace Discord.WebSocket private RestApplication _applicationInfo; private bool _isDisposed; private GatewayIntents _gatewayIntents; + private ImmutableArray> _defaultStickers; /// /// 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; /// public override IReadOnlyCollection Guilds => State.Guilds; + /// + public override IReadOnlyCollection> DefaultStickerPacks + { + get + { + if (this._shardedClient != null) + return this._shardedClient.DefaultStickerPacks; + else + return _defaultStickers.ToReadOnlyCollection(); + } + } /// public override IReadOnlyCollection PrivateChannels => State.PrivateChannels; /// @@ -137,6 +149,7 @@ namespace Discord.WebSocket Rest = new DiscordSocketRestClient(config, ApiClient); _heartbeatTimes = new ConcurrentQueue(); _gatewayIntents = config.GatewayIntents; + _defaultStickers = new ImmutableArray>(); _stateLock = new SemaphoreSlim(1, 1); _gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); @@ -195,6 +208,31 @@ namespace Discord.WebSocket 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( + model.Name, + model.Id, + model.SkuId, + model.CoverStickerId.ToNullable(), + model.Description, + model.BannerAssetId, + stickers + ); + + _defaultStickers.Add(pack); + } + } + } + /// internal override async Task OnLogoutAsync() { @@ -368,6 +406,51 @@ namespace Discord.WebSocket internal void RemoveUser(ulong id) => State.RemoveUser(id); + /// + public override async Task 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); + } + } + + /// + /// Gets a sticker. + /// + /// The unique identifier of the sticker. + /// A sticker if found, otherwise . + public SocketSticker GetSticker(ulong id) + => GetStickerAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult(); + /// public override async ValueTask> GetVoiceRegionsAsync(RequestOptions options = null) { diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 2521d6b2b..390bc0512 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -533,6 +533,8 @@ namespace Discord.WebSocket stickers.TryAdd(sticker.Id, entity); } + + _stickers = stickers; } else _stickers = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, 7); @@ -1192,6 +1194,13 @@ namespace Discord.WebSocket return AddOrUpdateSticker(model); } /// + /// Gets a specific sticker within this guild. + /// + /// The id of the sticker to get. + /// A sticker, if none is found then . + public SocketCustomSticker GetSticker(ulong id) + => GetStickerAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult(); + /// /// Gets a collection of all stickers within this guild. /// /// The that determines whether the object should be fetched from cache. @@ -1629,7 +1638,8 @@ namespace Discord.WebSocket => await GetStickerAsync(id, mode, options); async Task> IGuild.GetStickersAsync(CacheMode mode, RequestOptions 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() { diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs index 1b62d14dd..167440069 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs @@ -106,7 +106,7 @@ namespace Discord.WebSocket /// public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); /// - public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); + public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); /// public IReadOnlyDictionary 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 IMessage.Components => Components; /// - IReadOnlyCollection IMessage.Stickers => Stickers; + IReadOnlyCollection IMessage.Stickers => Stickers; internal void AddReaction(SocketReaction reaction) { diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index 597544f4d..8127d54f5 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -23,7 +23,7 @@ namespace Discord.WebSocket private ImmutableArray _tags = ImmutableArray.Create(); private ImmutableArray _roleMentions = ImmutableArray.Create(); private ImmutableArray _userMentions = ImmutableArray.Create(); - private ImmutableArray _stickers = ImmutableArray.Create(); + private ImmutableArray _stickers = ImmutableArray.Create(); /// public override bool IsTTS => _isTTS; @@ -48,7 +48,7 @@ namespace Discord.WebSocket /// public override IReadOnlyCollection MentionedUsers => _userMentions; /// - public override IReadOnlyCollection Stickers => _stickers; + public override IReadOnlyCollection Stickers => _stickers; /// public IUserMessage ReferencedMessage => _referencedMessage; @@ -162,18 +162,35 @@ namespace Discord.WebSocket _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) { - var stickers = ImmutableArray.CreateBuilder(value.Length); + var stickers = ImmutableArray.CreateBuilder(value.Length); 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(); } else - _stickers = ImmutableArray.Create(); + _stickers = ImmutableArray.Create(); } } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketCustomSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs similarity index 94% rename from src/Discord.Net.WebSocket/Entities/Messages/SocketCustomSticker.cs rename to src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs index 4e00873c7..b8c29ed35 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketCustomSticker.cs +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs @@ -51,7 +51,7 @@ namespace Discord.WebSocket if(!Guild.CurrentUser.GuildPermissions.Has(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); } @@ -59,7 +59,7 @@ namespace Discord.WebSocket /// 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); } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs similarity index 62% rename from src/Discord.Net.WebSocket/Entities/Messages/SocketSticker.cs rename to src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs index 4b4f6a605..b450e4c36 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketSticker.cs +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs @@ -12,36 +12,42 @@ namespace Discord.WebSocket public class SocketSticker : SocketEntity, ISticker { /// - public ulong PackId { get; private set; } + public virtual ulong PackId { get; private set; } /// - public string Name { get; private set; } + public string Name { get; internal set; } /// - public string Description { get; private set; } + public virtual string Description { get; private set; } /// - public IReadOnlyCollection Tags { get; private set; } + public virtual IReadOnlyCollection Tags { get; private set; } /// - public string Asset { get; private set; } + public virtual string Asset { get; private set; } /// - public string PreviewAsset { get; private set; } + public virtual string PreviewAsset { get; private set; } /// - public StickerFormatType FormatType { get; private set; } + public StickerFormatType Format { get; internal set; } /// public string GetStickerUrl() - => CDN.GetStickerUrl(this.Id, this.FormatType); + => CDN.GetStickerUrl(this.Id, this.Format); internal SocketSticker(DiscordSocketClient client, ulong id) : base(client, id) { } 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); return entity; } @@ -53,7 +59,7 @@ namespace Discord.WebSocket this.PackId = model.PackId; this.Asset = model.Asset; this.PreviewAsset = model.PreviewAsset; - this.FormatType = model.FormatType; + this.Format = model.FormatType; if (model.Tags.IsSpecified) { diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs new file mode 100644 index 000000000..b54af3729 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs @@ -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 +{ + /// + /// Represents an unknown sticker received over the gateway. + /// + public class SocketUnknownSticker : SocketSticker + { + /// + public override string Asset + => null; + + /// + public override IReadOnlyCollection Tags + => null; + + /// + public override string Description + => null; + + /// + public override ulong PackId + => 0; + + /// + 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; + } + + /// + /// Attempts to try to find the sticker. + /// + /// + /// The sticker representing this unknown stickers Id, if none is found then . + /// + public Task ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + => Discord.GetStickerAsync(this.Id, mode, options); + } +}