Discord.js v14 反应收集器异常及计分系统实现咨询
Discord 反应收集器问题与计分系统实现方案
问题1:重复收集反应的原因及修复
原因
你在client.on("messageCreate")事件内部嵌套绑定了多层同类型事件监听器:
- 每次用户发送
prefix + "m"触发外层messageCreate时,都会新增一个client.on("messageCreate")监听器 - 当机器人发送彩蛋消息后,所有已绑定的
messageCreate监听器都会同时触发,各自创建独立的反应收集器 - 用户一次反应会被多个收集器同时捕获,导致控制台显示的收集次数远多于实际操作次数
修复方案
移除嵌套的事件绑定,直接在机器人发送彩蛋消息后创建收集器,不需要额外监听自身发送的消息:
client.on("messageCreate", async message => { // 处理发送彩蛋消息的指令 if (message.content === prefix + "m") { const eggMessage = await message.channel.send("Voici un oeuf de Pâques! Vite! Réagis avant qu'il ne disparaisse! :)"); await eggMessage.react('🥚'); const filter = (reaction, user) => { return reaction.emoji.name === '🥚' && user.id !== client.user.id; }; const collector = eggMessage.createReactionCollector({ filter, time: 5000 }); collector.on('collect', (reaction, user) => { console.log(`Collected ${reaction.emoji.name} from ${user.tag}`); // 调用后续实现的计分更新函数 updateUserScore(user.id); }); collector.on('end', collected => { console.log(`Collected ${collected.size} items`); }); } // 处理查询分数的指令,单独放在外层 if (message.content === prefix + "c") { const userScore = getUserDailyScore(message.author.id); const infoEmbed = new EmbedBuilder() .setColor('Random') .setTitle(`Inventory`) .setDescription("Check how many Easter Eggs you collected!") .addFields({ name: 'Easter Eggs', value: `${userScore}` }); message.channel.send({ embeds: [infoEmbed] }); } });
问题2:单日用户反应次数计分系统实现
核心逻辑
- 用结构化数据存储每日分数(开发阶段用全局对象,生产环境建议用数据库持久化)
- 每次用户反应时,基于当前日期更新对应用户的计数
- 查询时读取当日的用户分数数据
具体实现代码
// 全局存储每日分数,结构:{ "YYYY-MM-DD": { "用户ID": 累计次数 } } let dailyScores = {}; // 获取格式化的当前日期(YYYY-MM-DD) function getCurrentDate() { const now = new Date(); return `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`; } // 更新用户当日反应次数 function updateUserScore(userId) { const currentDate = getCurrentDate(); // 如果当日分数记录不存在,初始化空对象 if (!dailyScores[currentDate]) { dailyScores[currentDate] = {}; } // 累加用户次数,无记录则初始化为1 dailyScores[currentDate][userId] = (dailyScores[currentDate][userId] || 0) + 1; } // 获取用户当日累计反应次数 function getUserDailyScore(userId) { const currentDate = getCurrentDate(); return dailyScores[currentDate]?.[userId] || 0; }
生产环境优化提示
- 全局对象在机器人重启后会丢失数据,建议使用轻量数据库(如
quick.db或sqlite3)实现持久化存储 - 可添加定时任务,每日自动清理过期的历史分数,降低内存占用
内容的提问来源于stack exchange,提问作者FireFenrir
相关产品推荐
相关产品推荐

