[MD]
# MeowSidebar — 高性能侧边栏显示插件(C++ 原生 · 纯协议层发包 · 真异步多线程)
> 一款专为 BDS 服务器设计的侧边栏插件,采用纯协议层发包架构,支持 per-player 独立显示、帧动画、自定义更新频率、玩家自定义行。
## 一、插件简介
MeowSidebar 是一个基于 C++ 开发的 MCBE 侧边栏显示插件,与传统的记分板侧边栏不同,它采用**纯协议层手动发包**的架构,完全绕过 BDS 的 Scoreboard 系统,直接向客户端推送显示数据包。
这种架构带来三个核心优势:
- **per-player 独立显示**:每个玩家看到的侧边栏内容可以完全不同,互不干扰
- **真异步多线程**:PAPI 占位符翻译在后台线程执行,不阻塞游戏主线程
- **无依赖**:仅依赖 BDS 服务器端,无任何外部依赖或插件,可构建endstone衍生插件(若您想要让我支持一套可联系我)
## 二、核心特性
### 性能优化
- **真异步多线程**:后台线程做 PAPI 翻译(重计算),主线程只发包(轻量)
- **增量 diff 发包**:只发送发生变化的行,网络包量减少 80%+
- **内容去重**:与上次发送完全相同则跳过发包
- **标题降频**:标题 AIM 每 4 次刷新才推进一次,避免频繁触发全行重发
- **per-line 更新频率**:动画行可单独设置切换间隔,未到期的行零开销
### 显示能力
- **帧动画**:配置中支持数组的数组,自动循环切换实现动画效果
- **per-line 更新频率**:每个动画行可独立设置帧切换间隔(毫秒)
- **玩家自定义行**:玩家可通过命令添加自己的侧边栏行
### 兼容性
- 内置 40+ 常用占位符(tps/mspt/在线人数/内存/时间/玩家数据等)
- 通过 MeowPAPI 支持 JS 插件注册自定义占位符(RemoteCall 跨语言调用)
- 自动从 BetterSidebar 迁移玩家配置
- 兼容旧版 BEPAPI 接口
- MeowPAPI为静态库,无需单独安装
## 三、安装方法
### 环境要求
- LeviLamina 26.10.3 或更高版本
- LegacyScriptEngine(LSE,可选,用于运行 JS 插件注册占位符)
### 目录结构
```
plugins/MeowSidebar/
├── MeowSidebar.dll # 插件主体
├── manifest.json # 插件清单
├── config.json # 主配置
├── players/ # 玩家自定义行目录
│ └── <xuid>.json
└── .migrated # 数据迁移标记
```
## 四、配置详解
### 4.1 config.json 完整示例
```json
{
"hz": 1500, //刷新间隔(毫秒)
"title": [
"§1§g",
["|", "/", "-", "\\"],
"§5欢迎您加入! §g",
["|", "/", "-", "\\"]
],
"data": [
"§e你好,§g{pl.realName}",
"§g血量: §c{pl.health}/§f{pl.maxHealth}",
"§gTps: §a{server_tps}",
"§g时间: §c{date.h}§g:§e{date.m}§g:§b{date.s}",
[
["§gTps : §a{server_tps}§g ♪ ", "§gTps : §a{server_tps}§g ♪ ", "§gTps : §a{server_tps}§g♪ ", "§gTps : §a{server_tps}§g ♪ ", "§gTps : §a{server_tps}§g ♪ "],
1000 //切换间隔(毫秒)
]
]
}
```
### 4.2 字段说明
| 字段 | 类型 | 说明 |
|------|------|------|
| `hz` | 整数 | 刷新间隔(毫秒),最低 1。建议 1000-2000(1-2 秒刷新一次) |
| `title` | 数组 | 标题模板,支持字符串和子数组(动画) |
| `data` | 数组 | 数据行模板,支持字符串和子数组(动画,可带间隔) |
### 4.3 行类型说明
**静态行**(字符串):
每次刷新都会重新翻译占位符,适合需要实时更新的内容。
```json
"§g血量: §c{pl.health}/§f{pl.maxHealth}"
```
**动画行**(旧格式,跟随 hz 切换帧):
数组中的字符串按顺序循环切换,切换频率等于 hz。
```json
["§gTps : §a♪ ", "§gTps : §a ♪ ", "§gTps : §a ♪"]
```
**动画行**(新格式,自定义切换间隔):
外层是数组,第 0 项是帧数组,第 1 项是切换间隔(毫秒)。
```json
[
["§gTps : §a♪ ", "§gTps : §a ♪ ", "§gTps : §a ♪"],
1000
]
```
| 间隔值 | 行为 |
|--------|------|
| `0` | 跟随 hz 切换(同旧格式) |
| `>0` | 按墙钟时间切换,未到期时帧保持不变 |
**示例**:hz=1500(1.5 秒刷新一次),动画行间隔=5000(5 秒切换一帧),则该行每 5 秒切换一次帧,期间刷新时帧不变,翻译结果相同,自动跳过发包,零开销。
### 4.4 新格式判定条件
外层元素必须满足以下条件才会被识别为新格式:
- 是数组
- 长度为 2
- 第 0 项是数组(帧数组)
- 第 1 项是数字(切换间隔毫秒)
否则按旧格式(纯帧数组)处理,**完全向后兼容**。
### 4.5 标题动画
`title` 字段同样支持子数组动画,默认为-1,即不刷新标题,若您想刷新标题,请设置为非-1值
请注意,标题动画会导致整个侧边栏重发,请谨慎使用,若您坚持使用动画,推进值不小于4
## 五、命令系统
### 5.1 玩家命令
所有玩家可用的 `/sidebar` 子命令:
| 命令 | 说明 |
|------|------|
| `/sidebar` | 显示帮助 |
| `/sidebar on` | 开启侧边栏 |
| `/sidebar off` | 关闭侧边栏 |
| `/sidebar add <文本>` | 添加自定义行(支持占位符) |
| `/sidebar del <序号>` | 删除指定序号的自定义行 |
| `/sidebar clear` | 清空所有自定义行 |
| `/sidebar list` | 列出当前自定义行 |
### 5.2 管理员命令
| 命令 | 权限 | 说明 |
|------|------|------|
| `/sidebar reload` | OP | 重载 config.json 配置 |
### 5.3 玩家自定义行示例
```
/sidebar add §e我的金币: §a{pl.money}
/sidebar add §e我的坐标: §a{pl.pos}
/sidebar list
/sidebar del 1
/sidebar clear
```
玩家自定义行会追加到 `data` 配置行之后,一并翻译显示。配置持久化到 `plugins/MeowSidebar/players/<xuid>.json`,重新进服后保留。
## 六、内置占位符
MeowSidebar 内置 40+ 常用占位符,通过 MeowPAPI 注册,可在 `title` 和 `data` 中使用。
### 6.1 服务器信息
| 占位符 | 说明 |
|--------|------|
| `{server_version}` | 服务器版本 |
| `{server_protocol_version}` | 协议版本 |
| `{server_uptime}` | 服务器运行时间 |
| `{server_tps}` | 服务器 TPS |
| `{server_mspt}` | 服务器 MSPT |
| `{server_online}` | 在线人数 |
| `{server_max_players}` | 最大玩家数 |
| `{server_world_name}` | 世界名称 |
| `{server_difficulty}` | 难度 |
| `{server_total_entities}` | 实体总数 |
| `{server_ram_used}` | 已用内存 |
| `{server_ram_max}` | 最大内存 |
| `{server_port}` | 端口 |
| `{server_on_allowlist}` | 是否开启白名单 |
### 6.2 玩家信息
| 占位符 | 说明 |
|--------|------|
| `{pl.realName}` | 玩家名 |
| `{pl.xuid}` | XUID |
| `{pl.uuid}` | UUID |
| `{pl.ip}` | IP 地址 |
| `{pl.ping}` | 延迟 |
| `{pl.health}` | 当前血量 |
| `{pl.maxHealth}` | 最大血量 |
| `{pl.level}` | 等级 |
| `{pl.exp}` | 经验 |
| `{pl.dimension}` | 维度 |
| `{pl.pos}` | 坐标 |
| `{pl.gameMode}` | 游戏模式 |
| `{pl.onGround}` | 是否在地面 |
| `{pl.money}` | LLMoney 金钱余额(原始数字) | `12345` |
| `{pl.money_formatted}` | LLMoney 金钱余额(带千分位) | `12,345` |
### 6.3 时间
| 占位符 | 说明 |
|--------|------|
| `{date.y}` | 年 |
| `{date.m}` | 月 |
| `{date.d}` | 日 |
| `{date.h}` | 时 |
| `{date.min}` | 分 |
| `{date.s}` | 秒 |
### 6.4 JS 插件扩展
其他 JS 插件可通过 MeowPAPI 的 RemoteCall API 注册自定义占位符:
```javascript
// 注册静态占位符(与玩家无关,如服务器统计)
const register = ll.import("MeowPAPI", "registerStaticPlaceholder");
register("MyPlugin", "my_var", "MyPlugin", "my_callback", 5000); // 5秒缓存
ll.export(() => "Hello", "MyPlugin", "my_callback");
// 注册玩家占位符(需要玩家对象)
const regPlayer = ll.import("MeowPAPI", "registerPlayerPlaceholder");
regPlayer("MyPlugin", "my_player_var", "MyPlugin", "my_player_cb", 2000);
ll.export((player) => player.realName, "MyPlugin", "my_player_cb");
```
注册后即可在 `config.json` 中使用 `{my_var}`、`{my_player_var}`。
完整的占位符列表(包括 JS 插件注册的)请参考 [MeowPAPI 占位符列表.md](file:///e:/111FWQ/xb26.10.14/plugins/MeowPAPI/MeowPAPI_占位符列表.md)。
## 七、适用场景
### 推荐使用 MeowSidebar
- 需要每个玩家看到不同侧边栏内容(如显示玩家自己的金币、坐标、公会)
- 服务器已有计分板系统在用(如排行榜、PVP 分数),不希望侧边栏干扰
- 对性能敏感,希望侧边栏刷新不影响游戏 tick
- 需要丰富的动画效果和 per-line 更新频率
- 希望玩家能自定义侧边栏行
### 不推荐使用 MeowSidebar
- 需要计分板数据持久化到存档(MeowSidebar 不写 Scoreboard)
- 需要通过 `/scoreboard` 命令查看侧边栏数据(MeowSidebar 不注册到 Scoreboard)
## 八、常见问题
### Q1:卸载插件后侧边栏还在显示?
这是协议层发包的特性 — 客户端会保留最后收到的数据包状态,直到收到新的 SetDisplayObjective 或玩家重进。卸载插件后玩家重进即可清除。
### Q2:为什么 `/scoreboard` 命令看不到侧边栏的 objective?
因为 MeowSidebar 没有在 BDS 的 Scoreboard 系统中注册 objective,直接发包给客户端。这是设计取舍,换来零冲突和 per-player 隔离。
### Q3:玩家挖掘方块时感觉卡顿?
检查 `config.json` 的 `hz` 值,建议设置在 1000-2000(1-2 秒刷新一次)。过低的 hz 值(如 1)会导致刷新过于频繁。同时检查是否有动画行设置了过低的切换间隔。
### Q4:JS 插件注册的占位符显示为原样文本(如 `{my_var}`)?
检查:
1. MeowPAPI 是否已加载
2. JS 插件是否成功调用 `ll.import("MeowPAPI", "registerStaticPlaceholder")`
3. 占位符名称是否匹配(注意大小写)
### Q5:玩家自定义行会持久化吗?
会。自定义行存储在 `plugins/MeowSidebar/players/<xuid>.json`,玩家重新进服后自动加载。
### Q6:如何从 BetterSidebar 迁移?
首次启动 MeowSidebar 时会自动从 `plugins/Meow/plugins/BetterSidebar/players/` 迁移玩家配置到 `plugins/MeowSidebar/players/`,通过 `.migrated` 标记文件避免重复迁移。迁移完成后可安全卸载 BetterSidebar。
若迁移失败您可对照PAPI的占位符列表检查是否有缺失或错误的占位符。
## 九、技术架构(简要)
```
┌─────────────────────────────────────────┐
│ 后台线程 (tickLoop) │
│ sleep(hz) │
│ refreshAsync(): │
│ ├─ AIM 获取当前帧 │
│ ├─ PAPI 翻译(skipRemote=true) │
│ └─ 写入 pendingLines │
└─────────────────────────────────────────┘
↓ 调度主线程
┌─────────────────────────────────────────┐
│ 主线程 (flushPending) │
│ 1. 同步在线玩家列表 │
│ 2. 第二遍翻译(skipRemote=false) │
│ 3. 内容去重(相同则跳过) │
│ 4. 增量 diff 发包 │
│ 5. AIM 前进一步 │
└─────────────────────────────────────────┘
```
**两阶段翻译**:后台线程只翻译线程安全的占位符(服务器信息、时间等),主线程翻译需要主线程的占位符(Level/Player/JS 回调等),避免后台线程访问非线程安全 API。
## 十、依赖与致谢
### 依赖
- [LeviLamina](https://github.com/LiteLDev/LeviLamina) 26.10.3+ — 基础框架
- [LegacyScriptEngine](https://github.com/LiteLDev/LegacyScriptEngine)(可选)— 运行 JS 插件
- MeowPAPI — 占位符注册中心(随插件提供)
### 致谢
- [GMSidebar](https://github.com/GroupMountain/GMSidebar) — 增量更新与 per-line 更新频率的设计参考
- BetterSidebar — 数据迁移来源
## 十一、反馈与支持
- 发现 Bug 或有功能建议,请在论坛回复或联系作者(qq:3529832433)
- 配置问题请附上 `config.json` 内容和服务器日志
- 性能问题请说明在线人数、hz 设置、是否使用 JS 占位符
---
[/MD]