GwLevel 等级系统

一个功能强大、易于扩展的 Minecraft 基岩版玩家等级系统框架。 提供完整的 API 接口,支持模块化开发,让您轻松创建自定义的等级玩法。

主要特性

  • 完整的等级与经验系统
  • 丰富的 API 接口(40+ 个方法)
  • 灵活的事件系统
  • 模块化扩展支持
  • GUI 表单集成
  • PAPI 变量支持
  • 自动/手动升级模式
  • 数据持久化存储

版本信息

当前版本:v1.3.4

适用版本:LeviLamina + LSE

作者:GwBBS - 干物社

开源协议:MIT License

安装指南

按照以下步骤安装 GwLevel 等级系统

安装步骤

1前置要求

  • 已安装 LeviLamina 框架
  • 已安装 LSE (LegacyScriptEngine) 脚本引擎
  • (可选)GMLIB-LegacyRemoteCallApi 用于 PAPI 支持

2下载插件

从 GitHub 或其他发布页面下载最新版本的 GwLevel.js 文件

3安装插件

将 GwLevel.js 文件放入服务器的 plugins/ 目录

目录结构
BDS/
├── plugins/
│   ├── GwLevel.js
│   └── GMLIB-LegacyRemoteCallApi/ (可选)
└── ...

4启动服务器

启动服务器,插件将自动创建必要的目录和配置文件

自动创建的目录
plugins/GwLevel/
├── config/
│   └── settings.json    # 配置文件
├── data/
│   └── players.json     # 玩家数据
└── mod/                 # 模块目录
提示
首次安装后,建议查看配置文件并根据需要进行调整

快速上手

几分钟内开始使用 GwLevel 等级系统

基础命令

命令列表
/level - 打开等级系统主菜单
/lv - 简写命令

# 玩家命令
/lv my - 查看自己的等级信息
/lv info <玩家名> - 查看其他玩家等级
/lv levelup - 手动升级(需开启手动升级模式)

# 管理员命令
/lv addexp <玩家> <数量> - 添加经验
/lv setlevel <玩家> <等级> - 设置等级
/lv reload - 重载配置

基础 API 使用

获取 API 对象并使用:

JavaScript
// 导入 GwLevel API
const GwLevel = ll.imports("GwLevel");

// 获取玩家等级
mc.listen("onJoin", (player) => {
    const level = GwLevel.getPlayerLevel(player);
    const exp = GwLevel.getPlayerExp(player);
    player.tell(`§a欢迎回来!您当前等级:§e${level} §a级,经验:§e${exp}`);
});

// 击杀怪物获得经验
mc.listen("onMobDie", (mob, source) => {
    if (source && source.isPlayer()) {
        const player = source.toPlayer();
        // 根据怪物类型给予不同经验
        let expReward = 10; // 默认经验
        
        if (mob.type === "minecraft:zombie") expReward = 15;
        if (mob.type === "minecraft:skeleton") expReward = 20;
        if (mob.type === "minecraft:creeper") expReward = 25;
        
        GwLevel.addPlayerExp(player, expReward);
        player.tell(`§a+${expReward} 经验值`);
    }
});

创建第一个模块

plugins/GwLevel/mod/ 目录创建一个 JavaScript 文件:

JavaScript - kill_reward.js
// 击杀奖励模块
logger.setTitle("GwLevel-击杀奖励");

// 配置击杀奖励
const killRewards = {
    "minecraft:zombie": { exp: 10, money: 50 },
    "minecraft:skeleton": { exp: 15, money: 75 },
    "minecraft:creeper": { exp: 20, money: 100 },
    "minecraft:enderman": { exp: 30, money: 150 },
    "minecraft:wither": { exp: 500, money: 5000 },
    "minecraft:ender_dragon": { exp: 1000, money: 10000 }
};

// 监听怪物死亡事件
mc.listen("onMobDie", (mob, source) => {
    if (!source || !source.isPlayer()) return;
    
    const player = source.toPlayer();
    const reward = killRewards[mob.type];
    
    if (reward) {
        // 给予经验
        API.addPlayerExp(player, reward.exp);
        
        // 给予金钱(如果安装了经济插件)
        if (money && reward.money) {
            money.add(player.xuid, reward.money);
        }
        
        // 发送奖励信息
        player.tell(`§6击杀奖励: §a+${reward.exp} 经验${reward.money ? ` §e+${reward.money} 金币` : ''}`);
    }
});

logger.log("击杀奖励模块已加载");

玩家等级 API

管理玩家等级的核心接口

getPlayerLevel

获取
获取玩家当前等级
JavaScript
const level = GwLevel.getPlayerLevel(player);
// 返回: String - 玩家等级
参数 类型 说明
player Player | String 玩家对象或 XUID

setPlayerLevel

设置
设置玩家等级
JavaScript
const success = GwLevel.setPlayerLevel(player, 10);
// 返回: Boolean - 是否成功
参数 类型 说明
player Player | String 玩家对象或 XUID
level Number 目标等级(1 - maxLevel)
提示
设置等级会重置玩家当前经验值为 0

addPlayerLevel

操作
增加玩家等级
JavaScript
const success = GwLevel.addPlayerLevel(player, 5);
// 返回: Boolean - 是否成功
使用示例
JavaScript
// 监听玩家击杀事件,击杀 Boss 升 5 级
mc.listen("onMobDie", (mob, source) => {
    if (source && source.isPlayer() && mob.type === "minecraft:wither") {
        const player = source.toPlayer();
        GwLevel.addPlayerLevel(player, 5);
        player.tell("§a恭喜击败凋灵!等级 +5");
    }
});

reducePlayerLevel

操作
减少玩家等级
JavaScript
const success = GwLevel.reducePlayerLevel(player, 2);
// 返回: Boolean - 是否成功
注意
减少等级会将当前经验重置为 0,等级最低为 1

levelUp

特殊
手动升级(需要开启手动升级模式)
JavaScript
const success = GwLevel.levelUp(player);
// 返回: Boolean - 是否成功升级
手动升级系统示例
JavaScript
// 创建升级 NPC
mc.listen("onUseItemOn", (player, item, block) => {
    // 假设使用绿宝石右键信标进行升级
    if (item.type === "minecraft:emerald" && block.type === "minecraft:beacon") {
        const config = GwLevel.getConfig();
        if (!config.manualLevelUp) {
            player.tell("§c服务器未开启手动升级模式");
            return;
        }
        
        const currentExp = parseInt(GwLevel.getPlayerExp(player));
        const requiredExp = parseInt(GwLevel.getExpRequiredForNextLevel(player));
        
        if (currentExp >= requiredExp) {
            if (GwLevel.levelUp(player)) {
                player.tell("§a升级成功!");
                mc.spawnParticle(block.pos, "minecraft:villager_happy");
            }
        } else {
            player.tell(`§c经验不足!还需要 ${requiredExp - currentExp} 经验`);
        }
    }
});

玩家经验 API

管理玩家经验值的接口

getPlayerExp

获取
获取玩家当前经验值
JavaScript
const exp = GwLevel.getPlayerExp(player);
// 返回: String - 当前经验值

addPlayerExp

操作
为玩家添加经验值,自动处理升级(非手动升级模式)
JavaScript
const success = GwLevel.addPlayerExp(player, 100);
// 返回: Boolean - 是否成功
经验系统集成示例
JavaScript
// 破坏方块获得经验
const blockExpReward = {
    "minecraft:coal_ore": 5,
    "minecraft:iron_ore": 10,
    "minecraft:gold_ore": 15,
    "minecraft:diamond_ore": 50,
    "minecraft:emerald_ore": 100,
    "minecraft:ancient_debris": 200
};

mc.listen("onDestroyBlock", (player, block) => {
    const reward = blockExpReward[block.type];
    if (reward) {
        GwLevel.addPlayerExp(player, reward);
        
        // 显示获得的经验
        player.tell(`§a+${reward} 经验`);
        
        // 在方块位置生成经验球特效
        mc.spawnParticle(block.pos, "minecraft:totem_particle");
    }
});

reducePlayerExp

操作
减少玩家经验值,可能导致降级
JavaScript
const success = GwLevel.reducePlayerExp(player, 50);
// 返回: Boolean - 是否成功
死亡惩罚示例
JavaScript
// 死亡损失经验
mc.listen("onPlayerDie", (player, source) => {
    const currentExp = parseInt(GwLevel.getPlayerExp(player));
    const penalty = Math.floor(currentExp * 0.1); // 损失 10% 经验
    
    if (penalty > 0) {
        GwLevel.reducePlayerExp(player, penalty);
        player.tell(`§c死亡惩罚:-${penalty} 经验`);
    }
});

setPlayerExp

设置
设置玩家经验为指定值
JavaScript
const success = GwLevel.setPlayerExp(player, 500);
// 返回: Boolean - 是否成功

getPlayerTotalExp

获取
获取玩家累计获得的总经验值
JavaScript
const totalExp = GwLevel.getPlayerTotalExp(player);
// 返回: String - 总经验值

getExpRequiredForNextLevel

