运行 仅在用户运行特定命令后才会结束的功能

Run a function which will end only after user runs a certain command

我正在创建一个 Discord 机器人来玩扑克。我有一个函数 wait_for_betting_to_end 定义如下:

def wait_for_betting_to_end():
    while not_all_players_have_bet():
        pass

我在 cog 中有一个命令 poker,其中包含以下代码片段:

@commands.command(name='poker')
async def poker(self, ctx):
    self.game_started = True
    # ...
    await preflop()
    wait_for_betting_to_end()
    # ...

我在 cog:

中有一个 Discord 命令 bet
@commands.command(name='bet')
async def bet(self, ctx, amt):
    if not self.game_started:
        print("You're not playing a game.")
        return
    # does something that would make wait_for_betting_to_end stop

问题是用户在玩扑克时永远无法运行 bet 命令;执行流程永远停留在 wait_for_betting_to_end 中。不播放时,bet 正确显示错误并存在。

我该如何解决这个问题?

您的代码存在的问题是您在 wait_for_betting_to_end() 函数中创建了无限循环。这是一个错误,源于认为 discord.py 使用多线程来获得其异步功能(我可以猜到很多看标签),但事实并非如此。 asyncio 在单个线程中工作,它执行一项任务(如接收消息、处理命令等)并在该任务完成后执行下一个任务,asyncio 的强大之处在于能够暂时 'freeze' 一个没有进展的任务(比如等待响应或只是简单地睡觉)继续下一个任务,并在需要时恢复冻结的任务。 (顺便说一句,我很确定 'freezing' 是完全错误的术语)。您的机器人获得的每个命令都在其自己的任务中处理。你使无限循环永远不会释放扑克任务,所以它阻塞了整个循环。

要解决您的问题,有几种可能性,例如:

而不是无限循环,在你的循环中调用 await asyncio.sleep(0.1) 而不是 pass,这将允许你的机器人在那个时候从 discord 获取消息,从而对用户的响应做出反应.要停止你的 while 循环,你可以使用一个 self.value ,你可以在需要时将其设置为 False (在你的 bet 命令中)(也许为此使用带有游戏的字典之类的东西,因为你可能想要 运行同时进行不同的游戏)。

我并没有真正使用 cog,所以我不能自信地为您提供一个可以如何编写代码的示例(至少不会有遗漏一些可以使用 cog 轻松完成的事情的风险)。但我相信这应该会让你走上正确的道路。