@@ -20,7 +20,7 @@ namespace Discord.API.Rest | |||
{ | |||
var d = new Dictionary<string, object>(); | |||
d["file"] = new MultipartFile(File, Name); | |||
d["file"] = new MultipartFile(File, Name + ".dat"); | |||
d["name"] = Name; | |||
d["description"] = Description; | |||
@@ -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 | |||
/// <summary> | |||
/// Represents a Rest-based custom sticker within a guild. | |||
/// </summary> | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class CustomSticker : Sticker, ICustomSticker | |||
{ | |||
/// <summary> | |||
@@ -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; | |||
} | |||
} |
@@ -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); } | |||
} | |||
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. | |||
</summary> | |||
</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"> | |||
<inheritdoc /> | |||
</member> | |||
@@ -4513,6 +4528,11 @@ | |||
<member name="P:Discord.WebSocket.SocketEntity`1.Id"> | |||
<inheritdoc /> | |||
</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"> | |||
<summary> | |||
Gets the user that uploaded the guild sticker. | |||
@@ -4538,6 +4558,11 @@ | |||
<member name="M:Discord.WebSocket.SocketCustomSticker.DeleteAsync(Discord.RequestOptions)"> | |||
<inheritdoc/> | |||
</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"> | |||
<inheritdoc/> | |||
</member> | |||
@@ -4562,6 +4587,9 @@ | |||
<member name="M:Discord.WebSocket.SocketSticker.GetStickerUrl"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="M:Discord.WebSocket.SocketSticker.Equals(System.Object)"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketUnknownSticker"> | |||
<summary> | |||
Represents an unknown sticker received over the gateway. | |||
@@ -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<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) | |||
case "CHANNEL_PINS_ACK": | |||
@@ -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 | |||
{ | |||
/// <summary> | |||
/// Represents a custom sticker within a guild received over the gateway. | |||
/// </summary> | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class SocketCustomSticker : SocketSticker, ICustomSticker | |||
{ | |||
/// <summary> | |||
@@ -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; | |||
@@ -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 | |||
{ | |||
/// <summary> | |||
/// Represents a general sticker received over the gateway. | |||
/// </summary> | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class SocketSticker : SocketEntity<ulong>, ISticker | |||
{ | |||
/// <inheritdoc/> | |||
@@ -70,5 +75,27 @@ namespace Discord.WebSocket | |||
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.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
@@ -10,6 +11,7 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// Represents an unknown sticker received over the gateway. | |||
/// </summary> | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class SocketUnknownSticker : SocketSticker | |||
{ | |||
/// <inheritdoc/> | |||
@@ -56,5 +58,7 @@ namespace Discord.WebSocket | |||
/// </returns> | |||
public Task<SocketSticker> ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||
=> Discord.GetStickerAsync(this.Id, mode, options); | |||
private string DebuggerDisplay => $"{Name} ({Id})"; | |||
} | |||
} |