获取
获取升到下一级所需的经验值
JavaScript
const required = GwLevel.getExpRequiredForNextLevel(player);
// 返回: String - 升级所需经验
等级进度显示
JavaScript
// 显示等级进度条
function showLevelProgress(player) {
    const level = GwLevel.getPlayerLevel(player);
    const currentExp = parseInt(GwLevel.getPlayerExp(player));
    const requiredExp = parseInt(GwLevel.getExpRequiredForNextLevel(player));
    const progress = parseInt(GwLevel.getPlayerLevelProgress(player));
    
    // 生成进度条
    const barLength = 20;
    const filled = Math.floor(barLength * progress / 100);
    const empty = barLength - filled;
    const progressBar = "§a" + "█".repeat(filled) + "§7" + "░".repeat(empty);
    
    // 发送 ActionBar
    player.tell(`§e等级 ${level} §f| ${progressBar} §f| §b${currentExp}§7/§b${requiredExp} §7(${progress}%)`, 5);
}

// 定期显示进度
setInterval(() => {
    mc.getOnlinePlayers().forEach(player => {
        showLevelProgress(player);
    });
}, 2000);

等级管理 API

管理玩家数据和系统设置的高级接口

resetPlayerLevel

重置
重置玩家的等级和经验
JavaScript
const success = GwLevel.resetPlayerLevel(player);
// 返回: Boolean - 是否成功

resetAllPlayerData

危险
重置所有玩家的等级数据(自动备份)
JavaScript
const success = GwLevel.resetAllPlayerData();
// 返回: Boolean - 是否成功
警告
此操作会重置所有玩家数据,执行前会自动创建备份文件

removePlayerData

删除
完全删除指定玩家的数据
JavaScript
const success = GwLevel.removePlayerData(player);
// 返回: Boolean - 是否成功

getConfig / updateConfig

配置
获取和更新系统配置
JavaScript
// 获取当前配置
const config = GwLevel.getConfig();
console.log(config);
/* 返回:
{
    baseExpToLevelUp: 100,
    expIncreaseRate: 1.1,
    maxLevel: 100,
    saveIntervalMinutes: 5,
    enableModSystem: true,
    manualLevelUp: false,
    PAPI: true
}
*/

// 更新配置
const newConfig = {
    maxLevel: 200,
    expIncreaseRate: 1.2,
    manualLevelUp: true
};
GwLevel.updateConfig(newConfig);
动态配置示例
JavaScript
// 周末双倍经验活动
function weekendEvent() {
    const now = new Date();
    const day = now.getDay();
    
    // 周六(6)或周日(0)
    if (day === 0 || day === 6) {
        // 监听经验获取事件
        GwLevel.on("beforeExpAdd", (data) => {
            // 双倍经验
            data.amount *= 2;
            
            const player = mc.getPlayer(data.xuid);
            if (player) {
                player.tell("§6周末双倍经验活动生效中!");
            }
        });
        
        mc.broadcast("§e§l周末双倍经验活动已开启!");
    }
}

// 服务器启动时检查
mc.listen("onServerStarted", () => {
    weekendEvent();
});

reloadConfig / saveAllData

系统
重载配置文件和保存所有数据
JavaScript
// 重新加载配置文件
GwLevel.reloadConfig();

// 手动保存所有玩家数据
GwLevel.saveAllData();

数据查询 API

查询玩家数据和排行榜的接口

playerExists

查询
检查玩家数据是否存在
JavaScript
const exists = GwLevel.playerExists(player);
// 返回: Boolean - 是否存在

getPlayerData

查询
获取玩家的完整数据对象
JavaScript
const data = GwLevel.getPlayerData(player);
/* 返回:
{
    name: "PlayerName",
    level: 10,
    exp: 250,
    totalExp: 1500,
    lastOnline: 1234567890000
}
*/

getAllPlayerData

查询
获取所有玩家的数据
JavaScript
const allData = GwLevel.getAllPlayerData();
// 返回: Object - 所有玩家数据的映射表 { xuid: playerData }

getPlayerLevelProgress

查询
获取玩家当前等级进度百分比
JavaScript
const progress = GwLevel.getPlayerLevelProgress(player);
// 返回: String - 进度百分比 (0-100)

getTopPlayers

排行榜
获取排行榜数据
JavaScript
// 获取等级排行榜前10名
const topByLevel = GwLevel.getTopPlayers(10, "level");

// 获取总经验排行榜前10名
const topByExp = GwLevel.getTopPlayers(10, "totalExp");

/* 返回格式:
[
    {
        xuid: "1234567890",
        name: "Player1",
        level: 50,
        exp: 1200,
        totalExp: 45000
    },
    ...
]
*/
排行榜展示示例
JavaScript
// 创建排行榜展示
function showLeaderboard(player) {
    const form = mc.newSimpleForm();
    form.setTitle("§6等级排行榜");
    
    const topPlayers = GwLevel.getTopPlayers(10, "level");
    let content = "§e服务器等级排行榜 TOP 10\n\n";
    
    topPlayers.forEach((data, index) => {
        const medal = index === 0 ? "§6🥇" : index === 1 ? "§7🥈" : index === 2 ? "§c🥉" : `§f${index + 1}.`;
        content += `${medal} §b${data.name} §7- §a等级 ${data.level} §7(${data.exp} 经验)\n`;
    });
    
    // 显示玩家自己的排名
    const myRank = GwLevel.getPlayerRank(player, "level");
    content += `\n§d您的排名: §e第 ${myRank}`;
    
    form.setContent(content);
    form.addButton("§a关闭");
    
    player.sendForm(form, () => {});
}

getPlayerRank

排行榜
获取玩家在排行榜中的排名
JavaScript
// 获取等级排名
const levelRank = GwLevel.getPlayerRank(player, "level");

// 获取经验排名
const expRank = GwLevel.getPlayerRank(player, "exp");

// 获取总经验排名
const totalExpRank = GwLevel.getPlayerRank(player, "totalExp");

// 返回: Number - 排名(从1开始),如果玩家不存在返回 -1

getPlayersByLevelRange

查询
查询特定等级范围内的玩家
JavaScript
// 查询 20-30 级的玩家
const midLevelPlayers = GwLevel.getPlayersByLevelRange(20, 30);

// 查询 50 级以上的玩家
const highLevelPlayers = GwLevel.getPlayersByLevelRange(50, 100);

getLevelDistribution

统计
获取等级分布统计
JavaScript
const distribution = GwLevel.getLevelDistribution();
/* 返回格式:
{
    "1": 15,   // 1级有15个玩家
    "2": 8,    // 2级有8个玩家
    "3": 12,
    ...
}
*/

批量操作 API

批量处理玩家等级和经验的接口

batchSetLevel

批量
批量设置多个玩家的等级
JavaScript
const players = mc.getOnlinePlayers();
const success = GwLevel.batchSetLevel(players, 20);
// 返回: Boolean - 是否成功

batchAddExp

批量
批量为多个玩家添加经验
JavaScript
const players = mc.getOnlinePlayers();
const success = GwLevel.batchAddExp(players, 100);
// 返回: Boolean - 是否成功

addExpToAllOnline

批量
为所有在线玩家添加经验
JavaScript
// 全服奖励
GwLevel.addExpToAllOnline(500);
mc.broadcast("§a全服玩家获得 500 经验奖励!");
活动奖励系统
JavaScript
// 在线时长奖励系统
const onlineRewards = new Map();

mc.listen("onJoin", (player) => {
    onlineRewards.set(player.xuid, Date.now());
});

mc.listen("onLeft", (player) => {
    onlineRewards.delete(player.xuid);
});

// 每小时奖励
setInterval(() => {
    const now = Date.now();
    const onlinePlayers = [];
    
    mc.getOnlinePlayers().forEach(player => {
        const joinTime = onlineRewards.get(player.xuid);
        if (joinTime && now - joinTime >= 3600000) { // 1小时
            onlinePlayers.push(player);
            onlineRewards.set(player.xuid, now); // 重置时间
        }
    });
    
    if (onlinePlayers.length > 0) {
        GwLevel.batchAddExp(onlinePlayers, 200);
        onlinePlayers.forEach(player => {
            player.tell("§a在线奖励:+200 经验");
        });
    }
}, 60000); // 每分钟检查一次

等级相关工具方法

工具
计算等级和经验的辅助方法
JavaScript
// 获取指定等级所需的经验
const expForLevel10 = GwLevel.getExpForLevel(10);

// 计算累计到某等级需要的总经验
const totalExpToLevel50 = GwLevel.getTotalExpToLevel(50);

// 根据总经验计算等级
const result = GwLevel.getLevelByExp(5000);
// 返回: { level: 15, currentExp: 250 }

// 设置系统参数
GwLevel.setMaxLevel(200);           // 设置最大等级
GwLevel.setExpIncreaseRate(1.2);    // 设置经验增长率
GwLevel.setBaseExp(150);            // 设置基础经验值

经验事件

监听和处理经验相关的事件

beforeExpAdd

