Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support new username system #9634

Merged
merged 10 commits into from
Jul 8, 2023
4 changes: 2 additions & 2 deletions src/structures/GuildMember.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,12 @@ class GuildMember extends Base {
}

/**
* The nickname of this member, or their username if they don't have one
* The nickname of this member, or their user display name if they don't have one
* @type {?string}
* @readonly
*/
get displayName() {
return this.nickname ?? this.user.username;
return this.nickname ?? this.user.displayName;
}

/**
Expand Down
46 changes: 42 additions & 4 deletions src/structures/User.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
'use strict';

const process = require('node:process');
const Base = require('./Base');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { Error } = require('../errors');
const SnowflakeUtil = require('../util/SnowflakeUtil');
const UserFlags = require('../util/UserFlags');
const Util = require('../util/Util');

let tagDeprecationEmitted = false;

/**
* Represents a user on Discord.
Expand Down Expand Up @@ -41,6 +45,16 @@ class User extends Base {
this.username ??= null;
}

if ('global_name' in data) {
/**
* The global name of this user
* @type {?string}
*/
this.globalName = data.global_name;
} else {
this.globalName ??= null;
}

if ('bot' in data) {
/**
* Whether or not the user is a bot
Expand All @@ -53,7 +67,8 @@ class User extends Base {

if ('discriminator' in data) {
/**
* A discriminator based on username for the user
* The discriminator of this user
* <info>`'0'`, or a 4-digit stringified number if they're using the legacy username system</info>
* @type {?string}
*/
this.discriminator = data.discriminator;
Expand Down Expand Up @@ -155,7 +170,8 @@ class User extends Base {
* @readonly
*/
get defaultAvatarURL() {
return this.client.rest.cdn.DefaultAvatar(this.discriminator % 5);
const index = this.discriminator === '0' ? Util.calculateUserDefaultAvatarIndex(this.id) : this.discriminator % 5;
return this.client.rest.cdn.DefaultAvatar(index);
}

/**
Expand Down Expand Up @@ -193,12 +209,32 @@ class User extends Base {
}

/**
* The Discord "tag" (e.g. `hydrabolt#0001`) for this user
* The tag of this user
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
* if they're using the legacy username system</info>
* @type {?string}
* @deprecated Use {@link User#username} instead.
aiko-chan-ai marked this conversation as resolved.
Show resolved Hide resolved
* @readonly
*/
get tag() {
return typeof this.username === 'string' ? `${this.username}#${this.discriminator}` : null;
if (!tagDeprecationEmitted) {
process.emitWarning('User#tag is deprecated. Use User#username instead.', 'DeprecationWarning');
tagDeprecationEmitted = true;
}
return typeof this.username === 'string'
? this.discriminator === '0'
? this.username
: `${this.username}#${this.discriminator}`
: null;
}

/**
* The global name of this user, or their username if they don't have one
* @type {?string}
* @readonly
*/
get displayName() {
return this.globalName ?? this.username;
}

/**
Expand Down Expand Up @@ -240,6 +276,7 @@ class User extends Base {
this.id === user.id &&
this.username === user.username &&
this.discriminator === user.discriminator &&
this.globalName === user.globalName &&
this.avatar === user.avatar &&
this.flags?.bitfield === user.flags?.bitfield &&
this.banner === user.banner &&
Expand All @@ -259,6 +296,7 @@ class User extends Base {
this.id === user.id &&
this.username === user.username &&
this.discriminator === user.discriminator &&
this.globalName === user.global_name &&
this.avatar === user.avatar &&
this.flags?.bitfield === user.public_flags &&
('banner' in user ? this.banner === user.banner : true) &&
Expand Down
2 changes: 1 addition & 1 deletion src/util/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ exports.Endpoints = {
return {
Emoji: (emojiId, format = 'webp') => `${root}/emojis/${emojiId}.${format}`,
Asset: name => `${root}/assets/${name}`,
DefaultAvatar: discriminator => `${root}/embed/avatars/${discriminator}.png`,
DefaultAvatar: index => `${root}/embed/avatars/${index}.png`,
Avatar: (userId, hash, format, size, dynamic = false) => {
if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/avatars/${userId}/${hash}`, { format, size });
Expand Down
9 changes: 9 additions & 0 deletions src/util/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,15 @@ class Util extends null {
emoji_name: defaultReaction.name,
};
}

/**
* Calculates the default avatar index for a given user id.
* @param {Snowflake} userId - The user id to calculate the default avatar index for
* @returns {number}
*/
static calculateUserDefaultAvatarIndex(userId) {
return Number(BigInt(userId) >> 22n) % 6;
}
}

module.exports = Util;
Expand Down
5 changes: 4 additions & 1 deletion typings/index.d.ts
aiko-chan-ai marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2703,13 +2703,16 @@ export class User extends PartialTextBasedChannel(Base) {
public readonly createdAt: Date;
public readonly createdTimestamp: number;
public discriminator: string;
public readonly displayName: string;
public readonly defaultAvatarURL: string;
public readonly dmChannel: DMChannel | null;
public flags: Readonly<UserFlags> | null;
public globalName: string | null;
public readonly hexAccentColor: HexColorString | null | undefined;
public id: Snowflake;
public readonly partial: false;
public system: boolean;
/** @deprecated Use {@link User#username} instead. */
public readonly tag: string;
public username: string;
public avatarURL(options?: ImageURLOptions): string | null;
Expand Down Expand Up @@ -3093,7 +3096,7 @@ export const Constants: {
dynamic: boolean,
): string;
Banner(id: Snowflake, hash: string, format: DynamicImageFormat, size: AllowedImageSize, dynamic: boolean): string;
DefaultAvatar(discriminator: number): string;
DefaultAvatar(index: number): string;
DiscoverySplash(guildId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize): string;
Emoji(emojiId: Snowflake, format: DynamicImageFormat): string;
GDMIcon(channelId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize): string;
Expand Down