@@ -217,37 +217,82 @@ async def register_commands(self) -> None:
217
217
218
218
Registers all commands that have been added through :meth:`.add_application_command`.
219
219
This method cleans up all commands over the API and should sync them with the internal cache of commands.
220
+ This will only be rolled out to Discord if :meth:`.http.get_global_commands` has certain keys that differ from :data:`.pending_application_commands`
220
221
221
222
By default, this coroutine is called inside the :func:`.on_connect`
222
223
event. If you choose to override the :func:`.on_connect` event, then
223
224
you should invoke this coroutine as well.
224
225
225
226
.. versionadded:: 2.0
226
227
"""
227
- commands = []
228
+ commands_to_bulk = []
229
+
230
+ needs_bulk = False
228
231
229
232
# Global Command Permissions
230
233
global_permissions : List = []
231
234
232
235
registered_commands = await self .http .get_global_commands (self .user .id )
233
- for command in [
234
- cmd for cmd in self .pending_application_commands if cmd .guild_ids is None
235
- ]:
236
- as_dict = command .to_dict ()
237
- if len (registered_commands ) > 0 :
238
- matches = [
239
- x
240
- for x in registered_commands
241
- if x ["name" ] == command .name and x ["type" ] == command .type
242
- ]
243
- # TODO: rewrite this, it seems inefficient
244
- if matches :
245
- as_dict ["id" ] = matches [0 ]["id" ]
246
- commands .append (as_dict )
247
-
248
- cmds = await self .http .bulk_upsert_global_commands (self .user .id , commands )
249
-
250
- for i in cmds :
236
+ # 'Your app cannot have two global commands with the same name. Your app cannot have two guild commands within the same name on the same guild.'
237
+ # We can therefore safely use the name of the command in our global slash commands as a unique identifier
238
+ registered_commands_dict = {cmd ["name" ]:cmd for cmd in registered_commands }
239
+ global_pending_application_commands_dict = {}
240
+
241
+ if len (registered_commands ) > 0 :
242
+ for command in [
243
+ cmd for cmd in self .pending_application_commands if cmd .guild_ids is None
244
+ ]:
245
+ as_dict = command .to_dict ()
246
+
247
+ global_pending_application_commands_dict [command .name ] = as_dict
248
+ if command .name in registered_commands_dict :
249
+ match = registered_commands_dict [command .name ]
250
+ else :
251
+ match = None
252
+ # TODO: There is probably a far more efficient way of doing this
253
+ # We want to check if the registered global command on Discord servers matches the given global commands
254
+ if match :
255
+ as_dict ["id" ] = match ["id" ]
256
+
257
+ keys_to_check = {"default_permission" : True , "name" : True , "description" : True , "options" : ["type" , "name" , "description" ]}
258
+ for key , more_keys in {
259
+ key :more_keys
260
+ for key , more_keys in keys_to_check .items ()
261
+ if key in as_dict .keys ()
262
+ if key in match .keys ()
263
+ }.items ():
264
+ if key == "options" :
265
+ for i , option_dict in enumerate (as_dict [key ]):
266
+ for key2_change in [
267
+ key2
268
+ for key2 in more_keys
269
+ if key2 in option_dict .keys () and key2 in match [key ][i ].keys ()
270
+ if option_dict [key2 ] != match [key ][i ][key2 ]
271
+ ]:
272
+ print (f"A change in the '{ key2_change } ' property of '{ key } ' in the '{ command .name } ' global command was noticed, will send to Discord to update" )
273
+ needs_bulk = True
274
+ else :
275
+ if as_dict [key ] != match [key ]:
276
+ print (f"A change in the '{ key } ' property of '{ command .name } ' global command was noticed, will send to Discord to update" )
277
+ needs_bulk = True
278
+ else :
279
+ print (f"A pending global command '{ command .name } ' is not registered in Discord servers, will send to Discord to update" )
280
+ needs_bulk = True
281
+
282
+ commands_to_bulk .append (as_dict )
283
+
284
+ if len (registered_commands_dict ) > 0 :
285
+ for name , command in registered_commands_dict .items ():
286
+ if not name in global_pending_application_commands_dict .keys ():
287
+ print (f"A registered global command '{ name } ' is not found in the pending global commands, will send to Discord to update" )
288
+ needs_bulk
289
+
290
+ if needs_bulk :
291
+ commands = await self .http .bulk_upsert_global_commands (self .user .id , commands_to_bulk )
292
+ else :
293
+ commands = registered_commands
294
+
295
+ for i in commands :
251
296
cmd = get (
252
297
self .pending_application_commands ,
253
298
name = i ["name" ],
@@ -275,7 +320,7 @@ async def register_commands(self) -> None:
275
320
276
321
for guild_id , guild_data in update_guild_commands .items ():
277
322
try :
278
- cmds = await self .http .bulk_upsert_guild_commands (
323
+ commands = await self .http .bulk_upsert_guild_commands (
279
324
self .user .id , guild_id , update_guild_commands [guild_id ]
280
325
)
281
326
@@ -287,7 +332,7 @@ async def register_commands(self) -> None:
287
332
print (f"Failed to add command to guild { guild_id } " , file = sys .stderr )
288
333
raise
289
334
else :
290
- for i in cmds :
335
+ for i in commands :
291
336
cmd = find (lambda cmd : cmd .name == i ["name" ] and cmd .type == i ["type" ] and int (i ["guild_id" ]) in cmd .guild_ids , self .pending_application_commands )
292
337
cmd .id = i ["id" ]
293
338
self ._application_commands [cmd .id ] = cmd
0 commit comments