可拦截
玩家获得经验前触发,可以修改获得的经验值或阻止获取
JavaScript
GwLevel.on("beforeExpAdd", (data) => {
    // data.player - 玩家对象
    // data.xuid - 玩家 XUID
    // data.amount - 即将获得的经验值(可修改)
    // data.currentExp - 当前经验
    // data.currentLevel - 当前等级
    
    // 示例:VIP 双倍经验
    const player = data.player;
    if (player.hasTag("vip")) {
        data.amount *= 2;
        player.tell("§6VIP 双倍经验生效!");
    }
    
    // 返回 false 阻止获得经验
    return true;
});
经验加成系统
JavaScript
// 多重经验加成系统
GwLevel.on("beforeExpAdd", (data) => {
    const player = data.player;
    let multiplier = 1.0;
    
    // VIP 等级加成
    if (player.hasTag("vip1")) multiplier += 0.5;      // 50% 加成
    if (player.hasTag("vip2")) multiplier += 1.0;      // 100% 加成
    if (player.hasTag("vip3")) multiplier += 1.5;      // 150% 加成
    
    // 药水效果加成
    const effects = player.getAllEffects();
    if (effects.some(e => e.effectName === "luck")) {
        multiplier += 0.3; // 幸运效果 30% 加成
    }
    
    // 装备加成
    const helmet = player.getArmor().getItem(0);
    if (helmet && helmet.type === "minecraft:golden_helmet") {
        multiplier += 0.2; // 金头盔 20% 加成
    }
    
    // 应用总加成
    data.amount = Math.floor(data.amount * multiplier);
    
    if (multiplier > 1) {
        player.tell(`§a经验加成 x${multiplier.toFixed(1)} 生效!`);
    }
});

afterExpAdd

不可拦截
玩家获得经验后触发
JavaScript
GwLevel.on("afterExpAdd", (data) => {
    // data.player - 玩家对象
    // data.xuid - 玩家 XUID
    // data.addedAmount - 实际添加的经验值
    // data.currentExp - 当前经验
    // data.currentLevel - 当前等级
    // data.levelChanged - 是否发生了升级
    
    const player = data.player;
    
    // 经验获取提示
    player.tell(`§a+${data.addedAmount} 经验`, 5);
    
    // 播放音效
    player.playSound("random.orb");
});

beforeExpReduce

可拦截
玩家失去经验前触发
JavaScript
GwLevel.on("beforeExpReduce", (data) => {
    const player = data.player;
    
    // 死亡保护符
    if (player.hasTag("death_protection")) {
        player.tell("§a死亡保护符生效,免除经验损失!");
        player.removeTag("death_protection");
        return false; // 阻止经验减少
    }
    
    // 减少惩罚
    if (player.hasTag("reduce_penalty")) {
        data.amount = Math.floor(data.amount * 0.5); // 减半惩罚
    }
    
    return true;
});

beforeExpSet / afterExpSet

设置事件
设置经验值前后触发
JavaScript
// 设置前
GwLevel.on("beforeExpSet", (data) => {
    // 记录日志
    logger.log(`设置玩家 ${data.xuid} 经验: ${data.currentExp} -> ${data.amount}`);
    return true;
});

// 设置后
GwLevel.on("afterExpSet", (data) => {
    // data.previousExp - 之前的经验值
    // data.currentExp - 当前的经验值
    
    if (data.currentExp > data.previousExp) {
        const gained = data.currentExp - data.previousExp;
        data.player.tell(`§a经验增加 ${gained}`);
    }
});

等级事件

监听和处理等级变化相关的事件

onLevelUp

不可拦截
玩家升级时触发
JavaScript
GwLevel.on("onLevelUp", (data) => {
    const { player, xuid, newLevel, oldLevel } = data;
    
    // 升级特效
    mc.spawnParticle(player.pos, "minecraft:totem_particle");
    player.playSound("random.levelup");
    
    // 升级奖励
    const levelRewards = {
        10: { item: "minecraft:diamond", count: 5 },
        20: { item: "minecraft:netherite_ingot", count: 1 },
        30: { item: "minecraft:elytra", count: 1 },
        50: { item: "minecraft:beacon", count: 1 }
    };
    
    const reward = levelRewards[newLevel];
    if (reward) {
        player.giveItem(mc.newItem(reward.item, reward.count));
        player.tell(`§6恭喜达到 ${newLevel} 级!获得特殊奖励!`);
    }
    
    // 全服公告
    if (newLevel % 10 === 0) {
        mc.broadcast(`§e玩家 §b${player.name} §e升级到了 §6${newLevel} §e级!`);
    }
});
等级技能解锁系统
JavaScript
// 等级技能系统
const levelSkills = {
    5: { name: "快速挖掘", effect: "haste", level: 1 },
    10: { name: "生命提升", effect: "health_boost", level: 1 },
    15: { name: "力量增强", effect: "strength", level: 1 },
    20: { name: "抗性提升", effect: "resistance", level: 1 },
    25: { name: "速度提升", effect: "speed", level: 1 },
    30: { name: "跳跃强化", effect: "jump_boost", level: 2 },
    40: { name: "水下呼吸", effect: "water_breathing", level: 1 },
    50: { name: "夜视", effect: "night_vision", level: 1 }
};

GwLevel.on("onLevelUp", (data) => {
    const { player, newLevel } = data;
    const skill = levelSkills[newLevel];
    
    if (skill) {
        // 解锁技能
        player.addTag(`skill_${skill.effect}`);
        
        // 发送解锁消息
        player.setTitle(`§6技能解锁`, `§e${skill.name}`, 20, 60, 20);
        player.tell(`§a恭喜解锁新技能: §e${skill.name}`);
        
        // 应用永久效果
        applyPermanentEffect(player, skill.effect, skill.level);
    }
});

// 玩家加入时恢复技能效果
mc.listen("onJoin", (player) => {
    const level = parseInt(GwLevel.getPlayerLevel(player));
    
    for (const [reqLevel, skill] of Object.entries(levelSkills)) {
        if (level >= parseInt(reqLevel)) {
            applyPermanentEffect(player, skill.effect, skill.level);
        }
    }
});

beforeLevelChange / afterLevelChange

等级变更
等级改变前后触发(通过 setPlayerLevel)
JavaScript
GwLevel.on("beforeLevelChange", (data) => {
    const { player, xuid, newLevel, oldLevel } = data;
    
    // 防止等级倒退
    if (newLevel < oldLevel && !player.isOP()) {
        player.tell("§c等级不能倒退!");
        return false;
    }
    
    return true;
});

GwLevel.on("afterLevelChange", (data) => {
    const { player, newLevel, oldLevel } = data;
    
    if (newLevel > oldLevel) {
        player.tell(`§a等级提升至 ${newLevel} 级!`);
    } else {
        player.tell(`§c等级降至 ${newLevel}`);
    }
});

beforeLevelAdd / afterLevelAdd

等级增加
增加等级前后触发
JavaScript
GwLevel.on("beforeLevelAdd", (data) => {
    // 可以修改增加的等级数
    if (data.player.hasTag("double_level")) {
        data.levels *= 2;
        data.player.tell("§6双倍等级加成生效!");
    }
    return true;
});

beforeReset / afterReset

重置事件
玩家数据重置前后触发
JavaScript
GwLevel.on("beforeReset", (data) => {
    const { player, xuid } = data;
    
    // 保存重置前的数据
    const currentData = GwLevel.getPlayerData(xuid);
    player.setExtraData("lastLevelData", currentData);
    
    return true;
});

GwLevel.on("afterReset", (data) => {
    const { player, xuid } = data;
    player.tell("§c您的等级数据已被重置");
    
    // 给予补偿
    player.giveItem(mc.newItem("minecraft:experience_bottle", 64));
});

系统事件

系统级别的事件监听

onConfigUpdate

配置
配置更新时触发
JavaScript
GwLevel.on("onConfigUpdate", (data) => {
    const { oldConfig, newConfig } = data;
    
    // 检测关键配置变化
    if (oldConfig.maxLevel !== newConfig.maxLevel) {
        mc.broadcast(`§e最高等级已调整为 ${newConfig.maxLevel}`);
    }
    
    if (oldConfig.manualLevelUp !== newConfig.manualLevelUp) {
        const mode = newConfig.manualLevelUp ? "手动" : "自动";
        mc.broadcast(`§e升级模式已切换为${mode}升级`);
    }
    
    logger.log("配置已更新", newConfig);
});

beforeResetAll / afterResetAll

全局重置
重置所有玩家数据前后触发
JavaScript
GwLevel.on("beforeResetAll", (data) => {
    // 发送警告
    mc.broadcast("§4警告:服务器等级数据将在 10 秒后重置!");
    
    // 可以返回 false 阻止重置
    return true;
});

GwLevel.on("afterResetAll", (data) => {
    mc.broadcast("§a服务器等级数据已重置,所有玩家重新开始!");
    
    // 给所有在线玩家补偿
    mc.getOnlinePlayers().forEach(player => {
        player.giveItem(mc.newItem("minecraft:diamond", 10));
        player.tell("§a您获得了重置补偿");
    });
});

beforeRemove / afterRemove

