仅在满足条件时才启动discord.py命令冷却


问题内容

我希望仅在满足函数中的条件时才开始命令之一的冷却,例如:

@bot.command
async def move(ctx, destination):
    destinations=["d1", "d2", "d3"] # List of valid arguments for the command
    if destination in destinations:
        movement(destination) # Function to actually move, not important for the question
        # Start cooldown only here
    else:
        await ctx.send("This is not a valid destination")

这样,如果用户输入错误的目的地,他们将不会因冷却时间而受到惩罚。我该如何实现?

EDIT1:通常会使用discord.py的内置@ commands.cooldown装饰器,这是源代码:

def cooldown(rate, per, type=BucketType.default):
    def decorator(func):
        if isinstance(func, Command):
            func._buckets = CooldownMapping(Cooldown(rate, per, type))
        else:
            func.__commands_cooldown__ = Cooldown(rate, per, type)
        return func
    return decorator

但这适用于整个命令(通常放置在@ bot.command装饰器之后)


问题答案:

可以使用多种方法来制作自己的冷却时间,这里有一个简单的方法可以解决问题。其背后的想法是让机器人“记住”上次有人使用此特定命令的时间,并在允许玩家移动之前对其进行检查。

from datetime import datetime, timedelta

on_cooldown = {} # Dictionary with user IDs as keys and datetime as values
destinations=["d1", "d2", "d3"] # List of valid arguments for the command
move_cooldown = 5 # cooldown of the move command in seconds

@bot.command()
async def move(ctx, destination):

    if destination in destinations:
        author = ctx.author.id

        try:
            # calculate the amount of time since the last (successful) use of the command
            last_move = datetime.now() - on_cooldown[author] 
        except KeyError:
            # the key doesn't exist, the player used the command for the first time
            # or the bot has been shut down since
            last_move = None
            on_cooldown[author] = datetime.now()

        if last_move is None or last_move.seconds > move_cooldown:
            # move(...)
            on_cooldown[author] = datetime.now() # the player successfully moved so we start his cooldown again
            await ctx.send("You moved!")
        else:
            await ctx.send("You're still on cooldown.")

    else:
        await ctx.send("This is not a valid destination")

注意:您可以在@bot.command装饰器后删除括号,也可以不必删除括号。