Skip to content

Commit 9ca8ebe

Browse files
authored
New usernames system (#221)
* Add global_name to User after new usernames system + Add User#display_name + Change User#distinct to use discriminator or not, depend to the context (Maybe need change method later, next API versions may remove the discriminator field) + Change Discordrb::API::User#default_avatar & User#avatar_url to use old method to calculate index or not, depend to legacy or not (Maybe need change method later, next API versions may remove the discriminator field) + Change Member#display_name to select global_name before username, but after server nickname + Change Webhook#avatar_url to use new method to calculate index (After testing the webhook creation, the ID already seems to be used for the default avatar instead of the discriminator at 0000) * Modification to allow to determine if User is a Webhook + Without relying on a 0000 discrimator, since it is very likely that this field will disappear completely, sooner or later * Add missing flag + As I saw that the 'ACTIVE_DEVELOPER' flag was missing in the documentation, I added it in the process. * Rubocop friendly * Addition of missing cache edit
1 parent b029e52 commit 9ca8ebe

File tree

6 files changed

+64
-23
lines changed

6 files changed

+64
-23
lines changed

lib/discordrb/api/user.rb

+8-3
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,14 @@ def change_status_setting(token, status)
132132
)
133133
end
134134

135-
# Returns one of the "default" discord avatars from the CDN given a discriminator
136-
def default_avatar(discrim = 0)
137-
index = discrim.to_i % 5
135+
# Returns one of the "default" discord avatars from the CDN given a discriminator or id since new usernames
136+
# TODO: Maybe change this method again after discriminator removal ?
137+
def default_avatar(discrim_id = 0, legacy: false)
138+
index = if legacy
139+
discrim_id.to_i % 5
140+
else
141+
(discrim_id.to_i >> 22) % 5
142+
end
138143
"#{Discordrb::API.cdn_url}/embed/avatars/#{index}.png"
139144
end
140145

lib/discordrb/bot.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -946,10 +946,16 @@ def update_presence(data)
946946

947947
username = data['user']['username']
948948
if username && !member_is_new # Don't set the username for newly-cached members
949-
debug "Implicitly updating presence-obtained information for member #{user_id}"
949+
debug "Implicitly updating presence-obtained information username for member #{user_id}"
950950
member.update_username(username)
951951
end
952952

953+
global_name = data['user']['global_name']
954+
if global_name && !member_is_new # Don't set the global_name for newly-cached members
955+
debug "Implicitly updating presence-obtained information global_name for member #{user_id}"
956+
member.update_global_name(global_name)
957+
end
958+
953959
member.update_presence(data)
954960

955961
member.avatar_id = data['user']['avatar'] if data['user']['avatar']
@@ -1088,6 +1094,7 @@ def update_guild_member(data)
10881094
member = server.member(data['user']['id'].to_i)
10891095
member.update_roles(data['roles'])
10901096
member.update_nick(data['nick'])
1097+
member.update_global_name(data['user']['global_name']) if data['user']['global_name']
10911098
member.update_boosting_since(data['premium_since'])
10921099
member.update_communication_disabled_until(data['communication_disabled_until'])
10931100
end

lib/discordrb/data/member.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,9 @@ def set_nick(nick, reason = nil)
289289

290290
alias_method :set_nickname, :set_nick
291291

292-
# @return [String] the name the user displays as (nickname if they have one, username otherwise)
292+
# @return [String] the name the user displays as (nickname if they have one, global_name if they have one, username otherwise)
293293
def display_name
294-
nickname || username
294+
nickname || global_name || username
295295
end
296296

297297
# Update this member's roles

lib/discordrb/data/message.rb

+5-7
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ class Message
7373
# @return [Array<Component>]
7474
attr_reader :components
7575

76-
# The discriminator that webhook user accounts have.
77-
ZERO_DISCRIM = '0000'
78-
7976
# @!visibility private
8077
def initialize(data, bot)
8178
@bot = bot
@@ -92,12 +89,14 @@ def initialize(data, bot)
9289

9390
@server = @channel.server
9491

92+
@webhook_id = data['webhook_id']&.to_i
93+
9594
@author = if data['author']
96-
if data['author']['discriminator'] == ZERO_DISCRIM
95+
if @webhook_id
9796
# This is a webhook user! It would be pointless to try to resolve a member here, so we just create
9897
# a User and return that instead.
9998
Discordrb::LOGGER.debug("Webhook user: #{data['author']['id']}")
100-
User.new(data['author'], @bot)
99+
User.new(data['author'].merge({ '_webhook' => true }), @bot)
101100
elsif @channel.private?
102101
# Turn the message user into a recipient - we can't use the channel recipient
103102
# directly because the bot may also send messages to the channel
@@ -107,6 +106,7 @@ def initialize(data, bot)
107106

108107
if member
109108
member.update_data(data['member']) if data['member']
109+
member.update_global_name(data['author']['global_name']) if data['author']['global_name']
110110
else
111111
Discordrb::LOGGER.debug("Member with ID #{data['author']['id']} not cached (possibly left the server).")
112112
member = if data['member']
@@ -121,8 +121,6 @@ def initialize(data, bot)
121121
end
122122
end
123123

