【免费下载链接】LeviLaunchroid
A launcher designed for Minecraft Bedrock Edition on Android
LeviLaunchroid 是一款专为 Android 平台打造的 Minecraft Bedrock Edition(基岩版)启动器。它用C++ 编写的 NBT 二进制解析器安全地读写世界文件,通过内嵌的LevelDB 引擎直接操作 Bedrock 世界数据库,并借助多版本隔离机制让官方版与第三方版本互不干扰——本文将剖析这三块核心技术背后的实现原理,帮助你理解一个"能真正打开并修改游戏存档"的启动器是如何构建的。
一图认识 LeviLaunchroid
LeviLaunchroid 不只是"启动"基岩版,它还能直接解析 NBT 世界文件、扫描 LevelDB 区块数据、管理多个游戏版本的独立目录,相当于把世界编辑器的底层能力搬到了手机上。
架构总览:三层能力划分
整个项目可以拆成三个层次,层层递进:
| 层次 | 技术栈 | 职责 |
|---|---|---|
| 世界数据层 | C++ / JNI | NBT 解析编码、LevelDB 读写 |
| 游戏运行时层 | Kotlin / Java | 版本管理、多版本隔离、启动调度 |
| 交互层 | Java + XML | 世界编辑器 UI、实例卡片、Mod 管理 |
C++ 层集中在 WorldJni.cpp,通过 CMake 编译为leviworld共享库;Java/Kotlin 层围绕 content 包组织世界、Mod、资源包等资源管理能力;versions 包负责多版本隔离。
一、C++ NBT 解析器:如何又快又安全地读取世界文件
Minecraft 的区块、实体、生物群系都以NBT(Named Binary Tag)格式存储。LeviLaunchroid 没有使用 Java 反射式解析,而是在 WorldJni.cpp 中基于 GlacieTeam NBT 库(MPL-2.0)实现了原生解析管线,Java 侧入口是 NativeNbt.java。
1. 安全 Guard:先"体检",再解析
解析器内置了一个Guard结构(见 WorldJni.cpp),它在正式解析前遍历一遍 NBT 树做防御性校验:
- 大小上限:任何记录超过 64 MiB 直接拒绝;
- 嵌套深度 ≤ 128、节点数 ≤ 200 万:防止恶意构造的深嵌套导致栈溢出或内存爆炸;
- 数组长度溢出检测:
count > MaxBytes / width时判定异常; - 重名键检测:Compound 中出现重复字段名立即报错。
这种"先 Guard 校验、再反序列化"的两段式设计,让启动器面对损坏或伪造的存档文件时只会报出清晰错误(如Truncated NBT),而不是崩溃。
2. 三种格式与自动识别
Java 层用三个常量区分格式(NativeNbt.java):
LITTLE_ENDIAN:标准小端 NBT(区块文件)LEVEL_DAT:带 8 字节"版本号+长度"头部的前缀格式(level.dat 存档)BIG_ENDIAN:大端格式(部分 Bedrock 数据)
readAuto会自动嗅探数据:若第 9 字节为0x0a(Compound 类型标记)且长度字段吻合,就按 level.dat 解析,否则回退到小端模式——对新手来说,这意味着同一个 API 能打开所有 Bedrock 存档文件。
3. Gzip 解压与 SNBT 文本互转
压缩 NBT 由 C++ 侧用 zlib 完成流式解压(inflateData,WorldJni.cpp),解压结果同样受 64 MiB 上限保护。此外还实现了SNBT 文本格式的双向转换(toSnbt/fromSnbt),解析前会先做引号与括号配对的快速扫描,让高级用户可以直接以人类可读文本编辑世界数据。
4. Java ↔ C++ 的数据桥
Bridge结构(WorldJni.cpp)负责把 C++ 的nbt::Tag树与 Java 的NbtTag/ArrayList/LinkedHashMap相互转换:数字类型走valueOf装箱,数组通过SetByteArrayRegion等 JNI 批量拷贝,Compound 映射为LinkedHashMap以保持字段顺序——这对世界编辑场景很重要,能避免重排键名造成无谓的数据变更。
二、LevelDB:Bedrock 世界数据库的读写引擎
Bedrock 的每个世界目录下的db/文件夹就是一个 LevelDB 数据库。LeviLaunchroid 在 worldtools/CMakeLists.txt 中把 LevelDB(BSD-3-Clause)连同Snappy、Zstd、zlib压缩器全部静态编入,Java 侧封装为 WorldDatabase.java。
1. 打开数据库:安全开关一览
原生openNative(WorldJni.cpp)的选项值得细看:
| 选项 | 值 | 作用 |
|---|---|---|
create_if_missing | false | 绝不凭空创建数据库 |
paranoid_checks | true | 开启最严格完整性检查 |
block_cache | 8 MiB LRU 缓存 | 加速重复读取 |
write_buffer_size | 2 MiB | 控制内存占用,适合手机 |
compression | kZlibRaw | 压缩 SST 表节省磁盘 |
更关键的是 Java 层的守护:WorldDatabase.java 在构造时会检查MinecraftActivityState.isRunning()——游戏进程正在运行时禁止打开世界数据库,从根上避免双写损坏存档。
2. 分页扫描与批量写入
原生scanNative实现了前缀扫描 + 游标分页(WorldJni.cpp):
- 每页最多 512 条,单轮最多扫描 8192 条,防止遍历超大世界时卡死 UI;
- 返回数组第 0 个元素是"下一页游标",Java 侧封装为
Page对象供编辑器翻页; - 支持小写不敏感的子串过滤,相当于给世界记录加了个"搜索框"。
写入走WriteBatch+sync=true原子批量提交,单批上限 128 MiB。Java 层的 WorldSession.java 更进一步:所有修改先进入暂存区(before/after 变更列表),跟踪 revision 版本号,只在最终提交时一次性写回——这意味着世界编辑器支持"撤销式"编辑。
3. Bedrock 键编码的逆向映射
LevelDBKey.java 把 Bedrock 世界数据库中的单字节键类型还原成了可读名称:0x2b→ Data3D、0x2f→ SubChunk(子区块体素)、0x31→ BlockEntity(方块实体)、0x32→ Entity(实体)、0x35→ BiomeState(生物群系状态)……配合 ChunkKey.java 解析坐标,UI 就能把"一坨二进制键"展示成"坐标 (x, y, z) 的子区块"这样的信息——这就是世界地图渲染(WorldMapRenderer.java)的数据基础。
三、多版本隔离:每个游戏版本一套独立目录
LeviLaunchroid 最实用的能力是同时安装多个基岩版 APK(官方版 + 第三方版本),且它们的数据互不污染。核心设计在 LauncherStorage.java 与 GameVersion.java。
1. Profile 目录模型
所有数据统一收敛到minecraft/根目录下,按Profile(配置档)切分:
Android/media/<包名>/minecraft/ ├── _shared/ # 官方共享 Profile │ ├── internal/ external/ # 文件数据(内部/外部分区) │ ├── data/ cache/ # 数据库与缓存 │ ├── mods/ metadata/ # Mod 目录与元数据 └── <第三方版本目录名>/ # 隔离 Profile,结构同上每个 Profile 内部都包含games/com.mojang/游戏数据子目录、mods/独立 Mod 目录和metadata/元数据区(LauncherStorage.java 中的常量定义了这套结构)。
2. 隔离路由:一行代码决定数据去向
GameVersion.java 中的规则极其简洁:versionIsolation = !isOfficial——官方 Mojang 版本(com.mojang.minecraftpe)走共享 Profile,第三方版本则获得自己名下的独立目录。
启动时,MinecraftRuntimePreparer.kt 根据该标志调用getStorageFilesRoot / getStorageDataRoot / getStorageCacheRoot,把filesDir、dataDir、cacheDir三个关键路径整体重定向,并通过 Intent 的VERSION_ISOLATION参数传递给游戏运行时。对游戏来说,它"以为"自己还是装在标准位置,实际数据已落入独立沙盒。
3. 兼容旧数据的平滑迁移
老用户升级时可能已有散落在系统dataDir里的旧数据。LauncherStorage提供了legacy / new双模式:chooseSharedStorageMode检测到旧路径下有游戏数据就自动保持legacy 模式,否则启用新的 Profile 布局;未被归类的旧数据会进入_legacy_unclassified兜底目录(LauncherStorage.java)。版本元数据由 VersionProfileMetadataStore.java 以 JSON 持久化,VersionManager.java 单例则统一管理"官方版本列表 + 自定义 APK 版本"的安装、删除与选择。
四、构建系统:CMake 如何打包这些原生组件
worldtools/CMakeLists.txt 展示了完整的原生构建策略:
- vendoring 一切:snappy、zstd、leveldb、NBT、BinaryStream 全部以源码形式内置于
vendor/目录,交叉编译零外部依赖; - C++23 + 隐藏符号:
-fvisibility=hidden与-Wl,--exclude-libs,ALL让导出的只有 JNI 入口,减小.so体积并避免符号冲突; - 16 KB 页对齐:
-z,max-page-size=16384链接参数,面向 Android 新内核对内存页大小的要求; - 许可合规:第三方组件的来源与许可证在 NOTICE.txt 中逐项声明,MPL-2.0 源码包随 APK 分发(assets/worldtools/ 下的
mpl-source.zip),完全符合开源协议要求。
五、总结:这套架构带来了什么
| 技术点 | 对用户的实际价值 |
|---|---|
| C++ NBT 解析 + Guard 校验 | 打开损坏/超大存档不崩溃,错误提示清晰 |
| LevelDB 原生引擎 + 分页扫描 | 手机上也流畅浏览数百万条世界记录 |
| 暂存式批量写入 | 世界编辑支持原子提交,不怕写一半断电 |
| 多版本 Profile 隔离 | 官方版与第三方版本数据物理隔离,随意安装卸载 |
| 全部 vendored 依赖 | 交叉编译稳定,无网络依赖,构建可复现 |
从 NBT 的二进制字节到 Profile 的目录边界,LeviLaunchroid 用"原生性能 + 严格校验 + 目录沙盒"三板斧,把一台手机变成了可以安全编辑 Minecraft 基岩版世界的工具。如果你想深入细节,建议从 WorldJni.cpp 的 Guard 结构和 LauncherStorage.java 的路由函数读起——这两处代码是理解整个架构的最佳入口。
【免费下载链接】LeviLaunchroid
A launcher designed for Minecraft Bedrock Edition on Android
相关推荐
LeviLaunchroid多版本管理:如何为多个Minecraft版本实现完美隔离与安全测试
LeviLaunchroid多版本管理:如何为多个Minecraft版本实现完美隔离与安全测试 LeviLaunchroid 是一款专为 Android 平台打
Unity-MCP测试策略:如何构建完整的AI开发测试循环确保功能可靠性
Unity MCP测试策略:如何构建完整的AI开发测试循环确保功能可靠性 Unity MCP是一个为Unity引擎提供AI技能、MCP工具和CLI的开源项目,能
AI Agent游戏开发开发工具Sunshine 游戏串流完全指南:把 PC 变成低延迟自托管云游戏主机的 5 种方式
Sunshine 游戏串流完全指南:把 PC 变成低延迟自托管云游戏主机的 5 种方式 Sunshine 是一款免费开源的自托管游戏串流服务器,它为 Moonl
音视频后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考