Discord bot is incorrect if several players are trying to get a part at the same time.



  • I'm writing discord bot (discord.py) and I need a function that will add a role to the player immediately (the user can choose the role himself) or in passing the test (which is sent to the LC participant). That's what I wrote:

    @bot.command()
    async def select_faculty(ctx):
        """Функция select_faculty позволяет выбрать сразу или пройти тест для
        определения факультета.
        """
        member = ctx.message.author
        channel_roles = [
            "gryffindor - ученик",
            "slytherin - ученик",
            "hufflepuff - ученик",
            "ravenclaw - ученик",
            "gryffindor - наставник",
            "slytherin - наставник",
            "hufflepuff - наставник",
            "ravenclaw - наставник",
            "ждущие зачисления",
            "ученик",
            "наставник",
        ]
        start_emb = discord.Embed(title="Приветствую тебя, маг!", colour=discord.Colour.orange(),
                                  description="Выбери вариант распределения:")
        who_emb = discord.Embed(title="Для начала выбери кто ты:", colour=discord.Colour.purple())
        select_fac_emb = discord.Embed(title="Выбери факультет:", colour=discord.Colour.red(),
                                       description="Выбери понравившийся тебе факультет.")
        send_fac_menu = ctx.send(embed=select_fac_emb, components=[
            [Button(style=ButtonStyle.green, label="Гриффиндор", emoji=""),
             Button(style=ButtonStyle.blue, label="Слизерин", emoji="")],
            [Button(style=ButtonStyle.red, label="Когтевран", emoji=""),
             Button(style=ButtonStyle.gray, label="Пуффендуй", emoji="")],
            [Button(style=ButtonStyle.blue, label="Пожиратели смерти", emoji="")]
        ])
        answer = await ctx.channel.send(embed=start_emb, components=[[
            Button(style=ButtonStyle.green, label="Выбрать сразу"),
            Button(style=ButtonStyle.blue, label="Пройти тест")]])
        response = await bot.wait_for("button_click")
        await response.edit_origin()
        if response.component.label == "Выбрать сразу":
            for role in [role.name for role in ctx.author.roles]:
                if role != "@everyone" and role.lower() in channel_roles:
                    user_role = discord.utils.get(ctx.message.author.roles, name=role)
                    await member.remove_roles(user_role)
            await ctx.message.delete()
            await answer.delete()
            answer = await ctx.send(embed=who_emb, components=[
                [Button(style=ButtonStyle.green, label="Ученик с жаждой знаний", emoji="‍")],
                [Button(style=ButtonStyle.blue, label="Мудрый наставник", emoji="")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Ученик с жаждой знаний":
                await send_fac_menu
                response = await bot.wait_for("button_click")
                await response.edit_origin()
                if response.component.label == "Гриффиндор":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["apprentice"]["gryff"]))
                elif response.component.label == "Слизерин":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["apprentice"]["slyth"]))
                elif response.component.label == "Когтевран":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["apprentice"]["raven"]))
                elif response.component.label == "Пуффендуй":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["apprentice"]["huff"]))
                elif response.component.label == "Пожиратели смерти":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["apprentice"]["death"]))
                await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["apprentice"]["apprentice"]))
                await answer.delete()
            elif response.component.label == "Мудрый наставник":
                await send_fac_menu
                response = await bot.wait_for("button_click")
                await response.edit_origin()
                if response.component.label == "Гриффиндор":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["mentor"]["gryff"]))
                elif response.component.label == "Слизерин":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["mentor"]["slyth"]))
                elif response.component.label == "Когтевран":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["mentor"]["raven"]))
                elif response.component.label == "Пуффендуй":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["mentor"]["huff"]))
                elif response.component.label == "Пожиратели смерти":
                    await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["mentor"]["death"]))
                await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles["mentor"]["mentor"]))
                await answer.delete()
        elif response.component.label == "Пройти тест":
            faculties = {
                "gryff": 0,
                "slyth": 0,
                "huff": 0,
                "raven": 0
            }
            who = ""
            faculty = ""
            question1_emb = discord.Embed(title="Давай пройдём небольшой тест.", colour=discord.Colour.green(),
                                          description="Первый вопрос - какой ты?:")
            question2_emb = discord.Embed(title="Второй вопрос:", colour=discord.Colour.orange(),
                                          description="Какое животное тебе нравится больше всего?")
            question3_emb = discord.Embed(title="Третий вопрос:", colour=discord.Colour.purple(),
                                          description="Какая стихия нравится тебе больше всего?")
            question4_emb = discord.Embed(title="Четвёртый вопрос:", colour=discord.Colour.blue(),
                                          description="Какие комбинации цветов нравятся тебе больше всего?")
            question5_emb = discord.Embed(title="Пятый вопрос:", colour=discord.Colour.red(),
                                          description="Какое привидение из Хогвартса нравится тебе больше всего?")
            await ctx.message.delete()
            await answer.delete()
            answer = await member.send(embed=who_emb, components=[
                [Button(style=ButtonStyle.green, label="Ученик с жаждой знаний", emoji="‍")],
                [Button(style=ButtonStyle.blue, label="Мудрый наставник", emoji="")],
                [Button(style=ButtonStyle.red, label="Министр магии", emoji="‍⚖️")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Ученик с жаждой знаний":
                who = "apprentice"
            elif response.component.label == "Мудрый наставник":
                who = "mentor"
            await answer.delete()
            answer = await member.send(embed=question1_emb, components=[
                [Button(style=ButtonStyle.red, label="Храбрый"),
                 Button(style=ButtonStyle.green, label="Хитрый")],
                [Button(style=ButtonStyle.gray, label="Упорный"),
                 Button(style=ButtonStyle.blue, label="Мудрый")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Храбрый":
                faculties["gryff"] += 1
            elif response.component.label == "Хитрый":
                faculties["slyth"] += 1
            elif response.component.label == "Упорный":
                faculties["huff"] += 1
            elif response.component.label == "Мудрый":
                faculties["raven"] += 1
            await answer.delete()
            answer = await member.send(embed=question2_emb, components=[
                [Button(style=ButtonStyle.red, label="Лев"),
                 Button(style=ButtonStyle.green, label="Змея"),
                 Button(style=ButtonStyle.gray, label="Барсук"),
                 Button(style=ButtonStyle.blue, label="Орёл")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Лев":
                faculties["gryff"] += 1
            elif response.component.label == "Змея":
                faculties["slyth"] += 1
            elif response.component.label == "Барсук":
                faculties["huff"] += 1
            elif response.component.label == "Орёл":
                faculties["raven"] += 1
            await answer.delete()
            answer = await member.send(embed=question3_emb, components=[
                [Button(style=ButtonStyle.red, label="Огонь"),
                 Button(style=ButtonStyle.green, label="Вода"),
                 Button(style=ButtonStyle.gray, label="Земля"),
                 Button(style=ButtonStyle.blue, label="Воздух")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Огонь":
                faculties["gryff"] += 1
            elif response.component.label == "Вода":
                faculties["slyth"] += 1
            elif response.component.label == "Земля":
                faculties["huff"] += 1
            elif response.component.label == "Воздух":
                faculties["raven"] += 1
            await answer.delete()
            answer = await member.send(embed=question4_emb, components=[
                [Button(style=ButtonStyle.red, label="Красный и жёлтый"),
                 Button(style=ButtonStyle.green, label="Зелёный и серебрянный")],
                [Button(style=ButtonStyle.gray, label="Жёлтый и чёрный"),
                 Button(style=ButtonStyle.blue, label="Синий и бронзовый")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Красный и жёлтый":
                faculties["gryff"] += 1
            elif response.component.label == "Зелёный и серебрянный":
                faculties["slyth"] += 1
            elif response.component.label == "Жёлтый и чёрный":
                faculties["huff"] += 1
            elif response.component.label == "Синий и бронзовый":
                faculties["raven"] += 1
            await answer.delete()
            answer = await member.send(embed=question5_emb, components=[
                [Button(style=ButtonStyle.red, label="Почти Безголовый Ник"),
                 Button(style=ButtonStyle.green, label="Кровавый Барон")],
                [Button(style=ButtonStyle.gray, label="Толстый Монах"),
                 Button(style=ButtonStyle.blue, label="Серая Дама")]
            ])
            response = await bot.wait_for("button_click")
            await response.edit_origin()
            if response.component.label == "Почти Безголовый Ник":
                faculties["gryff"] += 1
            elif response.component.label == "Кровавый Барон":
                faculties["slyth"] += 1
            elif response.component.label == "Толстый Монах":
                faculties["huff"] += 1
            elif response.component.label == "Серая Дама":
                faculties["raven"] += 1
            await answer.delete()
            for k, v in faculties.items():
                if v == max(faculties.values()):
                    faculty = k
            for role in [role.name for role in ctx.author.roles]:
                if role != "@everyone" and role.lower() in channel_roles:
                    user_role = discord.utils.get(ctx.message.author.roles, name=role)
                    await member.remove_roles(user_role)
            emb = discord.Embed(title=f"Вы зачислены в {faculty}!", colour=discord.Colour.green())
            await member.send(embed=emb)
            await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles[who][faculty]))
            await member.add_roles(discord.utils.get(ctx.channel.guild.roles, id=roles[who][who]))
    

    But there's one problem - if the role is chosen by a few players, the bot starts to work in an inadequate way: the test uses the answers of other users to add a role to you when the participant presses the button, he gets a mistake of interaction, and the bot makes this mistake:

    RuntimeWarning: Enable tracemalloc to get the object allocation traceback
    Ignoring exception in command select_faculty:
    Traceback (most recent call last):
      File "C:\Users\belog\hat_dispenser\venv\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
        ret = await coro(*args, **kwargs)
      File "C:\Users\belog\hat_dispenser\main.py", line 226, in select_faculty
        await response.edit_origin()
      File "C:\Users\belog\hat_dispenser\venv\lib\site-packages\discord_components\interaction.py", line 244, in edit_origin
        await self.defer(edit_origin=True)
      File "C:\Users\belog\hat_dispenser\venv\lib\site-packages\discord_components\interaction.py", line 93, in defer
        await self.respond(type=5 if not edit_origin else 6, ephemeral=ephemeral)
      File "C:\Users\belog\hat_dispenser\venv\lib\site-packages\discord_components\interaction.py", line 185, in respond
        raise NotFound(
    discord.errors.NotFound: 404 Not Found (error code: 0): Interaction is unknown (you have already responded to the interaction or responding took too long) 
    

    How can a few users choose a role immediately?



  • In this case, you have a mistake. response = await bot.wait_for("button_click")♪ You're just waiting for a push. any buttons, even other users. Add the test condition.

    def check(inter):
        return inter.message.id == message.id and inter.user == ctx.author
    

    await bot.wait_for(event='button_click', check=check)

    P.S. Previously, I answered yours. https://ru.stackoverflow.com/questions/1346060/%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B0-runtimewarning-%D0%BF%D0%BE%D1%81%D0%BB%D0%B5-%D0%B2%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-%D0%B2-discord-%D0%B1%D0%BE%D1%82%D0%B5 (sighs) https://ru.stackoverflow.com/a/1346550/436670 ) What didn't satisfy you in my past implementation?



Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2