Skip to content

Discord.py Features and Functionalities

Jace Manshadi edited this page Jul 10, 2024 · 10 revisions

Loading Commands

To start off, there is 2 different kinds of discord bot commands. text commands and slash commands

Text Commands

text commands mean command that is called with a prefix [or a character]. With the WALL_E command, this is a . [aka dot commands]. The prefix is determined by the parameter command_prefix this line

super().__init__(command_prefix='.', intents=intents, help_command=EmbedHelpCommand())

located here

When loading a text command, the text command is loaded into the discord.py framework only. Only your local discord.py that is running your bot knows what text commands you have loaded into it and subsequently are available in any discord guilds your bot is plugged into. None of the other running bots on the same guilds know what commands you have personally loaded, even if they are using the same Bot application's API token.

With a text commands, how they are loaded is like this:

  1. When you start up the bot, all the cogs [for example the class Misc in wall_e/extensions/misc.py] are loaded into the bot via this blob of code and this blob of code where extension is the python file wall_e/extensions/misc.py and cog is the class Misc itself. Furthermore, the text commands have this @commands.command annotation and discord.py picks up on that when scanning the cog and as a result, it loads the text command.
  2. when the bot is connected to the discord servers, all messages on all guilds that it is connected to [assuming it is given access to them] are received by the discord.py framework. What the discord.py framework then does, is it checks each message it receives from the guild and sees if it matches a loaded text command. For example sake, if you type in .hello, that will be parsed by the framework because it begins with . but because there is no command hello, that will end up going throwing an error of commands.errors.CommandNotFound which is just ignored here
  3. So finally, let's say that .poll is invoked, your locally loaded discord.py framework recognizes it as a legit command so it tries to invoke the command. Now this might result in other errors, such as permissions missing [if the command is restricted to certain users] or arguments not being correct [if user called it wrong]. But that's basically how a text command works.

Slash Commands

As opposed to text commands where only your local bot has any idea what commands it has made available, slash commands are different, they have a CommandTree concept. How this shows itself is in 2 ways:

CommandTree in Debug Mode

Global Commands

When a slash command is synced to the global CommandTree [which will be explained below how that happens], that command is available in your personal DM with that bot. It's not guaranteed to act the same in the DM as it would in the guild since some commands may have guild specific code but it can at least be detected and invoked from your personal DM with the bot.

Guild Commands

In addition, there is a guild command. A guild command is a command that a bot has synced with a specific guild's CommandTree, it is not available on any other guild nor is it available in your personal DM with that bot. All of WALL_e's slash commands are guild command synced specifically to the CSSS Discord Guild, this line is what is making all the slash commands into guild commands.

Example of Synced Guild Commands

I made the decision to sync just to the guild and not also do global because I didn't have the time or patience to make sure all the commands are global compatible, meaning they can be invoked in DMs. Also, there was really no demand for that.

With both guild and global commands, the discord server is aware of those slash commands, just in different contexts. you can test to see which commands are registered by doing / and the menu that comes up shows what slash commands are registered.

How to sync

With syncing an application command, there are 2 steps:

  1. Loading the command into the bot itself.
  2. registering loaded command with discord

How WALL_E does it

  1. override the default add_cog command so that the guild_id is added in one centralized place rather than having to specify it in each class
  2. sync the locally created CommandTree to a specific discord guild

How to sync an application command to just global

in your cog class

async def setup(bot):
    await bot.add_cog(Misc())

and have a text command that executes

await bot.tree.sync()

that you can run once the bot is up

How to sync an application command to just a guild

in your cog class

async def setup(bot):
    await bot.add_cog(Misc(guild = discord.Object(id=<guild_id>)))

and have a text command that executes

await bot.tree.sync(guild = discord.Object(id=<guild_id>))

that you can run once the bot is up

How to sync an application command to both

in your cog class

async def setup(bot):
    await bot.add_cog(Misc())

and have a text command that executes

bot.tree.copy_global_to(guild=<GUILD_ID>)
await bot.tree.sync()
await bot.tree.sync(guild = discord.Object(id=<guild_id>))

that you can run once the bot is up

Clone this wiki locally