数据删除
删除玩家数据前后触发
JavaScript
GwLevel.on("beforeRemove", (data) => {
    const { player, xuid } = data;
    
    // 记录删除日志
    logger.warn(`准备删除玩家数据: ${xuid}`);
    
    return true;
});

GwLevel.on("afterRemove", (data) => {
    logger.log(`玩家数据已删除: ${data.xuid}`);
});

配置选项

GwLevel 系统的配置参数说明

配置文件位置

配置文件位于 plugins/GwLevel/config/settings.json

配置项说明

配置项 类型 默认值 说明
baseExpToLevelUp Number 100 基础升级所需经验(1级升2级)
expIncreaseRate Number 1.1 每级升级经验增加倍率
maxLevel Number 100 最高等级限制
saveIntervalMinutes Number 5 自动保存间隔(分钟)
enableModSystem Boolean true 是否启用模块系统
manualLevelUp Boolean false 是否开启手动升级模式
PAPI Boolean true 是否注册 PAPI 变量

配置文件示例

JSON
{
    "baseExpToLevelUp": 100,
    "expIncreaseRate": 1.1,
    "maxLevel": 100,
    "saveIntervalMinutes": 5,
    "enableModSystem": true,
    "manualLevelUp": false,
    "PAPI": true
}

经验计算公式

升级所需经验计算公式:

数学公式
经验 = baseExpToLevelUp × expIncreaseRate^(等级-1)

例如:
- 1级升2级:100 × 1.1^0 = 100 经验
- 2级升3级:100 × 1.1^1 = 110 经验
- 3级升4级:100 × 1.1^2 = 121 经验
- 10级升11级:100 × 1.1^9 = 236 经验

PAPI 变量

如果启用了 PAPI 支持,将注册以下变量:

  • %GwLevel_level_current% - 当前等级
  • %GwLevel_level_exp% - 当前经验
  • %GwLevel_level_total% - 总经验
  • %GwLevel_level_required% - 升级所需经验
  • %GwLevel_level_progress% - 等级进度百分比
  • %GwLevel_level_rank% - 玩家排名

模块系统

创建自定义模块扩展 GwLevel 功能

模块目录结构

模块文件需要放置在 plugins/GwLevel/mod/ 目录下

目录结构
plugins/GwLevel/mod/
├── kill_reward.js      # 击杀奖励模块
├── level_shop.js       # 等级商店模块
├── skill_system.js     # 技能系统模块
└── daily_task.js       # 每日任务模块

模块开发基础

模块中可以直接使用 API 对象,无需导入

JavaScript - 模块模板
// 模块基础模板
// API 对象会自动注入,可直接使用

// 设置日志标题
logger.setTitle("GwLevel-模块名称");

// 模块初始化
logger.log("模块开始加载...");

// 使用 GwLevel API
API.on("onLevelUp", (data) => {
    // 处理升级事件
});

// 监听游戏事件
mc.listen("onJoin", (player) => {
    // 使用 API 获取玩家数据
    const level = API.getPlayerLevel(player);
    player.tell(`欢迎回来!您当前 ${level}`);
});

// 注册主菜单按钮
API.registerMainFormButton({
    text: "§6模块功能",
    image: "textures/items/diamond.png",
    callback: (player) => {
        // 按钮点击处理
    }
});

logger.log("模块加载完成");

完整模块示例:等级商店

一个完整的等级商店模块示例

JavaScript - level_shop.js
// 等级商店模块
logger.setTitle("GwLevel-等级商店");

// 商店物品配置
const shopItems = [
    {
        name: "§b钻石剑",
        item: "minecraft:diamond_sword",
        count: 1,
        levelCost: 10,
        expCost: 0,
        description: "§7一把锋利的钻石剑"
    },
    {
        name: "§5附魔之瓶×16",
        item: "minecraft:experience_bottle",
        count: 16,
        levelCost: 0,
        expCost: 500,
        description: "§7可以获得经验的神奇瓶子"
    },
    {
        name: "§6下界合金锭",
        item: "minecraft:netherite_ingot",
        count: 1,
        levelCost: 25,
        expCost: 1000,
        description: "§7最坚固的材料"
    },
    {
        name: "§d鞘翅",
        item: "minecraft:elytra",
        count: 1,
        levelCost: 50,
        expCost: 0,
        description: "§7让你翱翔天际"
    },
    {
        name: "§e信标",
        item: "minecraft:beacon",
        count: 1,
        levelCost: 30,
        expCost: 2000,
        description: "§7强大的增益效果"
    }
];

// 显示商店界面
function showLevelShop(player) {
    const form = mc.newSimpleForm();
    form.setTitle("§6等级商店");
    
    const playerLevel = parseInt(API.getPlayerLevel(player));
    const playerExp = parseInt(API.getPlayerExp(player));
    
    let content = `§e您当前的等级: §a${playerLevel} §e级\n`;
    content += `§e您当前的经验: §b${playerExp}\n\n`;
    content += "§7选择要购买的物品:";
    
    form.setContent(content);
    
    // 添加商品按钮
    shopItems.forEach(item => {
        let buttonText = item.name + "\n";
        
        if (item.levelCost > 0) {
            const canAffordLevel = playerLevel >= item.levelCost;
            const levelColor = canAffordLevel ? "§a" : "§c";
            buttonText += `${levelColor}需要等级: ${item.levelCost} `;
        }
        
        if (item.expCost > 0) {
            const canAffordExp = playerExp >= item.expCost;
            const expColor = canAffordExp ? "§b" : "§c";
            buttonText += `${expColor}需要经验: ${item.expCost}`;
        }
        
        form.addButton(buttonText);
    });
    
    form.addButton("§c关闭");
    
    player.sendForm(form, (player, id) => {
        if (id === null || id === shopItems.length) return;
        
        const selectedItem = shopItems[id];
        showPurchaseConfirm(player, selectedItem);
    });
}

// 显示购买确认
function showPurchaseConfirm(player, item) {
    const form = mc.newSimpleForm();
    form.setTitle("§6确认购买");
    
    let content = `§e物品: ${item.name}\n`;
    content += `§7${item.description}\n\n`;
    content += `§e数量: §f${item.count}\n`;
    
    if (item.levelCost > 0) {
        content += `§c消耗等级: §f${item.levelCost} 级\n`;
    }
    if (item.expCost > 0) {
        content += `§b消耗经验: §f${item.expCost} 点\n`;
    }
    
    content += "\n§e确认购买吗?";
    
    form.setContent(content);
    form.addButton("§a确认购买");
    form.addButton("§c取消");
    
    player.sendForm(form, (player, id) => {
        if (id === 0) {
            processPurchase(player, item);
        } else {
            showLevelShop(player);
        }
    });
}

// 处理购买
function processPurchase(player, item) {
    const playerLevel = parseInt(API.getPlayerLevel(player));
    const playerExp = parseInt(API.getPlayerExp(player));
    
    // 检查等级
    if (item.levelCost > 0 && playerLevel < item.levelCost) {
        player.tell(`§c等级不足!需要 ${item.levelCost}`);
        return;
    }
    
    // 检查经验
    if (item.expCost > 0 && playerExp < item.expCost) {
        player.tell(`§c经验不足!需要 ${item.expCost} 点经验`);
        return;
    }
    
    // 扣除消耗
    let success = true;
    
    if (item.levelCost > 0) {
        success = API.reducePlayerLevel(player, item.levelCost);
    }
    
    if (success && item.expCost > 0) {
        success = API.reducePlayerExp(player, item.expCost);
    }
    
    if (success) {
        // 给予物品
        const mcItem = mc.newItem(item.item, item.count);
        player.giveItem(mcItem);
        
        player.tell(`§a成功购买 ${item.name}§a!`);
        
        // 播放音效
        player.playSound("random.levelup");
        
        // 生成粒子效果
        mc.spawnParticle(player.pos, "minecraft:villager_happy");
    } else {
        player.tell("§c购买失败!");
    }
}

// 注册到主菜单
API.registerMainFormButton({
    text: "§6等级商店",
    image: "textures/items/emerald.png",
    callback: showLevelShop
});

// 命令快捷方式
mc.regPlayerCmd("levelshop", "打开等级商店", (player) => {
    showLevelShop(player);
});

logger.log("等级商店模块加载完成");

模块示例:每日任务系统

一个带有数据持久化的每日任务模块

JavaScript - daily_task.js
// 每日任务模块
logger.setTitle("GwLevel-每日任务");

// 任务配置
const dailyTasks = [
    {
        id: "kill_mobs",
        name: "怪物猎手",
        description: "击杀 20 只怪物",
        target: 20,
        expReward: 200,
        type: "kill"
    },
    {
        id: "mine_ores",
        name: "矿工",
        description: "挖掘 30 个矿石",
        target: 30,
        expReward: 150,
        type: "mine"
    },
    {
        id: "online_time",
        name: "在线达人",
        description: "在线 60 分钟",
        target: 3600000, // 毫秒
        expReward: 100,
        type: "online"
    }
];

// 玩家任务进度数据
let playerTasks = {};
const TASK_DATA_PATH = "plugins/GwLevel/data/daily_tasks.json";

