Issue
Expected output and what my code for it is:
My bot is supposed to send a message, and then check if somebody reacted on that message with :tada:, and if someone did, it is supposed to give that user a particular role, that part works fine, but I also want it to check if the user removed their reaction, if yes, then remove the role.
I put the role remover and role adder into their own async
coroutine functions,
# 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
and I put them into their own coroutines, because I need both of them to run asynchronously, and for that I now do
asyncio.create_task(add_participants_loop())
asyncio.create_task(remove_participants_loop())
The problem:
This works for the add_participants_loop()
but doesn't work for the remove_participants_loop()
, I have tried to debug it using breakpoints, and found that the remove_participants_loop
does run properly, but when it waits for "reaction_remove"
, it doesn't detect it when I remove my reaction, and keeps waiting and eventually raises the asyncio.TimoutError
.
I have tried:
- reading the documentation, and the function
wait_for()
's documentation states that, "event (str) – The event name, similar to the event reference, but without the on_ prefix, to wait for.", and the event reference shows that the proper term would indeed be "reaction_remove" and not anything else - Checking for typos
- Making sure that Bot.Intent.reactions == True
- Making sure that I have latest version of discord.py module
- Debugging with breakpoints just as mentioned above.
- Contemplating my sanity that after all this the issue would turn out to be just some dumb typo that i missed.
- Making sure that my bot has all the permissions it needs in its roles in discord
Solution
In an issue on the discord.py Github Repository, it's stated that:
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.
and it also states that
If you want to get event without this limitation then use the
on_raw_reaction_remove
event.
Therefore the reaction_remove
event doesn't work because of absent cache. Hence raw_reaction_remove
should be used here instead, because it isn't bound to this limitation, and it returns a payload discord.RawReactionActionEvent object, instead of the standard User and Reaction, which can then be used to get the User and the Reaction.
Hence the lambda check for that would now be something like:
lambda payload: str(payload.emoji) == "🎉" and payload.message_id == participation_message.id
putting that in the wait_for coroutine,
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)
Summary:
Answered By - Zacky
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.