SDG8
SDG8

Reputation: 79

How to make a cooldown system with discord.py?

Let's say I have two commands...

Now when I type hi 1 it should not respond to me when I type hi 2. Something like a shared cooldown system!

How can I do that?

I am currently using this:

@commands.cooldown(1, 5, commands.BucketType.user)

Which allows me to use the multiple commands without stopping for cooldown on a previous command.

Upvotes: 1

Views: 1633

Answers (1)

Minion3665
Minion3665

Reputation: 964

You could use a custom check to ensure that the commands aren't used while they're on cooldown. ./q63262849/cooldowns.py

import datetime
from discord.ext import commands

on_cooldown = {}  # A dictionary mapping user IDs to cooldown ends


def cooldown(seconds):
    def predicate(context):
        if (cooldown_end := on_cooldown.get(context.author.id)) is None or cooldown_end < datetime.datetime.now():  # If there's no cooldown or it's over
            if context.valid and context.invoked_with in (*context.command.aliases, context.command.name):  # If the command is being run as itself (not by help, which runs checks and would end up creating more cooldowns if this didn't exist)
                on_cooldown[context.author.id] = datetime.datetime.now() + datetime.timedelta(seconds=seconds)  # Add the datetime of the cooldown's end to the dictionary
            return True  # And allow the command to run
        else:
            raise commands.CommandOnCooldown(commands.BucketType.user, (cooldown_end - datetime.datetime.now()).seconds)  # Otherwise, raise the cooldown error to say the command is on cooldown

    return commands.check(predicate)

This can then be imported

./main.py

from q63262849 import cooldowns

and used as a decorator for commands

./main.py

@bot.command()
@cooldowns.cooldown(10)
async def cooldown1(ctx):
    await ctx.send("Ran cooldown 1")


@bot.command()
@cooldowns.cooldown(20)
async def cooldown2(ctx):
    await ctx.send("Ran cooldown 2")

It is notable that this approach still has some issues, in particular if another later check fails this check will still put the command on cooldown, however these could be solved by putting this check such that it will run after all the other checks.

Upvotes: 2

Related Questions