You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js等级角色奖励:获取数组中低于阈值的最高等级对应角色

Discord.js 机器人等级奖励角色发放逻辑修复

问题背景

开发Discord.js等级体系机器人时,需实现以下逻辑:用户升级达到指定等级里程碑时,为其发放对应奖励角色,同时移除此前持有的低阶段奖励角色。
初始版本代码仅支持奖励等级连续(相邻奖励等级差为1,如1级升2级)的场景,当奖励配置存在等级断层(如从4级升到5级、3/4级无对应奖励)时,程序会因找不到待移除的旧角色变量直接崩溃。

原有代码缺陷分析

初始版本直接通过「当前等级-1」匹配旧角色,完全未考虑奖励等级不连续的场景:

memberData.level = 4;

levelUpRoles = [ // 用户自定义的等级-角色映射配置
    {role: 'id1', level: 1},
    {role: 'id2', level: 2},
    {role: 'id3', level: 5},
    {role: 'id4', level: 20},
    {role: 'id5', level: 10},
]

let newLvl = levelUpRoles.find(object => object.level === memberData.level);
// 缺陷点:直接匹配等级-1的配置,等级断层时prevLvl为undefined
let prevLvl = levelUpRoles.find(object => object.level === memberData.level - 1);

if (newLvl) {
    target.roles.add(newLvl.role).catch(console.error);
    // prevLvl为undefined时读取.role属性,直接触发类型错误崩溃
    target.roles.remove(prevLvl.role).catch(console.error);
}

后续调整的版本仍存在两个致命问题:

  1. 多余的slice(0,-1)操作会错误截断符合要求的最高等级低阶角色
  2. slice(-1)返回值是长度为1的数组,而非单个角色对象,直接读取.role属性依然会得到undefined
    调整后的问题代码如下:
// 缺陷点:多余截断逻辑,且最终返回数组而非单个角色对象
let prevLvl = levelUpRoles.filter(object => object.level < memberData.level).sort(function (a, b) {return a.level - b.level}).slice(0,-1).slice(-1);
let newLvl = levelUpRoles.find(object => object.level === memberData.level);
if (newLvl) {
    console.log(newLvl);
    target.roles.add(newLvl.role).catch(console.error);
    console.log(prevLvl);
    if (prevLvl) {
        // prevLvl是数组,此处.role取值无效
        target.roles.remove(prevLvl.role).catch(console.error);
    }
}

正确实现方案

获取待移除旧角色的核心逻辑:

  • 先对等级角色配置做升序排序,规避用户自定义配置顺序混乱的问题
  • 筛选出所有等级要求低于当前用户等级的奖励配置
  • 取筛选结果中等级最高的配置,即为距离当前等级最近的上一阶段奖励角色
  • 增加空值校验,仅当确实存在旧奖励角色时才执行移除操作,避免空值报错
    最终可稳定运行的代码:
// 拷贝原数组后排序,避免修改原数组顺序影响其他业务逻辑
const sortedLevelRoles = [...levelUpRoles].sort((a, b) => a.level - b.level);
// 匹配当前等级对应的新奖励角色
const newReward = sortedLevelRoles.find(item => item.level === memberData.level);

if (newReward) {
    // 授予新的里程碑角色
    target.roles.add(newReward.role).catch(console.error);
    // 筛选所有低于当前等级的奖励,取最高等级的作为待移除旧角色
    const lowerLevelRewards = sortedLevelRoles.filter(item => item.level < memberData.level);
    const oldReward = lowerLevelRewards.pop(); // pop直接取数组最后一项,即最高等级的低阶奖励
    
    if (oldReward) {
        target.roles.remove(oldReward.role).catch(console.error);
    }
}

逻辑验证

基于示例配置测试多场景:

  • 用户首次升级到1级:低于1级的奖励为空,不执行移除操作,仅授予1级角色,无报错
  • 用户从4级升到5级:新奖励为5级角色id3,筛选出低于5级的最高奖励为2级角色id2,移除id2、授予id3,符合预期
  • 用户从9级升到10级:新奖励为10级角色id5,低于10级的最高奖励为5级角色id3,移除id3、授予id5,符合预期
  • 用户从19级升到20级:新奖励为20级角色id4,低于20级的最高奖励为10级角色id5,移除id5、授予id4,符合预期

内容的提问来源于stack exchange,提问作者Gleyveon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:06:26