#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);
});
Возможно, вы захотите внести некоторые изменения, но это работает.
Чтобы разбить его…
- Получать сообщения в определенном канале (или нескольких)
- Проверьте, есть ли реакции на сообщение
- Проверьте, соответствует ли какая-либо из реакций определенному смайлику
- Добавьте роль члену гильдии
- При необходимости проверьте, есть ли у участника уже роль, прежде чем пытаться ее добавить
Пожалуйста, обратите внимание, что этот код вполне может быть не самым эффективным, но он выполняет свою работу. Кроме того, он НЕ работает с «нестандартными» смайликами, для этого вам нужно будет проверить emoji.name вместо emoji.id .
По предложению @michael.grigoryan очень рекомендуется ознакомиться с документацией.
Редактировать: Удален предыдущий ответ, чтобы устранить путаницу
Ответ №3:
Я провел некоторое тестирование и обнаружил кое-что довольно странное.
Когда вы перезапускаете бота и пытаетесь отреагировать на сообщение, отправленное до перезапуска бота, бот не регистрирует реакцию. Но если вы отправите новое сообщение и отреагируете на него, бот внезапно начнет регистрировать реакции на все сообщения.
Я думаю, что это как-то связано с частичными, но я не эксперт в этом!