当我等待“reaction_remove”时,Bot.wait_for() 不能正常工作

Posted

技术标签:

【中文标题】当我等待“reaction_remove”时,Bot.wait_for() 不能正常工作【英文标题】:Bot.wait_for() doesn't work very properly when I wait it for "reaction_remove" 【发布时间】:2021-03-17 23:18:30 【问题描述】:

预期的输出和我的代码是什么:

我的机器人应该发送一条消息,然后检查是否有人用 :tada: 对该消息作出反应,如果有人这样做了,它应该给那个用户一个特定的角色,这部分工作正常,但我也希望它检查用户是否删除他们的反应,如果是,则删除该角色。 我把角色移除器和角色添加器放到自己的async协程函数中,

        # Listening for reactions
        await participation_message.add_reaction("????")
        reaction_check = lambda reaction, user: str(reaction.emoji) == "????" and reaction.message.id == participation_message.id # In case you might be wondering, participation_message is a discord.Message that I send before this code block

        async def remove_participants_loop():
            while True:
                try:
                    reaction, user = await self.client.wait_for('reaction_remove', timeout=60, check=reaction_check)
                    try:
                        await user.remove_roles(participant_role)
                    except Exception as e:
                        console_log("Error in removing participant role from user: ".format(e), "white", "on_red")
                except TimeoutError:
                    break

        async def add_participants_loop(timeout=delete_after*60):
            while True:
                try:
                    reaction, user = await self.client.wait_for('reaction_add', timeout=60, check=reaction_check)
                    try:
                        await user.add_roles(participant_role)
                    except Exception as e:
                        console_log("Error in adding participant role to user: ".format(e), "white", "on_red")
                except TimeoutError:
                    break

我把它们放到它们自己的协程中,因为我需要它们都异步运行,为此我现在这样做了

        asyncio.create_task(add_participants_loop())
        asyncio.create_task(remove_participants_loop())

问题:

这适用于add_participants_loop()但不适用于remove_participants_loop(),我尝试使用断点调试它,发现remove_participants_loop确实运行正常,但是当它等待"reaction_remove"时,当我删除我的反应时它没有检测到它,并继续等待并最终引发asyncio.TimoutError

我试过了:

阅读文档,函数wait_for() 的documentation 声明,“event (str) – 事件名称,类似于事件引用,但没有 on_ 前缀,等待。”,和事件参考表明正确的术语确实是“reaction_remove”而不是其他任何东西 检查拼写错误 确保 Bot.Intent.reactions == True 确保我拥有最新版本的 discord.py 模块 如上所述使用断点进行调试。 考虑到我的理智,毕竟这个问题只是我错过的一些愚蠢的错字。 确保我的机器人在不和谐中拥有其角色所需的所有权限

【问题讨论】:

我能想到的唯一问题是支票。你调试过str(reaction.emoji) == "????" 吗? 【参考方案1】:

我认为wait_for 只能处理“message”和“reaction_add”,不能处理“reaction_remove”。

【讨论】:

【参考方案2】:

在discord.py Github Repository 上的issue 中声明:

这需要消息缓存并且消息存在。它还需要成员缓存,因为 discord 不向此事件提供成员数据。

它还指出

如果您想获得不受此限制的事件,请使用on_raw_reaction_remove 事件。

因此,reaction_remove 事件由于缺少缓存而不起作用。因此这里应该使用raw_reaction_remove,因为它不受此限制的约束,它返回一个有效负载discord.RawReactionActionEvent 对象,而不是标准的用户和反应,然后可以使用它来获取用户和反应. 因此,现在的 lambda 检查将类似于:

lambda payload: str(payload.emoji) == "?" and payload.message_id == participation_message.id

把它放在 wait_for 协程中,

payload = await self.client.wait_for('raw_reaction_remove', timeout=timeout, check=lambda payload: str(payload.emoji) == "?" and payload.message_id == participation_message.id)

# And then the User/Member who removed the Reaction can 
# Be obtained by the user_id in the returned payload
user = self.client.get_guild(payload.guild_id).get_member(payload.user_id)

总结:

As documented this requires the message cache and for the message to be there. It also requires member cache since discord does not provide this event with member data. If you want to get event without this limitation then use the raw_reaction_remove event.

【讨论】:

以上是关于当我等待“reaction_remove”时,Bot.wait_for() 不能正常工作的主要内容,如果未能解决你的问题,请参考以下文章

实体框架无效的列名

当我需要等待事件时如何使方法异步

当我使用 for 循环时,为啥我的代码没有在 forEach 中等待? [复制]

当我的应用程序需要等待用户点击链接时,如何防止 "java.IOException.HTTP1.1 header parser received no bytes"?当我需要等待用

当我从等待移动到 Promise.all 时,TypeScript 函数返回类型错误

JS异步/等待的CORS错误,但当我将URL直接粘贴到浏览器时没有[重复]