// 加载任务数据
function loadTaskData() {
    try {
        if (File.exists(TASK_DATA_PATH)) {
            const content = File.readFrom(TASK_DATA_PATH);
            playerTasks = JSON.parse(content);
        }
    } catch (e) {
        logger.error("加载任务数据失败: " + e);
        playerTasks = {};
    }
}

// 保存任务数据
function saveTaskData() {
    try {
        File.writeTo(TASK_DATA_PATH, JSON.stringify(playerTasks, null, 2));
    } catch (e) {
        logger.error("保存任务数据失败: " + e);
    }
}

// 获取今天的日期键
function getTodayKey() {
    const now = new Date();
    return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
}

// 初始化玩家任务
function initPlayerTasks(xuid) {
    const today = getTodayKey();
    
    if (!playerTasks[xuid]) {
        playerTasks[xuid] = {};
    }
    
    if (!playerTasks[xuid][today]) {
        playerTasks[xuid][today] = {};
        dailyTasks.forEach(task => {
            playerTasks[xuid][today][task.id] = {
                progress: 0,
                completed: false,
                claimed: false
            };
        });
        saveTaskData();
    }
}

// 更新任务进度
function updateTaskProgress(player, taskId, amount = 1) {
    const xuid = player.xuid;
    const today = getTodayKey();
    
    initPlayerTasks(xuid);
    
    const task = dailyTasks.find(t => t.id === taskId);
    if (!task) return;
    
    const playerTask = playerTasks[xuid][today][taskId];
    if (playerTask.completed) return;
    
    playerTask.progress = Math.min(playerTask.progress + amount, task.target);
    
    if (playerTask.progress >= task.target) {
        playerTask.completed = true;
        player.tell(`§a任务完成: §e${task.name}`);
        player.playSound("random.levelup");
    }
    
    saveTaskData();
}

// 显示任务界面
function showDailyTasks(player) {
    const form = mc.newSimpleForm();
    form.setTitle("§6每日任务");
    
    const xuid = player.xuid;
    const today = getTodayKey();
    initPlayerTasks(xuid);
    
    let content = "§e完成每日任务获得经验奖励!\n\n";
    form.setContent(content);
    
    dailyTasks.forEach(task => {
        const playerTask = playerTasks[xuid][today][task.id];
        const progress = playerTask.progress;
        const isCompleted = playerTask.completed;
        const isClaimed = playerTask.claimed;
        
        let buttonText = `${task.name}\n`;
        buttonText += `§7${task.description}\n`;
        
        if (isClaimed) {
            buttonText += `§a已领取奖励`;
        } else if (isCompleted) {
            buttonText += `§e已完成 - 点击领取奖励`;
        } else {
            const percentage = Math.floor((progress / task.target) * 100);
            buttonText += `§f进度: ${progress}/${task.target} (${percentage}%)`;
        }
        
        form.addButton(buttonText);
    });
    
    form.addButton("§c关闭");
    
    player.sendForm(form, (player, id) => {
        if (id === null || id === dailyTasks.length) return;
        
        const task = dailyTasks[id];
        const playerTask = playerTasks[xuid][today][task.id];
        
        if (playerTask.completed && !playerTask.claimed) {
            // 领取奖励
            playerTask.claimed = true;
            API.addPlayerExp(player, task.expReward);
            player.tell(`§a领取成功!获得 §e${task.expReward} §a经验`);
            saveTaskData();
            
            // 重新显示界面
            showDailyTasks(player);
        }
    });
}

// 监听事件更新任务进度
mc.listen("onMobDie", (mob, source) => {
    if (source && source.isPlayer()) {
        const player = source.toPlayer();
        updateTaskProgress(player, "kill_mobs");
    }
});

mc.listen("onDestroyBlock", (player, block) => {
    const oreBlocks = [
        "minecraft:coal_ore",
        "minecraft:iron_ore",
        "minecraft:gold_ore",
        "minecraft:diamond_ore",
        "minecraft:emerald_ore",
        "minecraft:lapis_ore",
        "minecraft:redstone_ore",
        "minecraft:ancient_debris"
    ];
    
    if (oreBlocks.includes(block.type)) {
        updateTaskProgress(player, "mine_ores");
    }
});

// 在线时间追踪
const onlineTracking = new Map();

mc.listen("onJoin", (player) => {
    onlineTracking.set(player.xuid, Date.now());
    initPlayerTasks(player.xuid);
});

mc.listen("onLeft", (player) => {
    const xuid = player.xuid;
    const startTime = onlineTracking.get(xuid);
    
    if (startTime) {
        const onlineTime = Date.now() - startTime;
        updateTaskProgress(player, "online_time", onlineTime);
        onlineTracking.delete(xuid);
    }
});

// 定期更新在线时间
setInterval(() => {
    const now = Date.now();
    mc.getOnlinePlayers().forEach(player => {
        const startTime = onlineTracking.get(player.xuid);
        if (startTime) {
            const onlineTime = now - startTime;
            const today = getTodayKey();
            const playerTask = playerTasks[player.xuid]?.[today]?.["online_time"];
            
            if (playerTask && !playerTask.completed) {
                playerTask.progress = Math.min(onlineTime, 3600000);
                if (playerTask.progress >= 3600000) {
                    playerTask.completed = true;
                    player.tell("§a任务完成: §e在线达人");
                }
            }
        }
    });
    saveTaskData();
}, 60000); // 每分钟更新

// 注册到主菜单
API.registerMainFormButton({
    text: "§e每日任务",
    image: "textures/ui/book_writable_default.png",
    callback: showDailyTasks
});

// 加载数据
loadTaskData();
logger.log("每日任务模块加载完成");

表单集成

将自定义功能集成到 GwLevel 主表单

registerMainFormButton

表单 API
在 GwLevel 主菜单中注册自定义按钮
JavaScript
GwLevel.registerMainFormButton({
    text: "按钮文本",
    image: "图标路径", // 可选
    id: "唯一标识符", // 可选,自动生成
    requireOP: false, // 是否需要 OP 权限
    permissionCheck: (player) => { // 自定义权限检查
        return player.hasTag("vip");
    },
    callback: (player) => {
        // 按钮点击处理
    }
});
属性 类型 必填 说明
text String 按钮显示文本
callback Function 点击回调函数
image String 按钮图标路径
id String 按钮唯一标识符
requireOP Boolean 是否需要 OP 权限
permissionCheck Function 自定义权限检查函数

showMainForm

显示表单
手动显示 GwLevel 主表单
JavaScript
// 在其他地方调用主表单
GwLevel.showMainForm(player);

表单集成示例

完整的表单集成示例

JavaScript
// VIP 系统集成示例
const VipSystem = {
    // VIP 等级配置
    levels: {
        vip1: { name: "青铜VIP", expBonus: 1.5, color: "§7" },
        vip2: { name: "白银VIP", expBonus: 2.0, color: "§f" },
        vip3: { name: "黄金VIP", expBonus: 3.0, color: "§6" }
    },
    
    // 显示 VIP 界面
    showVipMenu(player) {
        const form = mc.newSimpleForm();
        form.setTitle("§6VIP 特权");
        
        let vipLevel = null;
        for (const [tag, info] of Object.entries(this.levels)) {
            if (player.hasTag(tag)) {
                vipLevel = info;
                break;
            }
        }
        
        let content = "";
        if (vipLevel) {
            content += `§a您当前的VIP等级: ${vipLevel.color}${vipLevel.name}\n`;
            content += `§e经验加成: x${vipLevel.expBonus}\n\n`;
        } else {
            content += "§c您还不是VIP会员\n\n";
        }
        
        content += "§7VIP特权:\n";
        content += "§7• 经验获取加成\n";
        content += "§7• 专属称号\n";
        content += "§7• 额外奖励\n";
        
        form.setContent(content);
        form.addButton("§a领取每日奖励");
        form.addButton("§e查看VIP商店");
        form.addButton("§c关闭");
        
        player.sendForm(form, (player, id) => {
            switch (id) {
                case 0:
                    this.claimDailyReward(player);
                    break;
                case 1:
                    this.showVipShop(player);
                    break;
            }
        });
    },
    
    // 领取每日奖励
    claimDailyReward(player) {
        // 检查是否已领取
        const today = new Date().toDateString();
        const lastClaim = player.getExtraData("vip_daily_claim");
        
        if (lastClaim === today) {
            player.tell("§c您今天已经领取过奖励了");
            return;
        }
        
        let expReward = 0;
        for (const [tag, info] of Object.entries(this.levels)) {
            if (player.hasTag(tag)) {
                expReward = 100 * info.expBonus;
                break;
            }
        }
        
        if (expReward > 0) {
            API.addPlayerExp(player, expReward);
            player.setExtraData("vip_daily_claim", today);
            player.tell(`§a成功领取VIP每日奖励: §e+${expReward} 经验`);
        } else {
            player.tell("§c只有VIP会员才能领取每日奖励");
        }
    },
    
    // VIP 商店
    showVipShop(player) {
        // 实现VIP商店逻辑
        player.tell("§eVIP商店功能开发中...");
    }
};

