How do fix this discord bot file to sync cog slash commands on demand or faster?

132 Views Asked by At

I followed the pycord guide regarding building a bot script with cogs, however i think it registers them as global and not guild commands. This is my main.py:

import discord
import interactions
import os
from dotenv import load_dotenv, dotenv_values

# adds path ../secrets/ to ./env
env_path = os.path.join(os.path.dirname(__file__), '..', 'secrets', '.env')
load_dotenv(env_path)
   
# For code review only, remove before production
config = dotenv_values(env_path)
print(config) 

# Define Enviroment variables
BOT_TOKEN = os.getenv("DISCORD_TOKEN")
SERVER_ID = os.getenv("DISCORD_GUILD")
BOT_ID = os.getenv("DISCORD_APPLICATION")

# Define our Bot
bot = discord.Bot()

# Checks if bot is ready
@bot.event
async def on_ready():
    print(f"{bot.user} is ready and online!")
     
# Loads cogs
cogs_list = [
    'greetings',
    'hydrocalc',
]

for cog in cogs_list:
    bot.load_extension(f'cogs.{cog}')

#this might work 
@bot.command(name="sync") 
async def sync(ctx):
    synced = await bot.tree.sync()
    print(f"Synced {len(synced)} command(s).")
    
bot.run(BOT_TOKEN)

And this is an example of one of my cogs

import discord
from discord.ext import commands

class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog

    # appends all functions as a part of the class
    def __init__(self, bot):
        self.bot = bot

    @discord.slash_command(name="hello", description="Greets the messenger") 
    async def hello(self, ctx):
        await ctx.respond('Hello!')
        
    @discord.slash_command(name="goodbye", description="Greets the messenger") 
    async def goodbye(self, ctx):
        await ctx.respond('Goodbye!')

# Set up the cog and update the bot
def setup(bot): 
    bot.add_cog(Greetings(bot)) 

Any help would be greatly appreciated.

I've seen this function:

@bot.command(name="sync") 
async def sync(ctx):
    synced = await bot.tree.sync()
    print(f"Synced {len(synced)} command(s).")

but can't see how tree is defined, and so it doesn't work.

1

There are 1 best solutions below

2
On

There are a few common mistakes.

  • first up I would import from discord.ext import commands and define my bot as bot = commands.bot(command_prefix="!",intents=discord.Intents.all())

  • and the second mistake is that you did not pass in any intents to the bot. (command_prefix is not needed only if you want to create normal commands, for you it is needed for the sync command)

  • Third is discord.py is an asynchronous library so when you do something with a function you need to add await to the result it returns so the program wont stop completely when you execute a function

Code:

Main.py:

@bot.command()
async def load(ctx:commands.Context):
    i = 0
    for filename in os.listdir('PATH/TO/cogs'):
        if filename.endswith('.py'):
            i += 1
            cog_name = filename[:-3]
            await bot.load_extension(f'cogs.{cog_name}')
    print(f"Loaded {i} cogs")

This will load all cogs at once, but based on this code you can create one where you can load them one by one with a command. For cogs you can also do await bot.reload_extension and bot.unload_extension first will refresh the cog so you don't have to restart the bot when you implement something, second will unload the cog so you wont be able to use the code in it until you load it back.

Cog.py:

import discord
from discord.ext import commands
from discord import app_commands

class Slash(commands.Cog):
    def __init__(self,bot):
        self.bot = bot
    
    @app_commands.command(name="test")
    async def test(self, interaction:discord.Interaction):
        await interaction.response.send_message('test successful')
    
    @commands.hybrid_command(name='asd', with_app_command=True)
    async def asd(self, ctx: commands.Context):
        await ctx.reply("Test was good!")

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

Here I provided a simple example of two kinds of slash commands in a cog. (hybrid_command can be used with a prefix too) (@discord.slash_command was an option in the older versions too but it was removed later) The mistake in your original code other then using a removed decorator (@discord.slash_command) was that you did not make the setup command asynchronous.

If you have any questions feel free to ask. (English isn't my native, don't blame me :D)