Почему мой бот Discord не открывает или не сохраняет данные в файле JSON правильно?

В настоящее время я создаю событие роли реакции. Там вы можете установить роль реакции с помощью команды. Формат: >reactionss @role messageID emote. Затем бот добавит реакцию на данное сообщение.
(Вы реагируете данной эмоцией на сообщение и получаете роль. Если вы не отреагируете, она будет удалена.) Поэтому я сохранил все в файле JSON. Формат можно увидеть в коде. Он отлично работает. После перезапуска бота все вроде не сохраняется/ничего не происходит, когда я нажимаю на реакцию. Однако все, кажется, все еще хранится в файле JSON, но он не используется. Мой код до сих пор:

class ReactionRoles(commands.Cog):
    """
    This instance handles all reaction role events.
    """

    def __init__(self, bot):
        super().__init__()
        self.bot = bot
        self.reaction_roles = []

    @commands.command(name = "Reaction", aliases=["reactionss"])
    async def set_reaction(self, ctx, role: discord.Role = None, msg: discord.Message = None, emoji=None):
        with open('reaction_roles.json', 'r', encoding='utf-8') as f:
            reaction_roles = json.load(f)

        try:
            reaction_roles[f"{role.id}, {msg.id}"] = emoji
        except KeyError:
            new = {ctx.message.id: role.id}
            reaction_roles.update(new)

        if role is not None and msg is not None and emoji is not None:
            await msg.add_reaction(emoji)
            self.reaction_roles.append((role.id, msg.id, str(emoji.encode("utf-8"))))

            with open('reaction_roles.json', 'w', encoding='utf-8') as f:
                json.dump(reaction_roles, f, indent=2)

            await ctx.channel.send("**Reaction has been set.**")

    @commands.Cog.listener()
    async def on_raw_reaction_add(self, payload):
        for role_id, msg_id, emoji in self.reaction_roles:
            if msg_id == payload.message_id and emoji == str(payload.emoji.name.encode("utf-8")):
                await payload.member.add_roles(self.bot.get_guild(payload.guild_id).get_role(role_id))

    @commands.Cog.listener()
    async def on_raw_reaction_remove(self, payload):
        for role_id, msg_id, emoji in self.reaction_roles:
            if msg_id == payload.message_id and emoji == str(payload.emoji.name.encode("utf-8")):
                guild = self.bot.get_guild(payload.guild_id)
                await guild.get_member(payload.user_id).remove_roles(guild.get_role(role_id))```
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
117
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой он не работает после сброса, заключается в том, что каждый раз, когда он сбрасывается, он переопределяет список reaction_roles и устанавливает его пустым.

    def __init__(self, bot):
        super().__init__()
        self.bot = bot
        self.reaction_roles = [] # Whenever code reloads, this is set here, and is empty

Ваши on_raw_reaction_add и on_raw_reaction_remove используют этот список для определения реакций и ролей, а не файл JSON.

Вы можете сделать что-то подобное, используя dicts и только файл JSON. JSON не поддерживает целые числа в качестве ключей, поэтому при работе с msg.id используйте str(msg.id)

# Not really necessary, but we need to read the file multiple times
# If you ever relocate it, you will only need to edit it once
def json_open(): #you can rename it, just remember to change the rest as well
    with open('reaction_roles.json', 'r', encoding='utf-8') as f:
        reaction_roles = json.load(f)
        return reaction_roles


class Reactions(commands.Cog):
    """
    This instance handles all reaction role events.
    """
    def __init__(self, bot):
        super().__init__()
        self.bot = bot


    @commands.command(name = "Reaction", aliases=["reactionss"])
    async def set_reaction(self, ctx, role: discord.Role = None, msg: discord.Message = None, emoji=None):
        reaction_roles = json_open() # Open the json file

        # First time registering emoji to msg will give error since msg is not in dict
        try:
            role_dict = reaction_roles[str(msg.id)]
        except:
            role_dict = {}

        role_dict[emoji] = role.id
        reaction_roles[str(msg.id)]=role_dict

        if role is not None and msg is not None and emoji is not None:
            await msg.add_reaction(emoji)

            with open('reaction_roles.json', 'w', encoding='utf-8') as f:
                json.dump(reaction_roles, f, indent=2, ensure_ascii=False)
                # setting ensure_ascii=False --> We can have actual emojis in json
                
            await ctx.channel.send("**Reaction has been set.**")

    # Next two steps are same, except one is remove and one is add
    @commands.Cog.listener()
    async def on_raw_reaction_add(self, payload):
        if payload.user_id == 775390992777216040: # Bot wont accidentally get any roles
            return
        reaction_roles = json_open() # Open JSON
        if str(payload.message_id) in list(reaction_roles.keys()): # If msg matches
            role_dict = reaction_roles[str(payload.message_id)]    # If reaction matches
            if payload.emoji.name in list(role_dict.keys()):
                role_id = role_dict[payload.emoji.name]
                guild = self.client.get_guild(payload.guild_id)
                role = guild.get_role(role_id)
                await guild.get_member(payload.user_id).add_roles(role)

    @commands.Cog.listener()
    async def on_raw_reaction_remove(self, payload):
        if payload.user_id == 775390992777216040:
            return
        reaction_roles = json_open()
        if str(payload.message_id) in list(reaction_roles.keys()):
            role_dict = reaction_roles[str(payload.message_id)]
            if payload.emoji.name in list(role_dict.keys()):
                role_id = role_dict[payload.emoji.name]
                guild = self.client.get_guild(payload.guild_id)
                role = guild.get_role(role_id)
                await guild.get_member(payload.user_id).remove_roles(role)

Файл JSON в конечном итоге будет выглядеть так

{
  "msg1_id": {
    "😈": role1_id,
    "😅": role2_id
  },
  "msg2_id": {
    "🌀": role3_id
  }
}

Спасибо, что нам нужно сделать для "json_open", так как я работаю с командами? Я просто устанавливаю следующее: reaction_roles= self.bot.json_open()?

Dominik 10.12.2020 22:47

@Доминик, тебе не нужно ничего с этим делать. Причина, по которой я поместил его туда, заключается в том, что когда нам нужно открыть файл reaction_roles.json (мы открываем его три раза только в этом фрагменте кода), мы можем сделать reaction_roles = json_open(). Поскольку json_open() — это функция, каждый раз, когда она вызывается, она открывает файл json и возвращает reaction_roles, с которым мы можем работать. Я определяю его перед классом, в самом верху кода. Теперь, если вы измените имя файла или местоположение, вам нужно будет отредактировать его вверху только один раз, а не три раза в коде.

AbdurJ 11.12.2020 00:58

Другие вопросы по теме