如何为discord.js开发的Discord聊天机器人添加触发词响应启停命令
实现方案
问题根源
你遇到的两个核心问题原因:
can't run commands before initialization报错是因为load函数里添加了大量不必要的sleep延迟,导致命令集还没加载完成机器人就已经上线接收消息,调用未初始化的命令集合就会报错。- 你认为触发词必须放在指令逻辑前是因为原代码里指令判断部分用了直接
return,非前缀消息会直接终止整个事件流程,导致触发词逻辑无法执行,只要调整这个判断逻辑即可解决。
具体修改步骤
1. 新增触发词状态存储
在常量声明区域添加全局状态存储,支持分服务器控制开关:
// 原有常量声明保留,新增以下内容 // key为服务器ID,value为触发词开关状态,默认开启 const triggerEnabled = new Map();
2. 优化加载逻辑解决初始化报错
删掉load函数里所有不必要的await sleep和await console.log(console.log本身不是异步方法,不需要await),修改后代码如下:
async function load() { console.log(chalk.green('AEIOU, Here to sing for you!')) console.log('\n\n'); console.log('Booting up ' + chalk.cyan(__filename)); console.log(chalk.bgCyan(chalk.black('[Command Loader]')), 'Loading Abilities...'); for (const file of commandFiles) { const command = require(`./commands/${file}`); client.commands.set(command.name, command); console.log(chalk.bgGreen(chalk.black('[Command Loader]')), 'Got this one! ' + chalk.magentaBright(file)); totalCommands++; } console.log(chalk.cyan(totalCommands), 'commands loaded'); client.login("TOKEN_HERE"); }
3. 重写message事件逻辑顺序
调整逻辑顺序为:!start/!stop命令处理 -> 普通前缀指令处理 -> 触发词检测(开关开启才执行),修改后的完整message事件代码如下:
client.on("message", async message => { if (message.author.id == client.user.id) { return } // 处理!start/!stop命令,可按需添加管理员权限判断 if (message.content === '!start') { if (!message.guild) return message.reply('私聊场景默认开启触发词响应'); triggerEnabled.set(message.guild.id, true); return message.reply('触发词响应已开启'); } if (message.content === '!stop') { if (!message.guild) return message.reply('私聊场景无法关闭触发词响应'); triggerEnabled.set(message.guild.id, false); return message.reply('触发词响应已关闭,仅响应指令'); } // 处理带au>前缀的普通指令 if (message.content.startsWith(prefix) && !message.author.bot) { const commandBody = message.content.slice(prefix.length); const args = commandBody.split(' '); const command = args.shift().toLowerCase(); if (command == 'credit' || command == 'credits') { client.commands.get('credits').execute(message, args, Discord, client); return; } if (command == 'help' || command == 'menu') { client.commands.get('help').execute(message, args, Discord, client); return; } if (command == 'link' || command == 'invite') { client.commands.get('invite').execute(message, args, Discord, client); return; } if (command == 'headpat' || command == 'pat') { client.commands.get('pet').execute(message, args, Discord, client); return; } if (command === "repeat") { const echoMessage = args.join(" "); message.delete(); message.channel.send(echoMessage); return; } if (command == 'suggest') { const suggestionmsg = args.join(' '); if (!args.length) { return message.channel.send(`You didn't provide a suggestion, ${message.author}!`); } else { // 修复原代码小写me的笔误 client.users.cache.get(Me).send(message.author.tag + ' suggests: ' + suggestionmsg); message.channel.send("Thanks for your suggestion, and for helping with my development! I'm always looking for ways to be a better bot!"); return; } } } // 预处理消息用于触发词检测 var msg = []; var placeholder = message.content.toLowerCase().split(' '); placeholder.forEach(string => { string = string.replace(',', ''); string = string.replace('?', ''); string = string.replace('!', ''); string = string.replace('"', ''); msg.push(string); }); // 触发词开关判断 const enabled = message.guild ? (triggerEnabled.get(message.guild.id) ?? true) : true; if (enabled) { if (msg.some(r => hi.messages.includes(r))) { return message.channel.send(hi.responses[getRandomInt(hi.responses.length)]); } if (msg.some(r => funny.messages.includes(r))) { return message.channel.send(funny.responses[getRandomInt(funny.responses.length)]); } if (msg.some(r => drink.messages.includes(r))) { return message.channel.send(drink.responses[getRandomInt(drink.responses.length)]); } if (msg.some(r => food.messages.includes(r))) { return message.channel.send(food.responses[getRandomInt(food.responses.length)]); } if (msg.some(r => cute.messages.includes(r))) { return message.channel.send(cute.responses[getRandomInt(cute.responses.length)]); } if (msg.some(r => horny.messages.includes(r))) { return message.channel.send(horny.responses[getRandomInt(horny.responses.length)]); } if (msg.some(r => loli.messages.includes(r))) { return message.channel.send(loli.responses[getRandomInt(loli.responses.length)]); } } // 艾特响应放在最后,不受开关影响可按需调整 if (message.mentions.has(client.user)) { message.channel.send("Hi! I'm AEIOU, and I do have a prefix. It's `au>[command]`. Thanks for mentioning me!") } });
可选优化
如果需要重启机器人后仍然保留开关状态,可以将triggerEnabled的内容定期写入本地json文件,启动时读取即可。
内容的提问来源于stack exchange,提问作者SchneebNabs
相关产品推荐
相关产品推荐

