diff --git a/packages/discord.js/src/structures/GuildMember.js b/packages/discord.js/src/structures/GuildMember.js index b1f1b5283..4ecf019a0 100644 --- a/packages/discord.js/src/structures/GuildMember.js +++ b/packages/discord.js/src/structures/GuildMember.js @@ -122,6 +122,20 @@ class GuildMember extends Base { } else { this.flags ??= new GuildMemberFlagsBitField().freeze(); } + + if (data.avatar_decoration_data) { + /** + * The member avatar decoration's data + * + * @type {?AvatarDecorationData} + */ + this.avatarDecorationData = { + asset: data.avatar_decoration_data.asset, + skuId: data.avatar_decoration_data.sku_id, + }; + } else { + this.avatarDecorationData = null; + } } _clone() { @@ -166,6 +180,15 @@ class GuildMember extends Base { return this.avatar && this.client.rest.cdn.guildMemberAvatar(this.guild.id, this.id, this.avatar, options); } + /** + * A link to the member's avatar decoration. + * + * @returns {?string} + */ + avatarDecorationURL() { + return this.avatarDecorationData ? this.client.rest.cdn.avatarDecoration(this.avatarDecorationData.asset) : null; + } + /** * A link to the member's banner. * @param {ImageURLOptions} [options={}] Options for the banner URL @@ -195,6 +218,16 @@ class GuildMember extends Base { return this.bannerURL(options) ?? this.user.bannerURL(options); } + /** + * A link to the member's guild avatar decoration if they have one. + * Otherwise, a link to their {@link User#avatarDecorationURL} will be returned. + * + * @returns {?string} + */ + displayAvatarDecorationURL() { + return this.avatarDecorationURL() ?? this.user.avatarDecorationURL(); + } + /** * The time this member joined the guild * @type {?Date} @@ -499,7 +532,10 @@ class GuildMember extends Base { this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp && this.flags.bitfield === member.flags.bitfield && (this._roles === member._roles || - (this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i]))) + (this._roles.length === member._roles.length && + this._roles.every((role, index) => role === member._roles[index]))) && + this.avatarDecorationData?.asset === member.avatarDecorationData?.asset && + this.avatarDecorationData?.skuId === member.avatarDecorationData?.skuId ); } @@ -525,6 +561,7 @@ class GuildMember extends Base { json.bannerURL = this.bannerURL(); json.displayAvatarURL = this.displayAvatarURL(); json.displayBannerURL = this.displayBannerURL(); + json.avatarDecorationURL = this.avatarDecorationURL(); return json; } } diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index cd6d4e045..20b4d768d 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -1799,6 +1799,7 @@ export class GuildMember extends Base { private constructor(client: Client, data: RawGuildMemberData, guild: Guild); private _roles: Snowflake[]; public avatar: string | null; + public avatarDecorationData: AvatarDecorationData | null; public banner: string | null; public get bannable(): boolean; public get dmChannel(): DMChannel | null; @@ -1826,6 +1827,7 @@ export class GuildMember extends Base { public user: User; public get voice(): VoiceState; public avatarURL(options?: ImageURLOptions): string | null; + public avatarDecorationURL(): string | null; public bannerURL(options?: ImageURLOptions): string | null; public ban(options?: BanOptions): Promise; public disableCommunicationUntil(timeout: DateResolvable | null, reason?: string): Promise; @@ -1835,6 +1837,7 @@ export class GuildMember extends Base { public deleteDM(): Promise; public displayAvatarURL(options?: ImageURLOptions): string; public displayBannerURL(options?: ImageURLOptions): string | null; + public displayAvatarDecorationURL(): string | null; public edit(options: GuildMemberEditOptions): Promise; public isCommunicationDisabled(): this is GuildMember & { communicationDisabledUntilTimestamp: number;