| @@ -20,7 +20,7 @@ namespace Discord.API.Rest | |||||
| { | { | ||||
| var d = new Dictionary<string, object>(); | var d = new Dictionary<string, object>(); | ||||
| d["file"] = new MultipartFile(File, Name); | |||||
| d["file"] = new MultipartFile(File, Name + ".dat"); | |||||
| d["name"] = Name; | d["name"] = Name; | ||||
| d["description"] = Description; | d["description"] = Description; | ||||
| @@ -1,5 +1,6 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Diagnostics; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -10,6 +11,7 @@ namespace Discord.Rest | |||||
| /// <summary> | /// <summary> | ||||
| /// Represents a Rest-based custom sticker within a guild. | /// Represents a Rest-based custom sticker within a guild. | ||||
| /// </summary> | /// </summary> | ||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class CustomSticker : Sticker, ICustomSticker | public class CustomSticker : Sticker, ICustomSticker | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -68,6 +70,8 @@ namespace Discord.Rest | |||||
| Update(model); | Update(model); | ||||
| } | } | ||||
| private string DebuggerDisplay => this.Guild != null ? $"{Name} in {Guild.Name} ({Id})" : $"{Name} ({Id})"; | |||||
| IGuild ICustomSticker.Guild => Guild; | IGuild ICustomSticker.Guild => Guild; | ||||
| } | } | ||||
| } | } | ||||
| @@ -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; } | |||||
| } | |||||
| } | |||||
| @@ -651,5 +651,35 @@ namespace Discord.WebSocket | |||||
| remove { _speakerRemoved.Remove(value); } | remove { _speakerRemoved.Remove(value); } | ||||
| } | } | ||||
| internal readonly AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>> _speakerRemoved = new AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>>(); | internal readonly AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>> _speakerRemoved = new AsyncEvent<Func<SocketStageChannel, SocketGuildUser, Task>>(); | ||||
| /// <summary> | |||||
| /// Fired when a sticker in a guild is created. | |||||
| /// </summary> | |||||
| public event Func<SocketCustomSticker, Task> GuildStickerCreated | |||||
| { | |||||
| add { _guildStickerCreated.Add(value); } | |||||
| remove { _guildStickerCreated.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketCustomSticker, Task>> _guildStickerCreated = new AsyncEvent<Func<SocketCustomSticker, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a sticker in a guild is updated. | |||||
| /// </summary> | |||||
| public event Func<SocketCustomSticker, SocketCustomSticker, Task> GuildStickerUpdated | |||||
| { | |||||
| add { _guildStickerUpdated.Add(value); } | |||||
| remove { _guildStickerUpdated.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketCustomSticker, SocketCustomSticker, Task>> _guildStickerUpdated = new AsyncEvent<Func<SocketCustomSticker, SocketCustomSticker, Task>>(); | |||||
| /// <summary> | |||||
| /// Fired when a sticker in a guild is deleted. | |||||
| /// </summary> | |||||
| public event Func<SocketCustomSticker, Task> GuildStickerDeleted | |||||
| { | |||||
| add { _guildStickerDeleted.Add(value); } | |||||
| remove { _guildStickerDeleted.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketCustomSticker, Task>> _guildStickerDeleted = new AsyncEvent<Func<SocketCustomSticker, Task>>(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -827,6 +827,21 @@ | |||||
| Fired when a speaker is removed from a stage channel. | Fired when a speaker is removed from a stage channel. | ||||
| </summary> | </summary> | ||||
| </member> | </member> | ||||
| <member name="E:Discord.WebSocket.BaseSocketClient.GuildStickerCreated"> | |||||
| <summary> | |||||
| Fired when a sticker in a guild is created. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.GuildStickerUpdated"> | |||||
| <summary> | |||||
| Fired when a sticker in a guild is updated. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="E:Discord.WebSocket.BaseSocketClient.GuildStickerDeleted"> | |||||
| <summary> | |||||
| Fired when a sticker in a guild is deleted. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.DiscordShardedClient.Latency"> | <member name="P:Discord.WebSocket.DiscordShardedClient.Latency"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| @@ -4513,6 +4528,11 @@ | |||||
| <member name="P:Discord.WebSocket.SocketEntity`1.Id"> | <member name="P:Discord.WebSocket.SocketEntity`1.Id"> | ||||
| <inheritdoc /> | <inheritdoc /> | ||||
| </member> | </member> | ||||
| <member name="T:Discord.WebSocket.SocketCustomSticker"> | |||||
| <summary> | |||||
| Represents a custom sticker within a guild received over the gateway. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketCustomSticker.Author"> | <member name="P:Discord.WebSocket.SocketCustomSticker.Author"> | ||||
| <summary> | <summary> | ||||
| Gets the user that uploaded the guild sticker. | Gets the user that uploaded the guild sticker. | ||||
| @@ -4538,6 +4558,11 @@ | |||||
| <member name="M:Discord.WebSocket.SocketCustomSticker.DeleteAsync(Discord.RequestOptions)"> | <member name="M:Discord.WebSocket.SocketCustomSticker.DeleteAsync(Discord.RequestOptions)"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="T:Discord.WebSocket.SocketSticker"> | |||||
| <summary> | |||||
| Represents a general sticker received over the gateway. | |||||
| </summary> | |||||
| </member> | |||||
| <member name="P:Discord.WebSocket.SocketSticker.PackId"> | <member name="P:Discord.WebSocket.SocketSticker.PackId"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| @@ -4562,6 +4587,9 @@ | |||||
| <member name="M:Discord.WebSocket.SocketSticker.GetStickerUrl"> | <member name="M:Discord.WebSocket.SocketSticker.GetStickerUrl"> | ||||
| <inheritdoc/> | <inheritdoc/> | ||||
| </member> | </member> | ||||
| <member name="M:Discord.WebSocket.SocketSticker.Equals(System.Object)"> | |||||
| <inheritdoc/> | |||||
| </member> | |||||
| <member name="T:Discord.WebSocket.SocketUnknownSticker"> | <member name="T:Discord.WebSocket.SocketUnknownSticker"> | ||||
| <summary> | <summary> | ||||
| Represents an unknown sticker received over the gateway. | Represents an unknown sticker received over the gateway. | ||||
| @@ -2327,6 +2327,59 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| case "GUILD_STICKERS_UPDATE": | |||||
| { | |||||
| await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_STICKERS_UPDATE)").ConfigureAwait(false); | |||||
| var data = (payload as JToken).ToObject<GuildStickerUpdateEvent>(_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) | //Ignored (User only) | ||||
| case "CHANNEL_PINS_ACK": | case "CHANNEL_PINS_ACK": | ||||
| @@ -1,6 +1,7 @@ | |||||
| using Discord.Rest; | using Discord.Rest; | ||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Diagnostics; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -9,6 +10,10 @@ using Model = Discord.API.Sticker; | |||||
| namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Represents a custom sticker within a guild received over the gateway. | |||||
| /// </summary> | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class SocketCustomSticker : SocketSticker, ICustomSticker | public class SocketCustomSticker : SocketSticker, ICustomSticker | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -63,6 +68,10 @@ namespace Discord.WebSocket | |||||
| Guild.RemoveSticker(this.Id); | Guild.RemoveSticker(this.Id); | ||||
| } | } | ||||
| internal SocketCustomSticker Clone() => MemberwiseClone() as SocketCustomSticker; | |||||
| private string DebuggerDisplay => $"{Name} in {Guild.Name} ({Id})"; | |||||
| // ICustomSticker | // ICustomSticker | ||||
| ulong? ICustomSticker.AuthorId | ulong? ICustomSticker.AuthorId | ||||
| => this.AuthorId; | => this.AuthorId; | ||||
| @@ -2,6 +2,7 @@ using Discord.Rest; | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
| using System.Diagnostics; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -9,6 +10,10 @@ using Model = Discord.API.Sticker; | |||||
| namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Represents a general sticker received over the gateway. | |||||
| /// </summary> | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class SocketSticker : SocketEntity<ulong>, ISticker | public class SocketSticker : SocketEntity<ulong>, ISticker | ||||
| { | { | ||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| @@ -70,5 +75,27 @@ namespace Discord.WebSocket | |||||
| this.Tags = ImmutableArray<string>.Empty; | this.Tags = ImmutableArray<string>.Empty; | ||||
| } | } | ||||
| } | } | ||||
| private string DebuggerDisplay => $"{Name} ({Id})"; | |||||
| /// <inheritdoc/> | |||||
| 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); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,6 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Diagnostics; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -10,6 +11,7 @@ namespace Discord.WebSocket | |||||
| /// <summary> | /// <summary> | ||||
| /// Represents an unknown sticker received over the gateway. | /// Represents an unknown sticker received over the gateway. | ||||
| /// </summary> | /// </summary> | ||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class SocketUnknownSticker : SocketSticker | public class SocketUnknownSticker : SocketSticker | ||||
| { | { | ||||
| /// <inheritdoc/> | /// <inheritdoc/> | ||||
| @@ -56,5 +58,7 @@ namespace Discord.WebSocket | |||||
| /// </returns> | /// </returns> | ||||
| public Task<SocketSticker> ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | public Task<SocketSticker> ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | ||||
| => Discord.GetStickerAsync(this.Id, mode, options); | => Discord.GetStickerAsync(this.Id, mode, options); | ||||
| private string DebuggerDisplay => $"{Name} ({Id})"; | |||||
| } | } | ||||
| } | } | ||||