diff --git a/src/client/ClientDataManager.js b/src/client/ClientDataManager.js index 1ebcffdef..9ba568a1b 100644 --- a/src/client/ClientDataManager.js +++ b/src/client/ClientDataManager.js @@ -95,7 +95,7 @@ class ClientDataManager { const already = guild.emojis.has(data.id); if (data && !already) { let emoji = new Emoji(guild, data); - this.client.emit(Constants.Events.EMOJI_CREATE, emoji); + this.client.emit(Constants.Events.GUILD_EMOJI_CREATE, emoji); guild.emojis.set(emoji.id, emoji); return emoji; } else if (already) { @@ -107,7 +107,7 @@ class ClientDataManager { killEmoji(emoji) { if (!(emoji instanceof Emoji && emoji.guild)) return; - this.client.emit(Constants.Events.EMOJI_DELETE, emoji); + this.client.emit(Constants.Events.GUILD_EMOJI_DELETE, emoji); emoji.guild.emojis.delete(emoji.id); } diff --git a/src/client/actions/GuildEmojiCreate.js b/src/client/actions/GuildEmojiCreate.js index a3f238fe5..a4234fcdd 100644 --- a/src/client/actions/GuildEmojiCreate.js +++ b/src/client/actions/GuildEmojiCreate.js @@ -1,9 +1,9 @@ const Action = require('./Action'); -class EmojiCreateAction extends Action { - handle(data, guild) { +class GuildEmojiCreateAction extends Action { + handle(guild, createdEmoji) { const client = this.client; - const emoji = client.dataManager.newEmoji(data, guild); + const emoji = client.dataManager.newEmoji(createdEmoji, guild); return { emoji, }; @@ -15,4 +15,4 @@ class EmojiCreateAction extends Action { * @event Client#guildEmojiCreate * @param {Emoji} emoji The emoji that was created. */ -module.exports = EmojiCreateAction; +module.exports = GuildEmojiCreateAction; diff --git a/src/client/actions/GuildEmojiDelete.js b/src/client/actions/GuildEmojiDelete.js index 7fdd1ca32..3ee4427d5 100644 --- a/src/client/actions/GuildEmojiDelete.js +++ b/src/client/actions/GuildEmojiDelete.js @@ -1,11 +1,11 @@ const Action = require('./Action'); -class EmojiDeleteAction extends Action { - handle(data) { +class GuildEmojiDeleteAction extends Action { + handle(emoji) { const client = this.client; - client.dataManager.killEmoji(data); + client.dataManager.killEmoji(emoji); return { - data, + emoji, }; } } @@ -15,4 +15,4 @@ class EmojiDeleteAction extends Action { * @event Client#guildEmojiDelete * @param {Emoji} emoji The emoji that was deleted. */ -module.exports = EmojiDeleteAction; +module.exports = GuildEmojiDeleteAction; diff --git a/src/client/actions/GuildEmojiUpdate.js b/src/client/actions/GuildEmojiUpdate.js index 88e0c395c..a79072c22 100644 --- a/src/client/actions/GuildEmojiUpdate.js +++ b/src/client/actions/GuildEmojiUpdate.js @@ -1,22 +1,8 @@ const Action = require('./Action'); class GuildEmojiUpdateAction extends Action { - handle(data, guild) { - const client = this.client; - for (let emoji of data.emojis) { - const already = guild.emojis.has(emoji.id); - if (already) { - client.dataManager.updateEmoji(guild.emojis.get(emoji.id), emoji); - } else { - emoji = client.dataManager.newEmoji(emoji, guild); - } - } - for (let emoji of guild.emojis) { - if (!data.emoijs.has(emoji.id)) client.dataManager.killEmoji(emoji); - } - return { - emojis: data.emojis, - }; + handle(oldEmoji, newEmoji) { + this.client.dataManager.updateEmoji(oldEmoji, newEmoji); } } diff --git a/src/client/websocket/packets/WebSocketPacketManager.js b/src/client/websocket/packets/WebSocketPacketManager.js index 3bfb8af44..f5779224d 100644 --- a/src/client/websocket/packets/WebSocketPacketManager.js +++ b/src/client/websocket/packets/WebSocketPacketManager.js @@ -27,6 +27,7 @@ class WebSocketPacketManager { this.register(Constants.WSEvents.GUILD_ROLE_CREATE, require('./handlers/GuildRoleCreate')); this.register(Constants.WSEvents.GUILD_ROLE_DELETE, require('./handlers/GuildRoleDelete')); this.register(Constants.WSEvents.GUILD_ROLE_UPDATE, require('./handlers/GuildRoleUpdate')); + this.register(Constants.WSEvents.GUILD_EMOJIS_UPDATE, require('./handlers/GuildEmojisUpdate')); this.register(Constants.WSEvents.GUILD_MEMBERS_CHUNK, require('./handlers/GuildMembersChunk')); this.register(Constants.WSEvents.CHANNEL_CREATE, require('./handlers/ChannelCreate')); this.register(Constants.WSEvents.CHANNEL_DELETE, require('./handlers/ChannelDelete')); diff --git a/src/client/websocket/packets/handlers/GuildEmojiUpdate.js b/src/client/websocket/packets/handlers/GuildEmojiUpdate.js deleted file mode 100644 index 5f983cd5d..000000000 --- a/src/client/websocket/packets/handlers/GuildEmojiUpdate.js +++ /dev/null @@ -1,13 +0,0 @@ -const AbstractHandler = require('./AbstractHandler'); - -class GuildEmojiUpdate extends AbstractHandler { - handle(packet) { - const client = this.packetManager.client; - const data = packet.d; - const guild = client.guilds.get(data.guild_id); - if (!guild) return; - client.actions.EmojiUpdate.handle(data, guild); - } -} - -module.exports = GuildEmojiUpdate; diff --git a/src/client/websocket/packets/handlers/GuildEmojisUpdate.js b/src/client/websocket/packets/handlers/GuildEmojisUpdate.js new file mode 100644 index 000000000..523f2de2c --- /dev/null +++ b/src/client/websocket/packets/handlers/GuildEmojisUpdate.js @@ -0,0 +1,40 @@ +const AbstractHandler = require('./AbstractHandler'); + +function mappify(iterable) { + const map = new Map(); + for (const x of iterable) map.set(...x); + return map; +} + +class GuildEmojisUpdate extends AbstractHandler { + handle(packet) { + const client = this.packetManager.client; + const data = packet.d; + const guild = client.guilds.get(data.guild_id); + if (!guild || !guild.emojis) return; + + const deletions = mappify(guild.emojis.entries()); + + for (const emoji of data.emojis) { + // determine type of emoji event + const cachedEmoji = guild.emojis.get(emoji.id); + if (cachedEmoji) { + deletions.delete(emoji.id); + if (!cachedEmoji.equals(emoji, true)) { + // emoji updated + client.actions.GuildEmojiUpdate.handle(cachedEmoji, emoji); + } + } else { + // emoji added + client.actions.GuildEmojiCreate.handle(guild, emoji); + } + } + + for (const emoji of deletions.values()) { + // emoji deleted + client.actions.GuildEmojiDelete.handle(emoji); + } + } +} + +module.exports = GuildEmojisUpdate; diff --git a/src/structures/Emoji.js b/src/structures/Emoji.js index a1823ba8f..d8a62e17e 100644 --- a/src/structures/Emoji.js +++ b/src/structures/Emoji.js @@ -103,6 +103,27 @@ class Emoji { return this.requiresColons ? `<:${this.name}:${this.id}>` : this.name; } + /** + * Whether this emoji is the same as another one + * @param {Emoji|Object} other the emoji to compare it to + * @returns {boolean} whether the emoji is equal to the given emoji or not + */ + equals(other) { + if (other instanceof Emoji) { + return ( + other.id === this.id && + other.name === this.name && + other.managed === this.managed && + other.requiresColons === this.requiresColons + ); + } else { + return ( + other.id === this.id && + other.name === this.name + ); + } + } + /** * The identifier of this emoji, used for message reactions * @readonly diff --git a/src/util/Constants.js b/src/util/Constants.js index fddc6d14a..abc94eafc 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -294,6 +294,7 @@ exports.WSEvents = { GUILD_ROLE_UPDATE: 'GUILD_ROLE_UPDATE', GUILD_BAN_ADD: 'GUILD_BAN_ADD', GUILD_BAN_REMOVE: 'GUILD_BAN_REMOVE', + GUILD_EMOJIS_UPDATE: 'GUILD_EMOJIS_UPDATE', CHANNEL_CREATE: 'CHANNEL_CREATE', CHANNEL_DELETE: 'CHANNEL_DELETE', CHANNEL_UPDATE: 'CHANNEL_UPDATE', diff --git a/test/random.js b/test/random.js index 0b22765ff..cc65fc759 100644 --- a/test/random.js +++ b/test/random.js @@ -20,6 +20,10 @@ client.on('userUpdate', (o, n) => { console.log(o.username, n.username); }); +client.on('guildEmojiCreate', e => console.log('create!!', e.name)); +client.on('guildEmojiDelete', e => console.log('delete!!', e.name)); +client.on('guildEmojiUpdate', (o, n) => console.log('update!!', o.name, n.name)); + client.on('guildMemberAdd', m => console.log(`${m.user.username} joined ${m.guild.name}`)); client.on('channelCreate', channel => {