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 对象并使用:
// 导入 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 文件:
// 击杀奖励模块
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
获取const level = GwLevel.getPlayerLevel(player);
// 返回: String - 玩家等级
参数 | 类型 | 说明 |
---|---|---|
player | Player | String | 玩家对象或 XUID |
setPlayerLevel
设置const success = GwLevel.setPlayerLevel(player, 10);
// 返回: Boolean - 是否成功
参数 | 类型 | 说明 |
---|---|---|
player | Player | String | 玩家对象或 XUID |
level | Number | 目标等级(1 - maxLevel) |
addPlayerLevel
操作const success = GwLevel.addPlayerLevel(player, 5);
// 返回: Boolean - 是否成功
// 监听玩家击杀事件,击杀 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
操作const success = GwLevel.reducePlayerLevel(player, 2);
// 返回: Boolean - 是否成功
levelUp
特殊const success = GwLevel.levelUp(player);
// 返回: Boolean - 是否成功升级
// 创建升级 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
获取const exp = GwLevel.getPlayerExp(player);
// 返回: String - 当前经验值
addPlayerExp
操作const success = GwLevel.addPlayerExp(player, 100);
// 返回: Boolean - 是否成功
// 破坏方块获得经验
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
操作const success = GwLevel.reducePlayerExp(player, 50);
// 返回: Boolean - 是否成功
// 死亡损失经验
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
设置const success = GwLevel.setPlayerExp(player, 500);
// 返回: Boolean - 是否成功
getPlayerTotalExp
获取const totalExp = GwLevel.getPlayerTotalExp(player);
// 返回: String - 总经验值
getExpRequiredForNextLevel
获取const required = GwLevel.getExpRequiredForNextLevel(player);
// 返回: String - 升级所需经验
// 显示等级进度条
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
重置const success = GwLevel.resetPlayerLevel(player);
// 返回: Boolean - 是否成功
resetAllPlayerData
危险const success = GwLevel.resetAllPlayerData();
// 返回: Boolean - 是否成功
removePlayerData
删除const success = GwLevel.removePlayerData(player);
// 返回: Boolean - 是否成功
getConfig / updateConfig
配置// 获取当前配置
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);
// 周末双倍经验活动
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
系统// 重新加载配置文件
GwLevel.reloadConfig();
// 手动保存所有玩家数据
GwLevel.saveAllData();
数据查询 API
查询玩家数据和排行榜的接口
playerExists
查询const exists = GwLevel.playerExists(player);
// 返回: Boolean - 是否存在
getPlayerData
查询const data = GwLevel.getPlayerData(player);
/* 返回:
{
name: "PlayerName",
level: 10,
exp: 250,
totalExp: 1500,
lastOnline: 1234567890000
}
*/
getAllPlayerData
查询const allData = GwLevel.getAllPlayerData();
// 返回: Object - 所有玩家数据的映射表 { xuid: playerData }
getPlayerLevelProgress
查询const progress = GwLevel.getPlayerLevelProgress(player);
// 返回: String - 进度百分比 (0-100)
getTopPlayers
排行榜// 获取等级排行榜前10名
const topByLevel = GwLevel.getTopPlayers(10, "level");
// 获取总经验排行榜前10名
const topByExp = GwLevel.getTopPlayers(10, "totalExp");
/* 返回格式:
[
{
xuid: "1234567890",
name: "Player1",
level: 50,
exp: 1200,
totalExp: 45000
},
...
]
*/
// 创建排行榜展示
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
排行榜// 获取等级排名
const levelRank = GwLevel.getPlayerRank(player, "level");
// 获取经验排名
const expRank = GwLevel.getPlayerRank(player, "exp");
// 获取总经验排名
const totalExpRank = GwLevel.getPlayerRank(player, "totalExp");
// 返回: Number - 排名(从1开始),如果玩家不存在返回 -1
getPlayersByLevelRange
查询// 查询 20-30 级的玩家
const midLevelPlayers = GwLevel.getPlayersByLevelRange(20, 30);
// 查询 50 级以上的玩家
const highLevelPlayers = GwLevel.getPlayersByLevelRange(50, 100);
getLevelDistribution
统计const distribution = GwLevel.getLevelDistribution();
/* 返回格式:
{
"1": 15, // 1级有15个玩家
"2": 8, // 2级有8个玩家
"3": 12,
...
}
*/
批量操作 API
批量处理玩家等级和经验的接口
batchSetLevel
批量const players = mc.getOnlinePlayers();
const success = GwLevel.batchSetLevel(players, 20);
// 返回: Boolean - 是否成功
batchAddExp
批量const players = mc.getOnlinePlayers();
const success = GwLevel.batchAddExp(players, 100);
// 返回: Boolean - 是否成功
addExpToAllOnline
批量// 全服奖励
GwLevel.addExpToAllOnline(500);
mc.broadcast("§a全服玩家获得 500 经验奖励!");
// 在线时长奖励系统
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); // 每分钟检查一次
等级相关工具方法
工具// 获取指定等级所需的经验
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
可拦截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;
});
// 多重经验加成系统
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
不可拦截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
可拦截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
设置事件// 设置前
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
不可拦截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级!`);
}
});
// 等级技能系统
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
等级变更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
等级增加GwLevel.on("beforeLevelAdd", (data) => {
// 可以修改增加的等级数
if (data.player.hasTag("double_level")) {
data.levels *= 2;
data.player.tell("§6双倍等级加成生效!");
}
return true;
});
beforeReset / afterReset
重置事件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
配置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
全局重置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
数据删除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 变量 |
配置文件示例
{
"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 对象,无需导入
// 模块基础模板
// 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("模块加载完成");
完整模块示例:等级商店
一个完整的等级商店模块示例
// 等级商店模块
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("等级商店模块加载完成");
模块示例:每日任务系统
一个带有数据持久化的每日任务模块
// 每日任务模块
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
表单 APIGwLevel.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.showMainForm(player);
表单集成示例
完整的表单集成示例
// 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;
}
}
});
基础示例
常见功能的实现示例
击杀获得经验
// 基础击杀经验系统
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);
});
破坏方块经验
// 挖矿经验系统
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");
}
});
等级称号系统
// 等级称号系统
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);
});
死亡惩罚系统
// 死亡惩罚配置
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}%)`);
}
});
高级用法
复杂功能的实现示例
等级权限系统
// 等级权限系统
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; // 阻止使用
}
}
});
转生系统
// 转生系统
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));
}
});
等级排位赛系统
// 等级排位赛系统
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. 合理使用事件监听
// ❌ 不好的做法 - 在高频事件中进行复杂计算(实际没有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. 批量操作优化
// ❌ 不好的做法 - 循环中多次调用 API
mc.getOnlinePlayers().forEach(player => {
GwLevel.addPlayerExp(player, 10);
GwLevel.saveAllData(); // 每次都保存
});
// ✅ 好的做法 - 批量处理后统一保存
const players = mc.getOnlinePlayers();
GwLevel.batchAddExp(players, 10);
GwLevel.saveAllData(); // 只保存一次
错误处理
安全的 API 调用
// 安全的玩家数据访问
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} 级`);
}
});
数据持久化
模块数据存储
// 模块数据管理类
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;
});
模块化设计
创建可复用的模块
// 基础模块类
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 处理可能的异常
- 性能优化:避免在高频事件中执行复杂操作
- 数据验证:始终验证输入数据的有效性
- 版本兼容:考虑不同版本的兼容性
- 用户体验:提供清晰的反馈信息