// 注册 VIP 按钮 - 只有 VIP 可见
API.registerMainFormButton({
    text: "§6VIP 特权",
    image: "textures/ui/icon_recipe_item.png",
    permissionCheck: (player) => {
        // 检查是否有任何 VIP 标签
        return player.hasTag("vip1") || 
               player.hasTag("vip2") || 
               player.hasTag("vip3");
    },
    callback: (player) => {
        VipSystem.showVipMenu(player);
    }
});

// 注册经验加成
API.on("beforeExpAdd", (data) => {
    const player = data.player;
    
    // 检查 VIP 等级
    for (const [tag, info] of Object.entries(VipSystem.levels)) {
        if (player.hasTag(tag)) {
            data.amount = Math.floor(data.amount * info.expBonus);
            break;
        }
    }
});

基础示例

常见功能的实现示例

击杀获得经验

JavaScript
// 基础击杀经验系统
mc.listen("onMobDie", (mob, source) => {
    if (!source || !source.isPlayer()) return;
    
    const player = source.toPlayer();
    let exp = 10; // 默认经验
    
    // 根据怪物类型给予不同经验
    const mobExp = {
        "minecraft:zombie": 15,
        "minecraft:skeleton": 20,
        "minecraft:creeper": 25,
        "minecraft:enderman": 30,
        "minecraft:witch": 35,
        "minecraft:blaze": 40,
        "minecraft:wither_skeleton": 50,
        "minecraft:wither": 500,
        "minecraft:ender_dragon": 1000
    };
    
    if (mobExp[mob.type]) {
        exp = mobExp[mob.type];
    }
    
    // 添加经验
    GwLevel.addPlayerExp(player, exp);
    
    // 显示获得的经验
    player.tell(`§a+${exp} 经验`, 5);
});

破坏方块经验

JavaScript
// 挖矿经验系统
mc.listen("onDestroyBlock", (player, block) => {
    const blockExp = {
        // 矿石类
        "minecraft:coal_ore": 5,
        "minecraft:deepslate_coal_ore": 5,
        "minecraft:iron_ore": 10,
        "minecraft:deepslate_iron_ore": 10,
        "minecraft:copper_ore": 8,
        "minecraft:deepslate_copper_ore": 8,
        "minecraft:gold_ore": 15,
        "minecraft:deepslate_gold_ore": 15,
        "minecraft:redstone_ore": 12,
        "minecraft:deepslate_redstone_ore": 12,
        "minecraft:emerald_ore": 50,
        "minecraft:deepslate_emerald_ore": 50,
        "minecraft:lapis_ore": 20,
        "minecraft:deepslate_lapis_ore": 20,
        "minecraft:diamond_ore": 100,
        "minecraft:deepslate_diamond_ore": 100,
        "minecraft:ancient_debris": 200,
        
        // 木头类(少量经验)
        "minecraft:oak_log": 1,
        "minecraft:birch_log": 1,
        "minecraft:spruce_log": 1,
        "minecraft:jungle_log": 1,
        "minecraft:acacia_log": 1,
        "minecraft:dark_oak_log": 1
    };
    
    const exp = blockExp[block.type];
    if (exp) {
        GwLevel.addPlayerExp(player, exp);
        
        // 在方块位置显示经验
        player.tell(`§a+${exp} 经验`, 5);
        
        // 生成经验球特效
        mc.spawnParticle(block.pos, "minecraft:totem_particle");
    }
});

等级称号系统

JavaScript
// 等级称号系统
const levelTitles = [
    { min: 1, max: 9, title: "§7新手", color: "§7" },
    { min: 10, max: 19, title: "§f学徒", color: "§f" },
    { min: 20, max: 29, title: "§a熟练", color: "§a" },
    { min: 30, max: 39, title: "§b专家", color: "§b" },
    { min: 40, max: 49, title: "§d大师", color: "§d" },
    { min: 50, max: 69, title: "§6宗师", color: "§6" },
    { min: 70, max: 89, title: "§c传奇", color: "§c" },
    { min: 90, max: 99, title: "§5史诗", color: "§5" },
    { min: 100, max: 100, title: "§4§l神话", color: "§4§l" }
];

// 获取玩家称号
function getPlayerTitle(level) {
    const title = levelTitles.find(t => level >= t.min && level <= t.max);
    return title || levelTitles[0];
}

// 更新玩家称号显示
function updatePlayerTitle(player) {
    const level = parseInt(GwLevel.getPlayerLevel(player));
    const title = getPlayerTitle(level);
    
    // 设置名称标签
    player.rename(`${title.color}[${title.title}] §r${player.realName}`);
}

// 玩家加入时更新称号
mc.listen("onJoin", (player) => {
    setTimeout(() => updatePlayerTitle(player), 1000);
});

// 升级时更新称号
GwLevel.on("onLevelUp", (data) => {
    const player = data.player;
    const newTitle = getPlayerTitle(data.newLevel);
    const oldTitle = getPlayerTitle(data.oldLevel);
    
    if (newTitle.title !== oldTitle.title) {
        player.tell(`§6恭喜!您获得了新称号: ${newTitle.color}${newTitle.title}`);
        mc.broadcast(`§e玩家 §b${player.name} §e获得了称号 ${newTitle.color}${newTitle.title}`);
    }
    
    updatePlayerTitle(player);
});

死亡惩罚系统

JavaScript
// 死亡惩罚配置
const deathPenalty = {
    expLossPercent: 10, // 损失 10% 经验
    protectionItems: [
        "minecraft:totem_of_undying", // 不死图腾
        "minecraft:golden_apple", // 金苹果保护
    ]
};

mc.listen("onPlayerDie", (player, source) => {
    // 检查保护物品
    const inventory = player.getInventory();
    let hasProtection = false;
    
    for (let i = 0; i < inventory.size; i++) {
        const item = inventory.getItem(i);
        if (item && deathPenalty.protectionItems.includes(item.type)) {
            hasProtection = true;
            // 消耗保护物品
            if (item.count > 1) {
                item.count--;
                inventory.setItem(i, item);
            } else {
                inventory.removeItem(i, 1);
            }
            break;
        }
    }
    
    if (hasProtection) {
        player.tell("§a死亡保护生效!免除经验损失");
        return;
    }
    
    // 计算经验损失
    const currentExp = parseInt(GwLevel.getPlayerExp(player));
    const expLoss = Math.floor(currentExp * deathPenalty.expLossPercent / 100);
    
    if (expLoss > 0) {
        GwLevel.reducePlayerExp(player, expLoss);
        player.tell(`§c死亡惩罚:损失 ${expLoss} 经验 (${deathPenalty.expLossPercent}%)`);
    }
});

高级用法

复杂功能的实现示例

等级权限系统

JavaScript
// 等级权限系统
const levelPermissions = {
    commands: {
        "/home": 5,
        "/back": 10,
        "/tpa": 15,
        "/fly": 30,
        "/god": 50
    },
    areas: {
        "vip_mine": 20,
        "end_portal": 25,
        "boss_arena": 40
    },
    items: {
        "minecraft:elytra": 30,
        "minecraft:netherite_sword": 25,
        "minecraft:totem_of_undying": 20
    }
};

// 命令权限检查
mc.listen("onPlayerCmd", (player, cmd) => {
    const cmdName = cmd.split(" ")[0].toLowerCase();
    const requiredLevel = levelPermissions.commands[cmdName];
    
    if (requiredLevel) {
        const playerLevel = parseInt(GwLevel.getPlayerLevel(player));
        if (playerLevel < requiredLevel) {
            player.tell(`§c此命令需要等级 ${requiredLevel} 才能使用!`);
            player.tell(`§e您当前等级: ${playerLevel}`);
            return false; // 阻止命令执行
        }
    }
});

// 区域进入权限(实际没有onMove事件,此处仅举例)
mc.listen("onMove", (player) => {
    const pos = player.blockPos;
    
    // 检查特殊区域(示例)
    if (pos.x >= 1000 && pos.x <= 1100 && 
        pos.z >= 1000 && pos.z <= 1100) {
        const requiredLevel = levelPermissions.areas["vip_mine"];
        const playerLevel = parseInt(GwLevel.getPlayerLevel(player));
        
        if (playerLevel < requiredLevel) {
            player.tell(`§c此区域需要等级 ${requiredLevel} 才能进入!`);
            // 传送回出生点
            player.teleport(mc.getWorldSpawn());
        }
    }
});

// 物品使用权限
mc.listen("onUseItem", (player, item) => {
    const requiredLevel = levelPermissions.items[item.type];
    
    if (requiredLevel) {
        const playerLevel = parseInt(GwLevel.getPlayerLevel(player));
        if (playerLevel < requiredLevel) {
            player.tell(`§c使用 ${item.name} 需要等级 ${requiredLevel}`);
            return false; // 阻止使用
        }
    }
});

转生系统

