Discord.js决斗机器人开发问题:仅允许被挑战者接受决斗
解决Discord.js决斗机器人仅允许被挑战者确认的问题
嘿,我完全懂你现在的窘境——本来想做一个只有被挑战者能确认的决斗系统,结果现在只有发起挑战的人能响应,这显然和预期不符对吧?我之前开发类似互动机器人的时候也踩过这个坑,给你一步步拆解怎么改:
问题根源分析
大概率是你之前的代码里,把响应确认的判断条件写成了检查消息作者是否是挑战发起者(比如message.author.id === challengerId),这就直接把被挑战者的权限给排除了。我们需要反过来,把挑战的目标对象(被挑战者)的ID存起来,然后在处理确认请求时验证当前用户是不是这个被挑战者。
具体解决方案
我们可以用一个Map来跟踪所有活跃的决斗挑战,存储每个挑战的发起者、被挑战者和发起频道信息,这样就能精准判断谁有权限确认。
1. 初始化活跃挑战存储
首先创建一个全局的Map来保存待确认的挑战:
// 全局变量,用于跟踪所有待确认的决斗挑战 const activeDuels = new Map(); // 结构示例:key = 被挑战者ID,value = { challengerId: '发起者ID', channelId: '挑战发起频道ID' }
2. 发起挑战的逻辑调整
在用户发起挑战时,把被挑战者的ID作为键,存储对应的挑战信息:
client.on('messageCreate', async (message) => { // 假设!duel是发起挑战的命令,格式如!duel @用户名 if (message.content.startsWith('!duel')) { const mentionedUser = message.mentions.users.first(); // 检查是否有@用户 if (!mentionedUser) { return message.reply('请@一个用户来发起决斗挑战哦!'); } // 禁止自我挑战 if (mentionedUser.id === message.author.id) { return message.reply('你总不能自己和自己决斗吧?😅'); } // 检查被挑战者是否已有待处理的挑战 if (activeDuels.has(mentionedUser.id)) { return message.reply(`<@${mentionedUser.id}>已经有一个待确认的挑战了,请等对方回复后再发起!`); } // 存储挑战信息 activeDuels.set(mentionedUser.id, { challengerId: message.author.id, channelId: message.channel.id }); // 发送挑战通知 message.channel.send(`⚔️ <@${mentionedUser.id}>!<@${message.author.id}>向你发起了决斗挑战!回复\`!accept\`接受挑战,\`!decline\`拒绝挑战!`); } });
3. 处理确认/拒绝的逻辑
现在在处理!accept或!decline命令时,只允许被挑战者操作:
client.on('messageCreate', async (message) => { const userId = message.author.id; const currentDuel = activeDuels.get(userId); // 处理接受挑战 if (message.content === '!accept') { if (!currentDuel) { return message.reply('你目前没有待接受的决斗挑战哦!'); } // 验证是否在发起挑战的频道操作(可选,防止跨频道误操作) if (currentDuel.channelId !== message.channel.id) { return message.reply('请在发起挑战的频道里确认决斗哦!'); } // 执行决斗开始的逻辑(这里可以替换成你自己的决斗流程) message.channel.send(`🎉 决斗开始!<@${currentDuel.challengerId}> VS <@${userId}>!准备好战斗吧!`); // 移除已处理的挑战,避免重复操作 activeDuels.delete(userId); } // 处理拒绝挑战(可选功能) if (message.content === '!decline') { if (!currentDuel) { return message.reply('你目前没有待拒绝的决斗挑战哦!'); } if (currentDuel.channelId !== message.channel.id) { return message.reply('请在发起挑战的频道里拒绝决斗哦!'); } message.channel.send(`😔 <@${currentDuel.challengerId}>,你的决斗挑战被<@${userId}>拒绝了!`); activeDuels.delete(userId); } });
额外优化建议
- 超时自动取消:可以给每个挑战加个定时器,比如5分钟后如果被挑战者没回复,就自动移除挑战并通知发起者
- 多挑战支持:如果需要同时支持多个挑战(比如A挑战B,C挑战D),当前的
Map结构已经能满足,因为键是被挑战者ID,不会冲突 - 权限验证:可以额外检查用户是否是机器人,避免机器人误操作
这样改完之后,就只有被@的目标用户才能用!accept或!decline来响应挑战,发起者自己回复这些命令会提示没有待处理的挑战,完美符合你的需求!
内容的提问来源于stack exchange,提问作者Tadyr
相关产品推荐
相关产品推荐

