如何为 discord.py 中的命令设置 double/advanced 冷却时间?

How do I set a double/advanced cooldown for a command in discord.py?

这是一个有基本冷却时间的基本命令:

@client.command()
@commands.cooldown(5, 57600, commands.BucketType.user)
async def ping(ctx)
   await ctx.send("pong")

所以基本上,当用户使用命令的前缀(例如'!k')然后键入“ping”时,机器人将发送“pong!”到聊天。这是一个非常基本的命令,然后是冷却装饰器。来自冷却时间:

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

我们可以看出该命令可以在 57600 秒(16 小时)之间使用 5 次,但是如果我希望命令每 16 小时仅使用 5 次并且每次使用该命令之间还有另一个冷却时间怎么办?让我解释一下...

您每 16 小时可以使用该命令 5 次

但是当你使用该命令时,你必须等待1小时才能再次使用它

这样一来,您将无法在一分钟内立即使用该命令 5 次

把它想象成一棵每小时长一个苹果但每天只长 5 个苹果的树...我怎样才能防止用户立即使用该命令 5 次?谢谢-

Discord.py 不允许每个命令进行多次冷却检查,因此您必须使用自定义冷却处理程序。

class CooldownManager:

    def __init__(self, executions_allowed: int, cooldown_time: float):
        self.state = {}
        self.executions_allowed = executions_allowed
        self.cooldown_time = cooldown_time

    def time_left(self, key) -> float:
        """Attempt to execute. Return 0 if ready, or the number of seconds until you're allowed to execute again."""
        if key not in self.state.keys():
            self.state[key] = []
        if len(self.state[key]) > 0:
            # Clean up executions that have aged away
            # self.state[key] is sorted with the newest first
            for i in range(len(self.state[key])-1, -1, -1):
                if self.state[key][i] + self.cooldown_time < time.time():
                    del self.state[key][i]
            if len(self.state[key]) < self.executions_allowed:
                self.state[key].append(time.time())
                return 0
            next_available_execution = self.state[key][len(self.state)-1] + self.cooldown_time
            return next_available_execution - time.time()
        else:
            self.state[key].append(time.time())
            return 0

    def assert_cooldown(self, data):
        """Run this at the beginning of the command."""
        time_left = self.time_left(data)
        if time_left > 0:
            raise commands.CommandOnCooldown('', retry_after=time_left)


cm1 = CooldownManager(1, 4.0)  # execute once every 4 seconds
cm2 = CooldownManager(3, 120.0)  # execute up to 3x every 2 minutes
@client.command(name='test')
async def multicooldown(ctx):
    # Check both cooldowns. This raises `CommandOnCooldown` just like the vanilla cooldown handler, so you can catch that later in your command error check.
    cm1.assert_cooldown(ctx.author.id)  # This is basically the bucket type. You can use things like ctx.author.id, ctx.guild.id, etc
    cm2.assert_cooldown(ctx.author.id)
    # Do whatever you want here
    await ctx.send('test')