JavaScript
// 转生系统
const rebirthSystem = {
    maxRebirth: 10, // 最大转生次数
    requiredLevel: 100, // 转生需要的等级
    
    // 获取玩家转生次数
    getRebirthCount(player) {
        return player.getExtraData("rebirth_count") || 0;
    },
    
    // 设置转生次数
    setRebirthCount(player, count) {
        player.setExtraData("rebirth_count", count);
    },
    
    // 检查是否可以转生
    canRebirth(player) {
        const level = parseInt(GwLevel.getPlayerLevel(player));
        const rebirthCount = this.getRebirthCount(player);
        
        return level >= this.requiredLevel && rebirthCount < this.maxRebirth;
    },
    
    // 执行转生
    doRebirth(player) {
        if (!this.canRebirth(player)) {
            return false;
        }
        
        const rebirthCount = this.getRebirthCount(player);
        const newRebirthCount = rebirthCount + 1;
        
        // 重置等级
        GwLevel.resetPlayerLevel(player);
        
        // 增加转生次数
        this.setRebirthCount(player, newRebirthCount);
        
        // 给予转生奖励
        this.giveRebirthRewards(player, newRebirthCount);
        
        // 更新称号
        player.rename(`§6[转生${newRebirthCount}] §r${player.realName}`);
        
        // 全服公告
        mc.broadcast(`§6恭喜玩家 §e${player.name} §6完成第 §c${newRebirthCount} §6次转生!`);
        
        // 特效
        mc.spawnParticle(player.pos, "minecraft:huge_explosion_emitter");
        player.playSound("random.levelup");
        
        return true;
    },
    
    // 转生奖励
    giveRebirthRewards(player, rebirthCount) {
        // 基础奖励
        player.giveItem(mc.newItem("minecraft:nether_star", rebirthCount));
        
        // 转生特殊奖励
        const rewards = {
            1: { item: "minecraft:diamond_block", count: 10 },
            2: { item: "minecraft:netherite_ingot", count: 5 },
            3: { item: "minecraft:enchanted_golden_apple", count: 3 },
            5: { item: "minecraft:beacon", count: 1 },
            10: { item: "minecraft:dragon_egg", count: 1 }
        };
        
        const reward = rewards[rebirthCount];
        if (reward) {
            player.giveItem(mc.newItem(reward.item, reward.count));
            player.tell(`§a转生特殊奖励: ${reward.count}x ${reward.item}`);
        }
        
        // 永久增益标签
        player.addTag(`rebirth_${rebirthCount}`);
    },
    
    // 显示转生界面
    showRebirthMenu(player) {
        const form = mc.newSimpleForm();
        form.setTitle("§6转生系统");
        
        const level = parseInt(GwLevel.getPlayerLevel(player));
        const rebirthCount = this.getRebirthCount(player);
        
        let content = `§e当前转生次数: §c${rebirthCount}§7/${this.maxRebirth}\n`;
        content += `§e当前等级: §a${level}\n\n`;
        
        if (this.canRebirth(player)) {
            content += "§a您已满足转生条件!\n";
            content += "§7转生后将重置等级,但获得永久加成和奖励\n";
            form.addButton("§6确认转生");
        } else {
            if (level < this.requiredLevel) {
                content += `§c需要达到 ${this.requiredLevel} 级才能转生\n`;
            }
            if (rebirthCount >= this.maxRebirth) {
                content += "§c您已达到最大转生次数\n";
            }
        }
        
        content += "\n§b转生加成:\n";
        content += `§7• 经验获取 +${rebirthCount * 10}%\n`;
        content += `§7• 攻击力 +${rebirthCount * 5}%\n`;
        content += `§7• 生命值 +${rebirthCount * 2}\n`;
        
        form.setContent(content);
        form.addButton("§c关闭");
        
        player.sendForm(form, (player, id) => {
            if (id === 0 && this.canRebirth(player)) {
                this.showConfirmRebirth(player);
            }
        });
    },
    
    // 确认转生
    showConfirmRebirth(player) {
        const form = mc.newSimpleForm();
        form.setTitle("§c确认转生");
        form.setContent("§c警告:转生将重置您的等级为1级!\n§e但您将获得永久加成和丰厚奖励\n\n§6确定要转生吗?");
        form.addButton("§a确认转生");
        form.addButton("§c取消");
        
        player.sendForm(form, (player, id) => {
            if (id === 0) {
                this.doRebirth(player);
            }
        });
    }
};

// 注册转生按钮
API.registerMainFormButton({
    text: "§6转生系统",
    image: "textures/items/nether_star.png",
    callback: (player) => {
        rebirthSystem.showRebirthMenu(player);
    }
});

// 转生加成
API.on("beforeExpAdd", (data) => {
    const rebirthCount = rebirthSystem.getRebirthCount(data.player);
    if (rebirthCount > 0) {
        // 每次转生增加 10% 经验获取
        data.amount = Math.floor(data.amount * (1 + rebirthCount * 0.1));
    }
});

等级排位赛系统

JavaScript
// 等级排位赛系统
const rankingSystem = {
    seasons: {},
    currentSeason: null,
    
    // 创建新赛季
    createSeason(name, duration) {
        const season = {
            id: Date.now(),
            name: name,
            startTime: Date.now(),
            endTime: Date.now() + duration,
            participants: {},
            rewards: {
                1: { item: "minecraft:netherite_block", count: 10, exp: 5000 },
                2: { item: "minecraft:diamond_block", count: 20, exp: 3000 },
                3: { item: "minecraft:gold_block", count: 30, exp: 2000 },
                top10: { item: "minecraft:emerald_block", count: 10, exp: 1000 },
                participation: { item: "minecraft:iron_block", count: 5, exp: 500 }
            }
        };
        
        this.seasons[season.id] = season;
        this.currentSeason = season;
        
        // 保存赛季数据
        this.saveSeasonData();
        
        mc.broadcast(`§6新赛季 "§e${name}§6" 已开始!`);
        return season;
    },
    
    // 记录玩家赛季数据
    recordProgress(player) {
        if (!this.currentSeason) return;
        
        const xuid = player.xuid;
        const level = parseInt(GwLevel.getPlayerLevel(player));
        const totalExp = parseInt(GwLevel.getPlayerTotalExp(player));
        
        if (!this.currentSeason.participants[xuid]) {
            this.currentSeason.participants[xuid] = {
                name: player.name,
                startLevel: level,
                startExp: totalExp
            };
        }
        
        this.currentSeason.participants[xuid].currentLevel = level;
        this.currentSeason.participants[xuid].currentExp = totalExp;
        this.currentSeason.participants[xuid].progress = totalExp - this.currentSeason.participants[xuid].startExp;
    },
    
    // 获取赛季排行
    getSeasonRanking() {
        if (!this.currentSeason) return [];
        
        return Object.entries(this.currentSeason.participants)
            .map(([xuid, data]) => ({
                xuid,
                name: data.name,
                progress: data.progress || 0,
                level: data.currentLevel || 1
            }))
            .sort((a, b) => b.progress - a.progress);
    },
    
    // 结束赛季
    endSeason() {
        if (!this.currentSeason) return;
        
        const ranking = this.getSeasonRanking();
        
        mc.broadcast(`§6赛季 "§e${this.currentSeason.name}§6" 已结束!`);
        mc.broadcast("§e=== 赛季排行榜 ===");
        
        // 发放奖励
        ranking.forEach((player, index) => {
            const rank = index + 1;
            let reward = null;
            
            if (rank === 1) reward = this.currentSeason.rewards[1];
            else if (rank === 2) reward = this.currentSeason.rewards[2];
            else if (rank === 3) reward = this.currentSeason.rewards[3];
            else if (rank <= 10) reward = this.currentSeason.rewards.top10;
            else reward = this.currentSeason.rewards.participation;
            
            // 在线发放奖励
            const onlinePlayer = mc.getPlayer(player.xuid);
            if (onlinePlayer) {
                onlinePlayer.giveItem(mc.newItem(reward.item, reward.count));
                GwLevel.addPlayerExp(onlinePlayer, reward.exp);
                onlinePlayer.tell(`§a赛季奖励已发放!排名: 第${rank}`);
            } else {
                // 离线玩家记录奖励
                this.recordOfflineReward(player.xuid, reward, rank);
            }
            
            if (rank <= 3) {
                mc.broadcast(`§6第${rank}名: §e${player.name} §7- 获得经验 ${player.progress}`);
            }
        });
        
        this.currentSeason = null;
    },
    
    // 显示赛季界面
    showSeasonMenu(player) {
        const form = mc.newSimpleForm();
        form.setTitle("§6等级排位赛");
        
        if (!this.currentSeason) {
            form.setContent("§c当前没有进行中的赛季");
            form.addButton("§c关闭");
            player.sendForm(form, () => {});
            return;
        }
        
        const ranking = this.getSeasonRanking();
        const playerRank = ranking.findIndex(p => p.xuid === player.xuid) + 1;
        const timeLeft = this.currentSeason.endTime - Date.now();
        const daysLeft = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
        
        let content = `§e赛季: §b${this.currentSeason.name}\n`;
        content += `§e剩余时间: §a${daysLeft} 天\n`;
        content += `§e您的排名: §6第 ${playerRank || '未参与'} 名\n\n`;
        content += "§e=== TOP 10 ===\n";
        
        ranking.slice(0, 10).forEach((player, index) => {
            content += `§6${index + 1}. §b${player.name} §7- ${player.progress} 经验进度\n`;
        });
        
        form.setContent(content);
        form.addButton("§a查看奖励");
        form.addButton("§c关闭");
        
        player.sendForm(form, (player, id) => {
            if (id === 0) {
                this.showRewards(player);
            }
        });
    }
};

