[MD]
# MeowAchievement — Java 版成就系统插件(C++ 原生 · 自动事件触发 · 成就包 · LSE 自定义触发器)
> 一款为 BDS 服务器打造的成就(进度)系统插件,完整复刻 Java 版 advancements 体验:约 126 项内置成就自动监听游戏事件触发,支持成就包、GUI 成就树、Toast 通知、全服广播、PAPI 占位符以及 LSE 脚本自定义触发器。当前版本 1.0.0。
## 一、插件简介
MeowAchievement 是一个基于 C++ 开发的 MCBE 成就系统插件。与基岩版原生平板成就不同,它将 Java 版的「进度树(advancements)」体验完整搬到了基岩版:玩家可以在聊天栏用命令查看进度,在 GUI 成就树中浏览五大分支,达成时弹出 Toast 通知并向全服广播。
插件核心由四个部分组成:
- **内置成就**:约 126 项成就,基于 Minecraft Wiki 最新进度树,覆盖故事 / 下界 / 末地 / 冒险 / 农牧业五大分支,通过事件监听**自动触发**,无需任何配置即可开箱即用。
- **成就包机制**:类似 Java 版数据包,服务器管理员只需把成就包目录丢进 `advancement_packs/` 即可加载一组预定义成就。
- **LSE 触发器**:对于内置事件无法覆盖的复杂条件,可通过 LSE(JavaScript)脚本编写自定义触发逻辑,由插件在 tick 中调度评估。
- **RemoteCall API**:对外暴露 27 个 API,涵盖成就注册、触发、进度、查询、管理(增删改查)与页面管理,供 ZXDash 等面板插件集成。
## 二、核心特性
### 成就体验
- **Java 版进度树**:五大分支(故事/下界/末地/冒险/农牧业)父子层级,父成就未解锁时子成就隐藏,还原原版探索感
- **三种成就框架**:`task`(普通)/ `goal`(目标)/ `challenge`(挑战),对应不同 Toast 标题颜色与稀有度
- **Toast 通知**:达成时右上角弹出成就 Toast,标题/内容模板可自定义,支持 § 颜色代码
- **全服广播**:达成时公屏广播,模板可自定义,可按成就单独开关
- **解锁音效**:可配置音效名、音量、音调
- **隐藏成就**:支持隐藏成就,达成前不在列表中显示
- **进度型成就**:支持 `maxProgress` 多步进度(如「击杀 41 种敌对生物」),可逐步累积
### 触发机制
- **自动事件监听**:内置成就通过监听挖掘、击杀、进入维度、物品拾取、信标激活、繁殖等游戏事件自动触发
- **异步检查器**:重计算任务在工作线程执行,主线程只消费结果,避免卡服
- **LSE 自定义触发器**:通过 JavaScript 编写任意触发条件,插件按玩家轮转调度评估,单次评估异常自动捕获不会崩服
- **第三方主动触发**:C++ 插件可通过 RemoteCall 的 `trigger` / `setProgress` / `addProgress` 主动驱动成就
### 可扩展性
- **成就包**:Java 数据包风格的目录结构与 JSON 格式,丢入目录即加载
- **RemoteCall API**:27 个 API,支持成就/页面/位置/触发器的完整增删改查,供面板与第三方插件集成
- **PAPI 占位符**:注册 3 个占位符,可在任何支持 PAPI 的插件中显示成就进度
- **资源包自动释放**:可选将内置资源包释放到 `worlds/<level>/resource_packs/`,由 BDS 原生扫描下载
### 兼容性
- 基于 LeviLamina 框架,C++ 原生插件
- 通过 LegacyRemoteCall 跨语言导出 API
- 自带 MeowPAPI 部署能力(load 阶段自动释放 MeowPAPI.dll 到 `plugins/MeowPAPI/`,无需依赖 MeowSidebar)
- 兼容 [URL='https://www.minebbs.com/resources/zxdraw.15284/']Zxdash管理面板[/URL](提供成就树拖拽、自定义成就编辑)
## 三、安装方法
### 环境要求
- LeviLamina 26.10.3 或更高版本
- LegacyRemoteCall(依赖,自动加载)
- MeowPAPI(由插件在 load 阶段自动释放到 `plugins/MeowPAPI/`,无需单独安装)
- LegacyScriptEngine(LSE,可选,用于运行 JS 自定义触发器)
### 目录结构
```
plugins/MeowAchievement/
├── MeowAchievement.dll # 插件主体
├── MeowAchievement_EmbeddedRP.mcpack# 内置资源包(音效/图标)
├── manifest.json # 插件清单
├── API.md # 完整 API 文档
├── 成就.md # Java 版进度树参考
├── 事件状态.md # 事件监听状态说明
├── data/
│ ├── config.json # 主配置(广播/Toast/音效/开关)
│ ├── custom_achievements.json # 自定义成就(ZXDash/API 创建)
│ └── players/ # 玩家数据目录
│ └── <xuid>.json
├── advancement_packs/ # 成就包目录(自动加载)
│ └── <成就包名>/
│ ├── manifest.json
│ └── data/<命名空间>/advancement/*.json
└── scripts/
└── lse_trigger_example/ # LSE 触发器示例
```
## 四、配置详解
### 4.1 config.json 完整示例
```json
{
"broadcastTemplate": "{player} 取得了进度 {achievement}",
"enableAdvancementPacks": true,
"enableResourcePack": false,
"enableBroadcast": true,
"enableSound": true,
"enableToast": true,
"soundName": "ui.toast.challenge_complete",
"soundPitch": 1.0,
"soundVolume": 1.0,
"toastContentTemplate": "§f§l{achievement}§r\n§7{description}",
"toastTitleChallenge": "§d挑战完成",
"toastTitleGoal": "§6目标完成",
"toastTitleTask": "§a成就完成"
}
```
### 4.2 字段说明
#### 全局功能开关
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `enableBroadcast` | bool | `true` | 全局是否启用公屏广播 |
| `enableToast` | bool | `true` | 全局是否启用 Toast 通知 |
| `enableSound` | bool | `true` | 全局是否启用解锁音效 |
| `enableAdvancementPacks` | bool | `true` | 是否启用成就包加载 |
| `enableResourcePack` | bool | `false` | 是否将内置资源包释放到 `worlds/<level>/resource_packs/` |
> `enableResourcePack` 启用后,插件会在 BDS 加载存档前将资源包释放到对应世界的 `resource_packs/` 目录,由 BDS 原生扫描并自动推送给客户端下载,无需 Hook 或运行时注册。
#### 消息模板
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `broadcastTemplate` | string | `"{player} 取得了进度 {achievement}"` | 全服广播模板 |
| `toastTitleTask` | string | `"§a成就完成"` | task 类 Toast 标题 |
| `toastTitleGoal` | string | `"§6目标完成"` | goal 类 Toast 标题 |
| `toastTitleChallenge` | string | `"§d挑战完成"` | challenge 类 Toast 标题 |
| `toastContentTemplate` | string | `"§f§l{achievement}§r\n§7{description}"` | Toast 内容模板 |
#### 音效配置
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `soundName` | string | `"ui.toast.challenge_complete"` | 解锁音效名称 |
| `soundVolume` | float | `1.0` | 音量 |
| `soundPitch` | float | `1.0` | 音调 |
### 4.3 模板变量
可在 `broadcastTemplate` 和 `toastContentTemplate` 中使用:
| 占位符 | 说明 |
|--------|------|
| `{player}` | 玩家名 |
| `{achievement}` | 成就名(广播中带颜色与 `[]`,Toast 中为纯文本) |
| `{description}` | 成就描述 |
支持 Minecraft 标准 § 颜色代码(`§a` 绿 / `§6` 金 / `§c` 红 / `§d` 粉 / `§e` 黄 / `§f` 白 等)。
### 4.4 单成就通知覆盖
`config.json` 还支持 `perAchievementNotify` 字段,对单个成就覆盖全局通知开关(优先级:单成就覆盖 > 全局默认):
```json
"perAchievementNotify": {
"husbandry/breed_an_animal": {
"broadcast": false,
"toast": true,
"sound": false
},
"story/mine_diamonds": {
"broadcast": true
}
}
```
每个成就可单独配置 `broadcast` / `toast` / `sound`,留空的项继承全局设置。修改后执行 `/ach reload` 生效。
## 五、命令系统
玩家可通过 `/ach` 或 `/achievement`(别名)查看与管理成就。
### 5.1 玩家命令
| 命令 | 说明 |
|------|------|
| `/ach` | 显示帮助与个人进度概览(已解锁/总数/百分比) |
| `/ach list` | 查看可见的未完成成就(按分支 tab 分组,隐藏成就与父成就未解锁的子成就不显示) |
| `/ach done` | 查看已完成的成就 |
| `/ach reset` | 重置自己的全部成就进度 |
### 5.2 管理员命令
| 命令 | 权限 | 说明 |
|------|------|------|
| `/ach reload` | OP(控制台也可) | 重载 config.json、custom_achievements.json 和玩家数据 |
| `/ach grant <player> <id>` | OP | 授予指定玩家指定成就(绕过父成就检查) |
### 5.3 分支分组(/ach list)
`/ach list` 会按成就 ID 前缀自动分组显示,内置分支顺序与颜色:
| 分支 key | 显示名 | 颜色 |
|----------|--------|------|
| `story` | 故事 | §b 青 |
| `nether` | 下界 | §c 红 |
| `end` | 末地 | §d 粉 |
| `adventure` | 冒险 | §a 绿 |
| `husbandry` | 农牧业 | §6 金 |
| `meme` | 梗成就 | §e 黄 |
> 成就 ID 支持两种分隔符:内置成就用 `/`(如 `adventure/kill_a_mob`),成就包成就用 `:`(如 `meme:rotten_flesh`)。
### 5.4 /ach reload 详细说明
执行后会重新加载:
1. `data/config.json` — 全局配置 + `perAchievementNotify`
2. `data/custom_achievements.json` — 自定义成就定义
3. 玩家数据:先保存当前在线玩家进度,清空缓存,再从 `data/players/*.json` 重新加载
**不会重新加载:**
- 内置成就定义(启动时注册一次)
- 成就包(`advancement_packs/` 目录,只在服务器启动时加载一次)
- 已注册的 LSE 触发器评估器(需重启服务器或重新执行 LSE 脚本的注册代码)
## 六、内置成就
### 6.1 五大分支
MeowAchievement 内置约 126 项成就,基于 Minecraft Wiki 最新 Java 版进度树,覆盖五大分支:
| 分支 | 根成就 | 内容概述 |
|------|--------|----------|
| 故事 `story` | `story/root`(拥有工作台) | 石器时代 → 获得升级 → 钻石 → 附魔师 → 末地入门 |
| 下界 `nether` | `nether/root`(进入下界) | 凋灵、信标、堡垒遗迹、下界合金、药水、炽足兽 |
| 末地 `end` | `end/root`(进入末地) | 击杀末影龙、龙蛋、末地城、鞘翅、折跃门 |
| 冒险 `adventure` | `adventure/root`(杀死/被杀) | 怪物猎人、狙击手、试炼密室、重锤、望远镜、纹饰 |
| 农牧业 `husbandry` | `husbandry/root`(食用食物) | 繁殖、钓鱼、美西螈、嗅探兽、蛙明灯、狼铠、均衡饮食 |
### 6.2 自动触发机制
内置成就**无需任何配置**,由插件监听游戏事件自动触发,包括但不限于:
- **物品栏变更**:拾取工作台、钻石、铁锭、下界合金装备等
- **维度切换**:进入下界 / 末地
- **实体死亡**:击杀末影龙、恶魂、怪物列表中的生物
- **方块交互**:信标激活、磁石使用、床、唱片机
- **状态效果**:同时拥有多种药水效果
- **结构进入**:进入堡垒遗迹、下界要塞、末地城、试炼密室
- **特殊行为**:望远镜观察实体、盾牌格挡弹射物、附魔、锻造纹饰
重计算类条件(如「同时拥有 34 种状态效果」)由异步检查器在工作线程处理,主线程只消费结果。
> 完整的进度树与触发条件可参考插件目录下的 `成就.md` 与 `事件状态.md`。
## 七、成就包机制
MeowAchievement 支持通过「成就包」加载一组预定义成就,采用 Java 版数据包风格的目录结构与 JSON 格式。
### 7.1 目录结构
```
plugins/MeowAchievement/advancement_packs/
<成就包名>/
manifest.json (必需)
data/
<命名空间>/
advancement/
<进度文件>.json
resources/ (可选)
```
### 7.2 manifest.json
```json
{
"name": "成就包名称",
"description": "描述",
"version": [1, 0, 0],
"namespace": "myns",
"author": "作者"
}
```
### 7.3 advancement JSON
```json
{
"display": {
"icon": "textures/items/example",
"title": "成就名称",
"description": "成就描述",
"frame": "task",
"hidden": false
},
"parent": "myns:parent_id",
"criteria": {
"trigger": {
"trigger": "custom:trigger_name",
"conditions": {}
}
},
"rewards": {
"experience": 10
}
}
```
| display.frame | 含义 |
|---------------|------|
| `task` | 普通成就 |
| `goal` | 目标成就 |
| `challenge` | 挑战成就 |
`criteria.trigger` 为 `custom:xxx` 的成就由第三方插件通过 RemoteCall `trigger` API 主动触发;若使用 LSE 评估器,则在 `custom_achievements.json` 中将 `triggerType` 设为 `lse`。
> 成就包只在服务器启动时加载一次,修改后需重启服务器生效(`/ach reload` 不会重载成就包)。
## 八、RemoteCall API
所有 API 通过 RemoteCall 导出,命名空间为 `MeowAchievement`。完整签名与字段说明详见插件目录下的 `API.md`,此处给出分类概览。
### 8.1 基础 API(成就注册与触发)
| 函数 | 说明 |
|------|------|
| `registerAchievement(...)` | 注册基础成就 |
| `registerAchievementEx(...)` | 注册带图标/来源包/奖励的完整成就 |
| `trigger(xuid, id)` | 触发成就(检查父成就要求) |
| `setProgress(xuid, id, progress)` | 设置进度(达 maxProgress 自动解锁) |
| `addProgress(xuid, id, amount)` | 增加进度 |
| `grant(xuid, id)` | 授予成就(绕过父成就检查,管理员用) |
| `revoke(xuid, id)` | 撤销成就 |
| `resetPlayer(xuid)` | 重置玩家全部成就 |
| `reload()` | 重载配置/自定义成就/玩家数据 |
### 8.2 查询 API
| 函数 | 说明 |
|------|------|
| `isUnlocked(xuid, id)` | 查询是否已解锁 |
| `getProgress(xuid, id)` | 获取当前进度 |
| `getTotalUnlocked(xuid)` | 获取已解锁总数 |
| `getAllAchievements()` | 获取所有成就(JSON) |
| `getAchievement(id)` | 获取单个成就定义(JSON) |
| `getPlayerAchievements(xuid)` | 获取玩家成就进度(JSON) |
| `getPlayerStats(xuid)` | 获取玩家统计 `{total, unlocked, percentage}` |
### 8.3 管理 API(ZXDash 调用)
| 函数 | 说明 |
|------|------|
| `adminUpdatePosition(id, posX, posY)` | 更新成就树位置 |
| `adminCreateAchievement(jsonStr)` | 创建自定义成就 |
| `adminDeleteAchievement(id)` | 删除自定义成就 |
| `adminUpdateAchievement(jsonStr)` | 更新成就字段 |
### 8.4 页面管理 API
| 函数 | 说明 |
|------|------|
| `getAllPages()` | 获取所有页面(内置 + 自定义) |
| `adminCreatePage(jsonStr)` | 创建页面 |
| `adminDeletePage(id)` | 删除页面 |
| `adminUpdatePage(jsonStr)` | 更新页面信息 |
| `adminSetAchievementPage(achId, pageId)` | 设置成就所属页面 |
### 8.5 LSE 触发器 API
| 函数 | 说明 |
|------|------|
| `registerLseTriggerEvaluator(lseNamespace, funcName)` | 注册 LSE 评估器 |
| `hasLseTriggerEvaluator()` | 查询是否已注册评估器 |
**调用示例(JavaScript)**:
```javascript
const trigger = ll.import("MeowAchievement", "trigger");
trigger(xuid, "custom/my_achievement");
```
## 九、PAPI 占位符
MeowAchievement 通过 MeowPAPI 注册了以下 PlaceholderAPI 占位符,可在任何支持 PAPI 的插件(如 MeowSidebar 侧边栏)中使用:
| 占位符 | 类型 | 说明 |
|--------|------|------|
| `%ach_total%` | Server | 服务器总成就数 |
| `%ach_unlocked%` | Player | 玩家已解锁成就数 |
| `%ach_progress%` | Player | 玩家完成百分比(如 `"24%"`) |
**侧边栏示例**:
```json
"§g成就: §a{ach_unlocked}§g/§e{ach_total} §7({ach_progress})"
```
## 十、LSE 触发器集成
对于内置事件无法覆盖的复杂条件,可通过 LSE(JavaScript)脚本编写自定义触发逻辑。
### 10.1 工作原理
```
┌─────────────────────────┐ ┌─────────────────────────┐
│ MeowAchievement (C++) │ │ LSE 脚本 (Node.js) │
│ 1. tick 中遍历在线玩家 │ │ 1. exportAs 评估器函数 │
│ 2. 对每个 triggerType │ ───────▶│ (xuid, achId, │
│ ="lse" 的成就 │ │ triggerDef) -> bool│
│ 3. 调用评估器函数 │ ◀───────│ 2. 解析 triggerDef │
│ 4. 返回 true 则触发 │ │ 3. 返回 true/false │
└─────────────────────────┘ └─────────────────────────┘
```
### 10.2 集成步骤
1. 在 LSE 脚本中导出评估器函数:
```javascript
RemoteCall.exportAs("MyLseNs", "evaluateTrigger", (xuid, achId, triggerDef) => {
const def = JSON.parse(triggerDef);
const pl = mc.getPlayerByXuid(xuid);
if (!pl) return false;
if (def.type === "dimension") return pl.dimid === def.dimId;
return false;
});
```
2. 注册到 MeowAchievement:
```javascript
const register = ll.import("MeowAchievement", "registerLseTriggerEvaluator");
register("MyLseNs", "evaluateTrigger");
```
3. 创建 `triggerType: "lse"` 的成就(通过 `adminCreateAchievement` API 或直接编辑 `custom_achievements.json`),`triggerDef` 为任意 JSON 字符串,由评估器自行解析。
### 10.3 内置示例支持的 triggerDef 类型
插件自带示例(`scripts/lse_trigger_example/`)演示了以下类型:
| `type` | 参数 | 说明 |
|--------|------|------|
| `dimension` | `dimId` | 进入指定维度(0/1/2) |
| `health` | `threshold` | 生命值低于阈值 |
| `biome` | `biomeId` | 处于指定生物群系 |
| `y_above` / `y_below` | `y` | Y 坐标高于/低于阈值 |
| `held_item` | `itemId` | 手持指定物品 |
### 10.4 性能说明
- 评估器在主线程 tick 中调用,通过玩家轮转(每 tick 仅处理 1/4 在线玩家)分散负载
- 单次评估应快速返回(< 10ms),避免卡服
- 评估器抛出的异常会被捕获并视为 `false`,不会导致服务器崩溃
## 十一、适用场景
### 推荐使用 MeowAchievement
- 想在基岩版还原 Java 版进度树体验,给玩家长期探索目标
- 需要自动监听游戏事件触发成就,开箱即用无需写脚本
- 服务器有自定义玩法,需要用 LSE 脚本编写复杂触发条件
- 希望通过 ZXDash 面板可视化编辑成就树、拖拽排版
- 需要在侧边栏/计分板展示玩家成就完成度
### 不推荐使用 MeowAchievement
- 只需要基岩版原生平板成就(无需额外插件,原版自带)
- 不希望玩家通过命令查看/重置成就(本插件玩家可 `/ach reset` 重置自己进度)
- 服务器未安装 LegacyRemoteCall 依赖
## 十二、常见问题
### Q1:内置成就为什么不显示?
检查:
1. `config.json` 中 `enableAdvancementPacks` 是否为 `true`(影响成就包,不影响内置成就)
2. 内置成就需父成就解锁后子成就才在 `/ach list` 显示,根成就需满足触发条件(如 `story/root` 需拥有工作台)
3. 隐藏成就达成前不会显示
### Q2:成就包修改后不生效?
成就包只在服务器启动时加载一次,`/ach reload` 不会重载成就包。修改成就包后需**重启服务器**。
### Q3:LSE 触发器不工作?
检查:
1. LegacyScriptEngine 是否已加载
2. LSE 脚本是否成功调用 `registerLseTriggerEvaluator`(可用 `hasLseTriggerEvaluator` 检测)
3. 成就的 `triggerType` 是否设为 `"lse"`
4. 评估器是否在 MeowAchievement 之后注册(建议在 `ServerStarted` 事件后注册)
### Q4:grant 命令的成就 ID 怎么写?
- 内置成就:`adventure/kill_a_mob`(用 `/`)
- 成就包成就:`meme:rotten_flesh`(用 `:`)
- 自定义成就:`custom/my_achievement`
### Q5:玩家数据存在哪里?
玩家进度存储在 `plugins/MeowAchievement/data/players/<xuid>.json`,包含每个成就的 `progress`、`unlocked`、`unlockedAt` 字段。重进服务器自动加载。
### Q6:如何关闭某个成就的全服广播?
在 `config.json` 添加 `perAchievementNotify`,按成就 ID 单独覆盖:
```json
"perAchievementNotify": {
"husbandry/breed_an_animal": { "broadcast": false }
}
```
修改后执行 `/ach reload`。
### Q7:Toast / 广播里的 § 颜色代码不生效?
确认模板字符串中的 `§` 是真正的 section sign(U+00A7),而非复制粘贴产生的相似字符。建议在配置中直接输入 `§`。
## 十三、技术架构(简要)
```
┌─────────────────────────────────────────┐
│ 服务器启动 (enable) │
│ 1. 注册内置成就 (~126 个) │
│ 2. 注册事件监听器 (挖掘/击杀/维度...) │
│ 3. 加载成就包 (advancement_packs/) │
│ 4. 注册 PAPI 占位符 / RemoteCall API │
│ 5. 启动异步检查器工作线程 │
└─────────────────────────────────────────┘
↓ 运行时
┌─────────────────────────────────────────┐
│ 事件监听 (主线程) │
│ 游戏事件 → 命中内置成就 → trigger() │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 异步检查器 (工作线程) │
│ 重计算条件 → 结果回主线程 → trigger() │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ LSE 评估器 (主线程 tick, 玩家轮转) │
│ triggerType="lse" 成就 → 调用 JS 评估 │
│ 返回 true → trigger() │
└─────────────────────────────────────────┘
↓ 解锁
┌─────────────────────────────────────────┐
│ 解锁流程 (主线程) │
│ 1. 检查父成就要求 │
│ 2. 写入玩家数据 (data/players/*.json) │
│ 3. Toast 通知 + 全服广播 + 音效 │
└─────────────────────────────────────────┘
```
**三路触发**:事件监听(自动)、异步检查器(重计算)、LSE 评估器(自定义),三者最终都汇入 `trigger()` 走统一的解锁流程。
## 十四、依赖与致谢
### 依赖
- [LeviLamina](https://github.com/LiteLDev/LeviLamina) 26.10.3+ — 基础框架
- [LegacyRemoteCall](https://github.com/LiteLDev/LegacyRemoteCall) — 跨语言 API 导出
- MeowPAPI — 占位符注册中心(由插件在 load 阶段自动释放到 `plugins/MeowPAPI/`,无需单独安装)
- [LegacyScriptEngine](https://github.com/LiteLDev/LegacyScriptEngine)(可选)— 运行 LSE 自定义触发器
### 致谢
- Minecraft Wiki — Java 版进度树参考
- ZXDash — 成就树可视化编辑面板
## 十五、反馈与支持
- 发现 Bug 或有功能建议,请在论坛回复或联系作者(qq: 3529832433)
- API 对接问题请附上调用代码与 `API.md` 中的对应章节
- 触发器问题请说明成就 ID、`triggerType`、`triggerDef` 内容与服务器日志
- 完整 API 文档见插件目录下的 `API.md`
---
**MeowAchievement** — 为 LeviLamina 服务器打造的 Java 版成就系统解决方案。
[/MD]