Discord JS добавить роль по команде реакции не работает после перезапуска

#javascript #discord #discord.js

#javascript #Discord #discord.js

Вопрос:

Я пытаюсь создать команду «добавить роль с помощью реакции». Таким образом, когда участник реагирует на определенное сообщение, участник получает роль. Это действительно работает, но когда я перезапускаю своего бота, он больше не добавляет роль. Кто-нибудь может помочь?

вот код:

 bot.on('message', msg=>{
    if(msg.content.startsWith(prefix   "react")){
        let embed = new Discord.MessageEmbed()
        .setTitle("Reactions Roles")
        .setDescription("React to get a role!")
        .setColor("BLUE")
        msg.channel.send(embed).then(m=> m.react("emoji_id"))
    }
})

bot.on("messageReactionAdd", async (reaction, user)=>{
    if (reaction.message.partial) await reaction.message.fetch();
    if (reaction.partial) await reaction.fetch();
    if(user.bot) return;
    if(!reaction.message.guild) return;
    if(reaction.message.channel.id === "channel_id"){
        if(reaction.emoji.id === "emoji_id"){
            await reaction.message.guild.members.cache.get(user.id).roles.add("role_id")
        }
    }
})

bot.on('messageReactionRemove', async (reaction, user)=>{
    if(reaction.message.partial) await reaction.message.fetch();
    if(reaction.partial) await reaction.fetch();

    if(user.bot) return;
    if(!reaction.message.guild) return;

    if(reaction.message.channel.id === "channel_id"){
        if(reaction.emoji.id === "emoji_id"){
            await reaction.message.guild.members.cache.get(user.id).roles.remove("role_id")
        }
    }
})
  

Комментарии:

1. Просто для пояснения. Когда вы перезапускаете своего бота, вы ожидаете, что он отреагирует на старые сообщения и применит роли, или он не реагирует на новые сообщения?

2. @MagnusVestergaard Нет, я хочу, чтобы бот отреагировал на старое сообщение и добавил роль. Было бы неудобно отправлять новое сообщение при перезапуске бота. Он должен выполнить свою работу со старым сообщением.

3. Проблема в том, что ваш код регистрирует только новые сообщения / реакции, поэтому вам придется добавить некоторый код, который сканирует уже отправленные сообщения и проверяет их реакцию. Я посмотрю, не забуду ли я написать ответ с каким-нибудь примером кода, когда вернусь домой.

Ответ №1:

Я только что столкнулся с этой же проблемой и исправил ее. Ваш точный вариант использования подробно описан здесь, в документах, хотя я также приведу небольшое объяснение:https://discordjs.guide/popular-topics/reactions.html#listening-for-reactions-on-old-messages

У DiscordJS есть «кэш», который он использует для ускорения запросов (т. Е. Всякий раз, когда пользователь отправляет сообщение, DiscordJS сохраняет его локально — он сохраняет до определенного количества последних сообщений, я полагаю, 100). Поэтому, когда вы прослушиваете реакции, discordJS в основном будет прослушивать только кэшированные (по крайней мере, насколько я понимаю). Чтобы заставить его прослушивать некэшированные сообщения, вы должны использовать «Partials», что именно так и звучит — partials полных объектов. Это означает, что вы получите только объект с идентификатором, а не полный объект MessageReaction / User (для них есть функция, вызываемая fetch() , которая позволит вам получить полный объект). Использование Partials позволит вам прослушивать реакции на старые некэшированные сообщения.

Чтобы использовать частичные файлы, создайте клиент следующим образом:

 const bot = new Client({
  partials: ['MESSAGE', 'CHANNEL', 'USER', 'REACTION'],
});
  

и будьте осторожны позже, когда будете слушать такие вещи, как messageReactionAdd ! Вы должны сделать что-то вроде этого:

 client.on(
  'messageReactionAdd',
  async (potentialPartialReaction, potentialPartialUser) => {
    try {
      const reaction = await potentialPartialReaction.fetch();
      const user = await potentialPartialUser.fetch();
    } catch (err) {
      console.log(err);
    }

    // can use reaction and user here!
});
  

Я считаю, что это должно сработать в вашем случае, но дайте мне знать, если это не так. Это сработало для меня в DiscordJS v12.

Ответ №2:

Чтобы заставить вашего бота проверять, реагировали ли на предыдущие сообщения, вы могли бы использовать код, подобный этому

 let guildID = "xxx";
let channelID = "xxx";
let emojiID = "xxx";
let roleID = "xxx";


bot.on("ready", async () => {

    let guild = bot.guilds.cache.find(guild => guild.id == guildID);
    let channel = await guild.channels.cache.find(ch => ch.id == channelID)

    // You can set any limit you want, for performance I used a low number
    channel.messages.fetch({ limit: 10 })
        .then(async messages => {
            messages.forEach(async message => {

                if (message.partial) await message.fetch();
                if (!message.guild) return;

                for (let reactionObj of message.reactions.cache) {
                    for (let reaction of reactionObj) {
                        if (typeof reaction == "string") continue;
                        if (reaction.emoji.id != emojiID) continue;
                        reaction.users.fetch()
                            .then(async users => {
                                users.forEach(async user => {
                                    if (user.bot) return;
                                    console.log("Adding role")
                                    await reaction.message.guild.members.cache.get(user.id).roles.add(roleID)
                                })
                            })
                    }
                }

            });
        })
        .catch(console.error);
});
  

Возможно, вы захотите внести некоторые изменения, но это работает.

Чтобы разбить его…

  1. Получать сообщения в определенном канале (или нескольких)
  2. Проверьте, есть ли реакции на сообщение
  3. Проверьте, соответствует ли какая-либо из реакций определенному смайлику
  4. Добавьте роль члену гильдии
  5. При необходимости проверьте, есть ли у участника уже роль, прежде чем пытаться ее добавить

Пожалуйста, обратите внимание, что этот код вполне может быть не самым эффективным, но он выполняет свою работу. Кроме того, он НЕ работает с «нестандартными» смайликами, для этого вам нужно будет проверить emoji.name вместо emoji.id .

По предложению @michael.grigoryan очень рекомендуется ознакомиться с документацией.

Редактировать: Удален предыдущий ответ, чтобы устранить путаницу

Ответ №3:

Я провел некоторое тестирование и обнаружил кое-что довольно странное.

Когда вы перезапускаете бота и пытаетесь отреагировать на сообщение, отправленное до перезапуска бота, бот не регистрирует реакцию. Но если вы отправите новое сообщение и отреагируете на него, бот внезапно начнет регистрировать реакции на все сообщения.

Я думаю, что это как-то связано с частичными, но я не эксперт в этом!