// 定期记录玩家进度
setInterval(() => {
    if (rankingSystem.currentSeason) {
        mc.getOnlinePlayers().forEach(player => {
            rankingSystem.recordProgress(player);
        });
    }
}, 60000); // 每分钟记录

// 自动检查赛季结束
setInterval(() => {
    if (rankingSystem.currentSeason && Date.now() >= rankingSystem.currentSeason.endTime) {
        rankingSystem.endSeason();
    }
}, 300000); // 每5分钟检查

最佳实践

开发 GwLevel 模块的建议和技巧

性能优化

1. 合理使用事件监听

JavaScript
// ❌ 不好的做法 - 在高频事件中进行复杂计算(实际没有onMove事件,此处仅举例)
mc.listen("onMove", (player) => {
    const level = parseInt(GwLevel.getPlayerLevel(player));
    const allData = GwLevel.getAllPlayerData();
    const ranking = GwLevel.getPlayerRank(player);
    // 每次移动都查询,性能开销大
});

// ✅ 好的做法 - 缓存数据,定期更新
const playerCache = new Map();

// 定期更新缓存
setInterval(() => {
    mc.getOnlinePlayers().forEach(player => {
        playerCache.set(player.xuid, {
            level: parseInt(GwLevel.getPlayerLevel(player)),
            rank: GwLevel.getPlayerRank(player)
        });
    });
}, 30000); // 30秒更新一次

// 使用缓存数据(实际没有onMove事件,此处仅举例)
mc.listen("onMove", (player) => {
    const cached = playerCache.get(player.xuid);
    if (cached) {
        // 使用缓存的数据
    }
});

2. 批量操作优化

JavaScript
// ❌ 不好的做法 - 循环中多次调用 API
mc.getOnlinePlayers().forEach(player => {
    GwLevel.addPlayerExp(player, 10);
    GwLevel.saveAllData(); // 每次都保存
});

// ✅ 好的做法 - 批量处理后统一保存
const players = mc.getOnlinePlayers();
GwLevel.batchAddExp(players, 10);
GwLevel.saveAllData(); // 只保存一次

错误处理

安全的 API 调用

JavaScript
// 安全的玩家数据访问
function safeGetPlayerData(player) {
    try {
        // 检查玩家有效性
        if (!player || !player.xuid) {
            logger.warn("无效的玩家对象");
            return null;
        }
        
        // 检查玩家是否存在
        if (!GwLevel.playerExists(player)) {
            logger.info(`玩家 ${player.name} 数据不存在,初始化中...`);
            return null;
        }
        
        const data = GwLevel.getPlayerData(player);
        
        // 验证数据完整性
        if (!data || typeof data.level !== 'number') {
            logger.error(`玩家 ${player.name} 数据损坏`);
            return null;
        }
        
        return data;
    } catch (error) {
        logger.error(`获取玩家数据失败: ${error.message}`);
        return null;
    }
}

// 使用示例
mc.listen("onJoin", (player) => {
    const data = safeGetPlayerData(player);
    if (data) {
        player.tell(`欢迎回来!您当前 ${data.level}`);
    }
});

数据持久化

模块数据存储

JavaScript
// 模块数据管理类
class ModuleDataManager {
    constructor(moduleName) {
        this.moduleName = moduleName;
        this.dataPath = `plugins/GwLevel/data/${moduleName}.json`;
        this.data = {};
        this.autoSaveInterval = null;
        
        this.load();
        this.enableAutoSave();
    }
    
    // 加载数据
    load() {
        try {
            if (File.exists(this.dataPath)) {
                const content = File.readFrom(this.dataPath);
                this.data = JSON.parse(content);
                logger.log(`${this.moduleName} 数据加载成功`);
            }
        } catch (e) {
            logger.error(`${this.moduleName} 数据加载失败: ${e}`);
            this.data = {};
        }
    }
    
    // 保存数据
    save() {
        try {
            File.writeTo(this.dataPath, JSON.stringify(this.data, null, 2));
            return true;
        } catch (e) {
            logger.error(`${this.moduleName} 数据保存失败: ${e}`);
            return false;
        }
    }
    
    // 启用自动保存
    enableAutoSave(interval = 300000) { // 5分钟
        this.autoSaveInterval = setInterval(() => {
            this.save();
        }, interval);
    }
    
    // 获取玩家数据
    getPlayerData(xuid, defaultValue = {}) {
        if (!this.data[xuid]) {
            this.data[xuid] = defaultValue;
        }
        return this.data[xuid];
    }
    
    // 设置玩家数据
    setPlayerData(xuid, data) {
        this.data[xuid] = data;
    }
    
    // 清理过期数据
    cleanup(daysInactive = 30) {
        const now = Date.now();
        const threshold = daysInactive * 24 * 60 * 60 * 1000;
        
        Object.keys(this.data).forEach(xuid => {
            const lastActive = this.data[xuid].lastActive || 0;
            if (now - lastActive > threshold) {
                delete this.data[xuid];
                logger.log(`清理过期数据: ${xuid}`);
            }
        });
        
        this.save();
    }
}

// 使用示例
const myModuleData = new ModuleDataManager("my_module");

// 存储数据
mc.listen("onJoin", (player) => {
    const data = myModuleData.getPlayerData(player.xuid);
    data.lastActive = Date.now();
    data.loginCount = (data.loginCount || 0) + 1;
});

模块化设计

创建可复用的模块

JavaScript
// 基础模块类
class GwLevelModule {
    constructor(config) {
        this.name = config.name;
        this.version = config.version;
        this.author = config.author;
        this.description = config.description;
        
        logger.setTitle(`GwLevel-${this.name}`);
        logger.log(`正在加载 ${this.name} v${this.version} by ${this.author}`);
        
        // 初始化
        this.init();
        
        // 注册事件
        this.registerEvents();
        
        // 注册命令
        this.registerCommands();
        
        // 注册表单
        if (config.showInMainMenu) {
            this.registerMainMenuButton();
        }
        
        logger.log(`${this.name} 加载完成`);
    }
    
    init() {
        // 子类实现
    }
    
    registerEvents() {
        // 子类实现
    }
    
    registerCommands() {
        // 子类实现
    }
    
    registerMainMenuButton() {
        // 子类实现
    }
}

// 实际模块示例
class LevelRewardsModule extends GwLevelModule {
    constructor() {
        super({
            name: "等级奖励",
            version: "1.0.0",
            author: "YourName",
            description: "等级提升奖励系统",
            showInMainMenu: true
        });
        
        this.rewards = {
            5: { items: ["minecraft:iron_ingot:10"], money: 100 },
            10: { items: ["minecraft:diamond:5"], money: 500 },
            20: { items: ["minecraft:netherite_ingot:1"], money: 1000 }
        };
    }
    
    registerEvents() {
        API.on("onLevelUp", (data) => {
            this.checkRewards(data.player, data.newLevel);
        });
    }
    
    checkRewards(player, level) {
        const reward = this.rewards[level];
        if (reward) {
            this.giveReward(player, reward);
        }
    }
    
    giveReward(player, reward) {
        // 给予物品
        reward.items.forEach(itemStr => {
            const [id, count] = itemStr.split(":");
            player.giveItem(mc.newItem(id, parseInt(count) || 1));
        });
        
        // 给予金钱
        if (reward.money && money) {
            money.add(player.xuid, reward.money);
        }
        
        player.tell(`§a恭喜达到 ${level} 级!获得奖励!`);
    }
    
    registerMainMenuButton() {
        API.registerMainFormButton({
            text: "§6等级奖励",
            image: "textures/items/emerald.png",
            callback: (player) => {
                this.showRewardsMenu(player);
            }
        });
    }
    
    showRewardsMenu(player) {
        const form = mc.newSimpleForm();
        form.setTitle("§6等级奖励");
        
        let content = "§e达到指定等级可获得奖励:\n\n";
        
        Object.entries(this.rewards).forEach(([level, reward]) => {
            content += `§a等级 ${level}:\n`;
            reward.items.forEach(item => {
                content += `  §7• ${item}\n`;
            });
            if (reward.money) {
                content += `  §7• ${reward.money} 金币\n`;
            }
            content += "\n";
        });
        
        form.setContent(content);
        form.addButton("§a关闭");
        
        player.sendForm(form, () => {});
    }
}

// 创建模块实例
new LevelRewardsModule();

开发建议

  • 使用语义化命名:变量和函数名应清晰表达其用途
  • 添加适当注释:复杂逻辑需要添加说明
  • 模块化设计:将功能分解为独立的模块
  • 错误处理:使用 try-catch 处理可能的异常
  • 性能优化:避免在高频事件中执行复杂操作
  • 数据验证:始终验证输入数据的有效性
  • 版本兼容:考虑不同版本的兼容性
  • 用户体验:提供清晰的反馈信息