From 9617144b9bf635d46f150f393ab7e8e5ae594745 Mon Sep 17 00:00:00 2001 From: Jaw0r3k Date: Sat, 1 Apr 2023 14:58:34 +0200 Subject: [PATCH 1/5] feat: support voiceChannelEffectSend event --- src/client/actions/ActionsManager.js | 1 + src/client/actions/VoiceChannelEffectSend.js | 22 +++++++ .../handlers/VOICE_CHANNEL_EFFECT_SEND.js | 5 ++ src/client/websocket/handlers/index.js | 1 + src/index.js | 1 + src/structures/VoiceChannelEffect.js | 57 +++++++++++++++++++ src/util/Constants.js | 14 +++++ typings/enums.d.ts | 5 ++ typings/index.d.ts | 15 +++++ 9 files changed, 121 insertions(+) create mode 100644 src/client/actions/VoiceChannelEffectSend.js create mode 100644 src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js create mode 100644 src/structures/VoiceChannelEffect.js diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js index 65415dd20af8..6cacfa2b8a10 100644 --- a/src/client/actions/ActionsManager.js +++ b/src/client/actions/ActionsManager.js @@ -67,6 +67,7 @@ class ActionsManager { this.register(require('./ThreadMembersUpdate')); this.register(require('./TypingStart')); this.register(require('./UserUpdate')); + this.register(require('./VoiceChannelEffectSend')); this.register(require('./VoiceStateUpdate')); this.register(require('./WebhooksUpdate')); } diff --git a/src/client/actions/VoiceChannelEffectSend.js b/src/client/actions/VoiceChannelEffectSend.js new file mode 100644 index 000000000000..456acf285359 --- /dev/null +++ b/src/client/actions/VoiceChannelEffectSend.js @@ -0,0 +1,22 @@ +'use strict'; + +const Action = require('./Action'); +const VoiceChannelEffect = require('../../../structures/VoiceChannelEffect'); +const Events = require('../../../util/Events'); + +class VoiceChannelEffectSendAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + if (!guild) return; + /** + * Emmited when someone sends an effect, such as an emoji reaction, + * in a voice channel the current user is connected to. + * @event Client#voiceChannelEffectSend + * @param {VoiceChannelEffect} voiceChannelEffect The sent voice channel effect + */ + client.emit(Events.VOICE_CHANNEL_EFFECT_SEND, new VoiceChannelEffect(data, guild);); + } +} + +module.exports = VoiceChannelEffectSendAction; diff --git a/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js b/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js new file mode 100644 index 000000000000..2047e7597e35 --- /dev/null +++ b/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.VoiceChannelEffectSend.handle(packet.d); +}; diff --git a/src/client/websocket/handlers/index.js b/src/client/websocket/handlers/index.js index df3c2ea2deca..89c7b22d1fd8 100644 --- a/src/client/websocket/handlers/index.js +++ b/src/client/websocket/handlers/index.js @@ -49,6 +49,7 @@ const handlers = Object.fromEntries([ ['USER_UPDATE', require('./USER_UPDATE')], ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')], ['TYPING_START', require('./TYPING_START')], + ['VOICE_CHANNEL_EFFECT_SEND', require('./VOICE_CHANNEL_EFFECT_SEND')], ['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')], ['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')], ['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')], diff --git a/src/index.js b/src/index.js index c8bb9803110b..441573604370 100644 --- a/src/index.js +++ b/src/index.js @@ -155,6 +155,7 @@ exports.Typing = require('./structures/Typing'); exports.User = require('./structures/User'); exports.UserContextMenuInteraction = require('./structures/UserContextMenuInteraction'); exports.VoiceChannel = require('./structures/VoiceChannel'); +exports.VoiceChannelEffect = require('./structures/VoiceChannelEffect'); exports.VoiceRegion = require('./structures/VoiceRegion'); exports.VoiceState = require('./structures/VoiceState'); exports.Webhook = require('./structures/Webhook'); diff --git a/src/structures/VoiceChannelEffect.js b/src/structures/VoiceChannelEffect.js new file mode 100644 index 000000000000..372f13bd0234 --- /dev/null +++ b/src/structures/VoiceChannelEffect.js @@ -0,0 +1,57 @@ +'use strict'; + +const { Emoji } = require('./Emoji'); + +/** + * Represents an effect used in a {@link VoiceChannel}. + */ +class VoiceChannelEffect { + constructor(data, guild) { + /** + * The guild where the effect was sent from. + * @type {Guild} + */ + this.guild = guild; + + /** + * The id of the channel the effect was sent in. + * @type {Snowflake} + */ + this.channelId = data.channel_id; + + /** + * The id of the user that sent the effect. + * @type {Snowflake} + */ + this.userId = data.user_id; + + /** + * The emoji of the effect. + * @type {?Emoji} + */ + this.emoji = data.emoji ? new Emoji(guild.client, data.emoji) : null; + + /** + * The animation type of the effect. + * @type {?AnimationType} + */ + this.animationType = data.animation_type ?? null; + + /** + * The animation id of the effect. + * @type {?number} + */ + this.animationId = data.animation_id ?? null; + } + + /** + * The channel the effect was sent in. + * @type {?VoiceChannel} + * @readonly + */ + get channel() { + return this.guild.channels.resolve(this.channelId); + } +} + +module.exports = VoiceChannelEffect; diff --git a/src/util/Constants.js b/src/util/Constants.js index 6129da41713a..e10111df3275 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -221,6 +221,7 @@ exports.Opcodes = { * * THREAD_MEMBERS_UPDATE: threadMembersUpdate * * USER_UPDATE: userUpdate * * PRESENCE_UPDATE: presenceUpdate + * * VOICE_CHANNEL_EFFECT_SEND: voiceChannelEffectSend * * VOICE_SERVER_UPDATE: voiceServerUpdate * * VOICE_STATE_UPDATE: voiceStateUpdate * * TYPING_START: typingStart @@ -305,6 +306,7 @@ exports.Events = { THREAD_MEMBERS_UPDATE: 'threadMembersUpdate', USER_UPDATE: 'userUpdate', PRESENCE_UPDATE: 'presenceUpdate', + VOICE_CHANNEL_EFFECT_SEND: 'voiceChannelEffectSend', VOICE_SERVER_UPDATE: 'voiceServerUpdate', VOICE_STATE_UPDATE: 'voiceStateUpdate', TYPING_START: 'typingStart', @@ -417,6 +419,7 @@ exports.PartialTypes = keyMirror(['USER', 'CHANNEL', 'GUILD_MEMBER', 'MESSAGE', * * USER_UPDATE * * PRESENCE_UPDATE * * TYPING_START + * * VOICE_CHANNEL_EFFECT_SEND * * VOICE_STATE_UPDATE * * VOICE_SERVER_UPDATE * * WEBHOOKS_UPDATE @@ -482,6 +485,7 @@ exports.WSEvents = keyMirror([ 'USER_UPDATE', 'PRESENCE_UPDATE', 'TYPING_START', + 'VOICE_CHANNEL_EFFECT_SEND', 'VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE', 'WEBHOOKS_UPDATE', @@ -1510,6 +1514,15 @@ exports.SortOrderTypes = createEnum([null, 'LATEST_ACTIVITY', 'CREATION_DATE']); */ exports.ForumLayoutTypes = createEnum(['NOT_SET', 'LIST_VIEW', 'GALLERY_VIEW']); +/** + * The animation type of the voice channel effect + * * PREMIUM + * * BASIC + * @typedef {string} AnimationType + * @see {@link https://discord.com/developers/docs/topics/gateway-events#voice-channel-effect-send-animation-type} + */ +exports.AnimationTypes = createEnum(['PREMIUM', 'BASIC']); + exports._cleanupSymbol = Symbol('djsCleanup'); function keyMirror(arr) { @@ -1531,6 +1544,7 @@ function createEnum(keys) { /** * @typedef {Object} Constants Constants that can be used in an enum or object-like way. * @property {Object} ActivityTypes The type of an activity of a users presence. + * @property {Object} AnimationTypes The animation type of the voice channel effect. * @property {Object} APIErrors An error encountered while performing an API request. * @property {Object} ApplicationCommandOptionTypes * The type of an {@link ApplicationCommandOption} object. diff --git a/typings/enums.d.ts b/typings/enums.d.ts index 92a86675da52..44543fb9be84 100644 --- a/typings/enums.d.ts +++ b/typings/enums.d.ts @@ -10,6 +10,11 @@ export const enum ActivityTypes { COMPETING = 5, } +export const enum AnimationTypes { + PREMIUM = 0, + BASIC = 1, +} + export const enum ApplicationCommandTypes { CHAT_INPUT = 1, USER = 2, diff --git a/typings/index.d.ts b/typings/index.d.ts index d1eff3bfaf95..de9583c9f9b1 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -97,6 +97,7 @@ import { SortOrderType, ForumLayoutType, ApplicationRoleConnectionMetadataTypes, + AnimationTypes, } from './enums'; import { APIApplicationRoleConnectionMetadata, @@ -2809,6 +2810,17 @@ export class VoiceChannel extends TextBasedChannelMixin(BaseGuildVoiceChannel, [ public setVideoQualityMode(videoQualityMode: VideoQualityMode | number, reason?: string): Promise; } +export class VoiceChannelEffect { + private constructor(data: unknown, guild: Guild); + public guild: Guild; + public channelId: Snowflake; + public userId: Snowflake; + public emoji: Emoji | null; + public animationType: AnimationTypes | null; + public animationId: number | null; + public get channel(): VoiceChannel | null; +} + export class VoiceRegion { private constructor(data: RawVoiceRegionData); public custom: boolean; @@ -3154,6 +3166,7 @@ export const Constants: { DefaultMessageNotificationLevels: EnumHolder; VerificationLevels: EnumHolder; MembershipStates: EnumHolder; + AnimationTypes: EnumHolder; AutoModerationRuleTriggerTypes: EnumHolder; AutoModerationRuleKeywordPresetTypes: EnumHolder; AutoModerationActionTypes: EnumHolder; @@ -4569,6 +4582,7 @@ export interface ClientEvents extends BaseClientEvents { threadUpdate: [oldThread: ThreadChannel, newThread: ThreadChannel]; typingStart: [typing: Typing]; userUpdate: [oldUser: User | PartialUser, newUser: User]; + voiceChannelEffectSend: [voiceChannelEffect: VoiceChannelEffect]; voiceStateUpdate: [oldState: VoiceState, newState: VoiceState]; webhookUpdate: [channel: TextChannel | NewsChannel | VoiceChannel | ForumChannel]; /** @deprecated Use interactionCreate instead */ @@ -4827,6 +4841,7 @@ export interface ConstantsEvents { THREAD_MEMBERS_UPDATE: 'threadMembersUpdate'; USER_UPDATE: 'userUpdate'; PRESENCE_UPDATE: 'presenceUpdate'; + VOICE_CHANNEL_EFFECT_SEND: 'voiceChaannelEffectSend'; VOICE_SERVER_UPDATE: 'voiceServerUpdate'; VOICE_STATE_UPDATE: 'voiceStateUpdate'; TYPING_START: 'typingStart'; From 055ea978654f988a240d002d1c1053f53278f399 Mon Sep 17 00:00:00 2001 From: Jaw0r3k Date: Sat, 1 Apr 2023 15:08:41 +0200 Subject: [PATCH 2/5] feat: add member getter --- src/client/actions/VoiceChannelEffectSend.js | 2 +- src/structures/VoiceChannelEffect.js | 11 ++++++++++- typings/index.d.ts | 11 ++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/client/actions/VoiceChannelEffectSend.js b/src/client/actions/VoiceChannelEffectSend.js index 456acf285359..05ea558c74e0 100644 --- a/src/client/actions/VoiceChannelEffectSend.js +++ b/src/client/actions/VoiceChannelEffectSend.js @@ -15,7 +15,7 @@ class VoiceChannelEffectSendAction extends Action { * @event Client#voiceChannelEffectSend * @param {VoiceChannelEffect} voiceChannelEffect The sent voice channel effect */ - client.emit(Events.VOICE_CHANNEL_EFFECT_SEND, new VoiceChannelEffect(data, guild);); + client.emit(Events.VOICE_CHANNEL_EFFECT_SEND, new VoiceChannelEffect(data, guild)); } } diff --git a/src/structures/VoiceChannelEffect.js b/src/structures/VoiceChannelEffect.js index 372f13bd0234..f000ef8eecdc 100644 --- a/src/structures/VoiceChannelEffect.js +++ b/src/structures/VoiceChannelEffect.js @@ -50,7 +50,16 @@ class VoiceChannelEffect { * @readonly */ get channel() { - return this.guild.channels.resolve(this.channelId); + return this.guild.channels.cache.get(this.channelId) ?? null; + } + + /** + * The member that sent the effect. + * @type {?GuildMember} + * @readonly + */ + get member() { + return this.guild.members.cache.get(this.userId) ?? null; } } diff --git a/typings/index.d.ts b/typings/index.d.ts index de9583c9f9b1..6c38a508379a 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -2812,13 +2812,14 @@ export class VoiceChannel extends TextBasedChannelMixin(BaseGuildVoiceChannel, [ export class VoiceChannelEffect { private constructor(data: unknown, guild: Guild); - public guild: Guild; - public channelId: Snowflake; - public userId: Snowflake; - public emoji: Emoji | null; public animationType: AnimationTypes | null; public animationId: number | null; - public get channel(): VoiceChannel | null; + public readonly channel: VoiceChannel | null; + public channelId: Snowflake; + public emoji: Emoji | null; + public guild: Guild; + public readonly member: GuildMember | null; + public userId: Snowflake; } export class VoiceRegion { From 3c6593129f9c737af549c381be0991c72c5e1d9d Mon Sep 17 00:00:00 2001 From: Jaw0r3k Date: Sat, 1 Apr 2023 15:40:20 +0200 Subject: [PATCH 3/5] Update src/util/Constants.js Co-authored-by: Tetie --- src/util/Constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/Constants.js b/src/util/Constants.js index e10111df3275..47744e93056c 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -1519,7 +1519,7 @@ exports.ForumLayoutTypes = createEnum(['NOT_SET', 'LIST_VIEW', 'GALLERY_VIEW']); * * PREMIUM * * BASIC * @typedef {string} AnimationType - * @see {@link https://discord.com/developers/docs/topics/gateway-events#voice-channel-effect-send-animation-type} + * @see {@link https://discord.com/developers/docs/topics/gateway-events#voice-channel-effect-send-animation-types} */ exports.AnimationTypes = createEnum(['PREMIUM', 'BASIC']); From 3619a91a168a1792c1a1f78dbfc2c9c6fb42ef25 Mon Sep 17 00:00:00 2001 From: Jaw0r3k Date: Sun, 2 Apr 2023 15:15:17 +0200 Subject: [PATCH 4/5] feat: add raw data --- src/client/actions/VoiceChannelEffectSend.js | 4 ++-- src/structures/VoiceChannelEffect.js | 3 ++- typings/index.d.ts | 4 +++- typings/rawDataTypes.d.ts | 12 +++++++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/client/actions/VoiceChannelEffectSend.js b/src/client/actions/VoiceChannelEffectSend.js index 05ea558c74e0..2961c93b9509 100644 --- a/src/client/actions/VoiceChannelEffectSend.js +++ b/src/client/actions/VoiceChannelEffectSend.js @@ -1,8 +1,8 @@ 'use strict'; const Action = require('./Action'); -const VoiceChannelEffect = require('../../../structures/VoiceChannelEffect'); -const Events = require('../../../util/Events'); +const VoiceChannelEffect = require('../../structures/VoiceChannelEffect'); +const { Events } = require('../../util/Constants'); class VoiceChannelEffectSendAction extends Action { handle(data) { diff --git a/src/structures/VoiceChannelEffect.js b/src/structures/VoiceChannelEffect.js index f000ef8eecdc..8cbe3c5adf6d 100644 --- a/src/structures/VoiceChannelEffect.js +++ b/src/structures/VoiceChannelEffect.js @@ -1,5 +1,6 @@ 'use strict'; +const { AnimationTypes } = require('../util/Constants'); const { Emoji } = require('./Emoji'); /** @@ -35,7 +36,7 @@ class VoiceChannelEffect { * The animation type of the effect. * @type {?AnimationType} */ - this.animationType = data.animation_type ?? null; + this.animationType = data.animation_type ? AnimationTypes[data.animation_type] : null; /** * The animation id of the effect. diff --git a/typings/index.d.ts b/typings/index.d.ts index 6c38a508379a..a0bcd5c78a62 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -161,6 +161,7 @@ import { RawWelcomeScreenData, RawWidgetData, RawWidgetMemberData, + VoiceChannelEffectData, } from './rawDataTypes'; //#region Classes @@ -2811,7 +2812,7 @@ export class VoiceChannel extends TextBasedChannelMixin(BaseGuildVoiceChannel, [ } export class VoiceChannelEffect { - private constructor(data: unknown, guild: Guild); + private constructor(data: VoiceChannelEffectData, guild: Guild); public animationType: AnimationTypes | null; public animationId: number | null; public readonly channel: VoiceChannel | null; @@ -6562,6 +6563,7 @@ export type WSEventType = | 'USER_UPDATE' | 'PRESENCE_UPDATE' | 'TYPING_START' + | 'VOICE_CHANNEL_EFFECT_SEND' | 'VOICE_STATE_UPDATE' | 'VOICE_SERVER_UPDATE' | 'WEBHOOKS_UPDATE' diff --git a/typings/rawDataTypes.d.ts b/typings/rawDataTypes.d.ts index 5b7aa1757cc3..eaf8a6f79b45 100644 --- a/typings/rawDataTypes.d.ts +++ b/typings/rawDataTypes.d.ts @@ -90,7 +90,8 @@ import type { AutoModerationRuleTriggerTypes, InteractionTypes, MessageComponentTypes, - ApplicationRoleConnectionMetadataTypes + ApplicationRoleConnectionMetadataTypes, + AnimationTypes } from './enums'; export type RawActivityData = GatewayActivity; @@ -279,3 +280,12 @@ export interface APIApplicationRoleConnectionMetadata { description: string; description_localizations?: LocalizationMap; } + +export interface VoiceChannelEffectData { + channel_id: Snowflake; + guild_id: Snowflake; + user_id: Snowflake; + emoji?: APIEmoji | null; + animation_type?: AnimationTypes; + animation_id?: number; +} From 0c362266e29b3cf5dd975d40feb5a98dc7d65de9 Mon Sep 17 00:00:00 2001 From: Jaw0r3k Date: Sun, 2 Apr 2023 15:23:37 +0200 Subject: [PATCH 5/5] chore: organise imports --- src/structures/VoiceChannelEffect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/VoiceChannelEffect.js b/src/structures/VoiceChannelEffect.js index 8cbe3c5adf6d..300f3050eb97 100644 --- a/src/structures/VoiceChannelEffect.js +++ b/src/structures/VoiceChannelEffect.js @@ -1,7 +1,7 @@ 'use strict'; -const { AnimationTypes } = require('../util/Constants'); const { Emoji } = require('./Emoji'); +const { AnimationTypes } = require('../util/Constants'); /** * Represents an effect used in a {@link VoiceChannel}.