diff --git a/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs b/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs index 291052f3a..be9cb05f0 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs @@ -20,7 +20,7 @@ namespace Discord.API.Rest { var d = new Dictionary(); - d["file"] = new MultipartFile(File, Name); + d["file"] = new MultipartFile(File, Name + ".dat"); d["name"] = Name; d["description"] = Description; diff --git a/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs b/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs index 41462572c..5307c4920 100644 --- a/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs +++ b/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,6 +11,7 @@ namespace Discord.Rest /// /// Represents a Rest-based custom sticker within a guild. /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class CustomSticker : Sticker, ICustomSticker { /// @@ -68,6 +70,8 @@ namespace Discord.Rest Update(model); } + private string DebuggerDisplay => this.Guild != null ? $"{Name} in {Guild.Name} ({Id})" : $"{Name} ({Id})"; + IGuild ICustomSticker.Guild => Guild; } } diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs new file mode 100644 index 000000000..8f3ba683b --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Gateway +{ + internal class GuildStickerUpdateEvent + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("stickers")] + public Sticker[] Stickers { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs index 4982655d7..1ed489aa5 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -651,5 +651,35 @@ namespace Discord.WebSocket remove { _speakerRemoved.Remove(value); } } internal readonly AsyncEvent> _speakerRemoved = new AsyncEvent>(); + + /// + /// Fired when a sticker in a guild is created. + /// + public event Func GuildStickerCreated + { + add { _guildStickerCreated.Add(value); } + remove { _guildStickerCreated.Remove(value); } + } + internal readonly AsyncEvent> _guildStickerCreated = new AsyncEvent>(); + + /// + /// Fired when a sticker in a guild is updated. + /// + public event Func GuildStickerUpdated + { + add { _guildStickerUpdated.Add(value); } + remove { _guildStickerUpdated.Remove(value); } + } + internal readonly AsyncEvent> _guildStickerUpdated = new AsyncEvent>(); + + /// + /// Fired when a sticker in a guild is deleted. + /// + public event Func GuildStickerDeleted + { + add { _guildStickerDeleted.Add(value); } + remove { _guildStickerDeleted.Remove(value); } + } + internal readonly AsyncEvent> _guildStickerDeleted = new AsyncEvent>(); } } diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index 60a45c005..2649e0aac 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -827,6 +827,21 @@ Fired when a speaker is removed from a stage channel. + + + Fired when a sticker in a guild is created. + + + + + Fired when a sticker in a guild is updated. + + + + + Fired when a sticker in a guild is deleted. + + @@ -4513,6 +4528,11 @@ + + + Represents a custom sticker within a guild received over the gateway. + + Gets the user that uploaded the guild sticker. @@ -4538,6 +4558,11 @@ + + + Represents a general sticker received over the gateway. + + @@ -4562,6 +4587,9 @@ + + + Represents an unknown sticker received over the gateway. diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 789f4aa53..fcef7463a 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -2327,6 +2327,59 @@ namespace Discord.WebSocket } } break; + case "GUILD_STICKERS_UPDATE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_STICKERS_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var newStickers = data.Stickers.Where(x => !guild.Stickers.Any(y => y.Id == x.Id)); + var deletedStickers = guild.Stickers.Where(x => !data.Stickers.Any(y => y.Id == x.Id)); + var updatedStickers = data.Stickers.Select(x => + { + var s = guild.Stickers.FirstOrDefault(y => y.Id == x.Id); + if (s == null) + return null; + + var e = s.Equals(x); + if (!e) + { + return (s, x) as (SocketCustomSticker Entity, API.Sticker Model)?; + } + else + { + return null; + } + }).Where(x => x.HasValue).Select(x => x.Value).ToArray(); + + foreach(var model in newStickers) + { + var entity = guild.AddSticker(model); + await TimedInvokeAsync(_guildStickerCreated, nameof(GuildStickerCreated), entity); + } + foreach(var sticker in deletedStickers) + { + var entity = guild.RemoveSticker(sticker.Id); + await TimedInvokeAsync(_guildStickerDeleted, nameof(GuildStickerDeleted), entity); + } + foreach(var entityModelPair in updatedStickers) + { + var before = entityModelPair.Entity.Clone(); + + entityModelPair.Entity.Update(entityModelPair.Model); + + await TimedInvokeAsync(_guildStickerUpdated, nameof(GuildStickerUpdated), before, entityModelPair.Entity); + } + } + break; //Ignored (User only) case "CHANNEL_PINS_ACK": diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs index b8c29ed35..97aad4f2f 100644 --- a/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs @@ -1,6 +1,7 @@ using Discord.Rest; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,6 +10,10 @@ using Model = Discord.API.Sticker; namespace Discord.WebSocket { + /// + /// Represents a custom sticker within a guild received over the gateway. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketCustomSticker : SocketSticker, ICustomSticker { /// @@ -63,6 +68,10 @@ namespace Discord.WebSocket Guild.RemoveSticker(this.Id); } + internal SocketCustomSticker Clone() => MemberwiseClone() as SocketCustomSticker; + + private string DebuggerDisplay => $"{Name} in {Guild.Name} ({Id})"; + // ICustomSticker ulong? ICustomSticker.AuthorId => this.AuthorId; diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs index b450e4c36..ec3977f19 100644 --- a/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs @@ -2,6 +2,7 @@ using Discord.Rest; using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,6 +10,10 @@ using Model = Discord.API.Sticker; namespace Discord.WebSocket { + /// + /// Represents a general sticker received over the gateway. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketSticker : SocketEntity, ISticker { /// @@ -70,5 +75,27 @@ namespace Discord.WebSocket this.Tags = ImmutableArray.Empty; } } + + private string DebuggerDisplay => $"{Name} ({Id})"; + + /// + public override bool Equals(object obj) + { + if (obj is API.Sticker stickerModel) + { + return stickerModel.Name == this.Name && + stickerModel.Desription == this.Description && + stickerModel.FormatType == this.Format && + stickerModel.Id == this.Id && + stickerModel.PackId == this.PackId && + stickerModel.Asset == this.Asset && + stickerModel.PreviewAsset == this.PreviewAsset && + (stickerModel.Tags.IsSpecified ? + stickerModel.Tags.Value == string.Join(", ", this.Tags) : + true); + } + else + return base.Equals(obj); + } } } diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs index b54af3729..771a4c413 100644 --- a/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,6 +11,7 @@ namespace Discord.WebSocket /// /// Represents an unknown sticker received over the gateway. /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketUnknownSticker : SocketSticker { /// @@ -56,5 +58,7 @@ namespace Discord.WebSocket /// public Task ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => Discord.GetStickerAsync(this.Id, mode, options); + + private string DebuggerDisplay => $"{Name} ({Id})"; } }