124-
@webhook_id = data['webhook_id'].to_i if data['webhook_id']
125-
126124
@timestamp = Time.parse(data['timestamp']) if data['timestamp']
127125
@edited_timestamp = data['edited_timestamp'].nil? ? nil : Time.parse(data['edited_timestamp'])
128126
@edited = !@edited_timestamp.nil?

lib/discordrb/data/user.rb

+40-9
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ module UserAttributes
1818
verified_bot: 1 << 16,
1919
verified_developer: 1 << 17,
2020
certified_moderator: 1 << 18,
21-
bot_http_interactions: 1 << 19
21+
bot_http_interactions: 1 << 19,
22+
active_developer: 1 << 22
2223
}.freeze
2324
# rubocop:enable Naming/VariableNumber
2425

2526
# @return [String] this user's username
2627
attr_reader :username
2728
alias_method :name, :username
2829

30+
# @return [String, nil] this user's global name
31+
attr_reader :global_name
32+
2933
# @return [String] this user's discriminator which is used internally to identify users with identical usernames.
3034
attr_reader :discriminator
3135
alias_method :discrim, :discriminator
@@ -36,10 +40,21 @@ module UserAttributes
3640
attr_reader :bot_account
3741
alias_method :bot_account?, :bot_account
3842

43+
# @return [true, false] whether this is fake user for a webhook message
44+
attr_reader :webhook_account
45+
alias_method :webhook_account?, :webhook_account
46+
alias_method :webhook?, :webhook_account
47+
3948
# @return [String] the ID of this user's current avatar, can be used to generate an avatar URL.
4049
# @see #avatar_url
4150
attr_accessor :avatar_id
4251

52+
# Utility function to get Discord's display name of a user not in server
53+
# @return [String] the name the user displays as (global_name if they have one, username otherwise)
54+
def display_name
55+
global_name || username
56+
end
57+
4358
# Utility function to mention users in messages
4459
# @return [String] the mention code in the form of <@id>
4560
def mention
@@ -48,15 +63,25 @@ def mention
4863

4964
# Utility function to get Discord's distinct representation of a user, i.e. username + discriminator
5065
# @return [String] distinct representation of user
66+
# TODO: Maybe change this method again after discriminator removal ?
5167
def distinct
52-
"#{@username}##{@discriminator}"
68+
if @discriminator && @discriminator != '0'
69+
"#{@username}##{@discriminator}"
70+
else
71+
@username.to_s
72+
end
5373
end
5474

5575
# Utility function to get a user's avatar URL.
5676
# @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the user has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this. Will always be PNG for default avatars.
5777
# @return [String] the URL to the avatar image.
78+
# TODO: Maybe change this method again after discriminator removal ?
5879
def avatar_url(format = nil)
59-
return API::User.default_avatar(@discriminator) unless @avatar_id
80+
unless @avatar_id
81+
return API::User.default_avatar(@discriminator, legacy: true) if @discriminator && @discriminator != '0'
82+
83+
return API::User.default_avatar(@id)
84+
end
6085

6186
API::User.avatar_url(@id, @avatar_id, format)
6287
end
@@ -91,6 +116,7 @@ def initialize(data, bot)
91116
@bot = bot
92117

93118
@username = data['username']
119+
@global_name = data['global_name']
94120
@id = data['id'].to_i
95121
@discriminator = data['discriminator']
96122
@avatar_id = data['avatar']
@@ -101,6 +127,9 @@ def initialize(data, bot)
101127
@bot_account = false
102128
@bot_account = true if data['bot']
103129

130+
@webhook_account = false
131+
@webhook_account = true if data['_webhook']
132+
104133
@status = :offline
105134
@client_status = process_client_status(data['client_status'])
106135
end
@@ -138,13 +167,20 @@ def send_file(file, caption = nil, filename: nil, spoiler: nil)
138167
pm.send_file(file, caption: caption, filename: filename, spoiler: spoiler)
139168
end
140169

141-
# Set the user's name
170+
# Set the user's username
142171
# @note for internal use only
143172
# @!visibility private
144173
def update_username(username)
145174
@username = username
146175
end
147176

177+
# Set the user's global_name
178+
# @note For internal use only.
179+
# @!visibility private
180+
def update_global_name(global_name)
181+
@global_name = global_name
182+
end
183+
148184
# Set the user's presence data
149185
# @note for internal use only
150186
# @!visibility private
@@ -183,11 +219,6 @@ def current_bot?
183219
@bot.profile.id == @id
184220
end
185221

186-
# @return [true, false] whether this user is a fake user for a webhook message
187-
def webhook?
188-
@discriminator == Message::ZERO_DISCRIM
189-
end
190-
191222
# @!visibility private
192223
def process_client_status(client_status)
193224
(client_status || {}).to_h { |k, v| [k.to_sym, v.to_sym] }

lib/discordrb/data/webhook.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, buil
192192
# Utility function to get a webhook's avatar URL.
193193
# @return [String] the URL to the avatar image
194194
def avatar_url
195-
return API::User.default_avatar unless @avatar
195+
return API::User.default_avatar(@id) unless @avatar
196196

197197
API::User.avatar_url(@id, @avatar)
198198
end

0 commit comments

Comments
 (0)