Minecraft 数据包虚拟文件系统协议规范倡议──统一数据包持久化存储格式
背景与动机
当前 Minecraft 数据包(Datapack)对于游戏内数据存储普遍采用data与scoreboard指令的方式手动存储数据,这种方式存在以下问题:
- 数据组织碎片化:每个数据包自行决定 storage 路径和 scoreboard objective 命名,无统一规范,冲突频发。
- 跨包数据交换困难:数据包 A 无法以标准方式发现和访问数据包 B 的数据,只能靠硬编码 storage 名约定。
- 数据生命周期不可追踪:storage 中的数据无元信息(创建时间、修改时间、类型),调试时只能盲猜。
这种方式难以追踪和管理数据,且多个数据包之间难以统一的方式修改数据和交换数据,游戏外工具也难以方便地管理数据。
本文提出 Minecraft 数据包虚拟文件系统协议(MCVFS),本质上是 对 data storage 中 NBT 数据的标准化组织方案,而非在
MC 内部实现一个真正的文件系统。协议包含两个层面:
- 节点树序列化格式:统一的 JSON 结构,用于工具链间数据交换与编译产物快照。
- 原生 MCF API:一组标准
.mcfunction函数,在运行时通过data指令操作 storage 中的 VFS 节点树。
一、核心概念
1.1 什么是”虚拟文件系统”
MCVFS 不是一个真正的文件系统。MC 没有文件系统 API,没有指针,没有系统调用。 MCVFS 的实质是 一套约定,安全的操作 NBT
以模拟真实的文件系统。
MCVFS 是全局单例,仅由首个加载的数据包初始化。
“文件”、”目录”、”路径”等术语原意指代真实文件系统中的内容,此处是 对 NBT 节点的别称,便于理解和规范数据布局。
1.2 与 data/scoreboard 指令的关系
MCVFS 不取代 data 和 scoreboard 指令,仅作为提供标准访问函数的数据存储与交互工具。
二、节点树数据结构
2.1 节点定义
每个 VFS 节点是一个 NBT Compound,统一结构如下:
1 | { |
- 时间戳使用 游戏刻(
gametime),通过execute store ... run time query gametime获取。 owner记录创建该节点的标识,用于多包场景下的权限边界。size仅对 file 节点有意义,目录固定为0。
2.2 目录节点
1 | { |
children为 NBT Compound,键为节点名(即”文件名”),值为子节点。- 空目录的
children为空 Compound{}。 - NBT 路径对应文件路径:
root.children.config.children.database即路径/config/database。
2.3 文件节点
1 | { |
content存储该文件节点的 NBT 值。NBT 类型不限,由写入方决定。size为content序列化后的近似字节数,可选字段,为-1时表示未计算。content的 NBT 存储类型由对应 MCVFS 具体实现为准,但应当支持后续提及 api。
2.4 符号链接节点
1 | { |
target存储的是 NBT 路径,而非”文件路径”。这是因为 MC 没有路径解析能力,直接存 NBT 路径可避免二次解析。- 工具链在序列化为 JSON 时可将 NBT 路径转换为人类可读的文件路径。
- 循环链接检测由 API 函数在遍历时处理,超过最大深度(默认 16)即截断。
三、Storage 布局规范
3.1 命名约定
1 | data storage vfs:file |
MCVFS 的数据包实现应在命名空间 vfs 下维护一个 file storage。
3.2 顶层结构
1 | // data storage vfs:file |
root为 VFS 根节点,必须是 directory 类型。meta记录协议版本和元信息,工具链读取此字段判断兼容性。
3.3 路径与 NBT 路径的映射
| VFS 路径 | NBT 路径(相对于 storage 根) |
|---|---|
/ |
root |
/config |
root.children.config |
/config/db.json |
root.children.config.children."db.json" |
/players/steve |
root.children.players.children.steve |
路径分隔符 / 对应 NBT 路径中的 .children.。
四、原生 MCF API
4.1 标准 API 函数清单
以下函数位于命名空间 vfs 下。
| 函数 | 说明 | 输入 (storage vfs:in) |
输出 (storage vfs:out) |
|---|---|---|---|
vfs:read |
读取文件 content | path (NBT path string) |
result (NBT value) |
vfs:write |
写入文件 content | path, data (NBT) |
ok (0b/1b) |
vfs:exists |
检查节点是否存在 | path |
exists (0b/1b) |
vfs:delete |
删除文件节点 | path |
ok (0b/1b) |
vfs:stat |
读取 stat 信息 | path |
result (stat compound) |
vfs:list |
列举目录子项名 | path |
result (list of strings) |
vfs:mkdir |
创建目录节点 | path |
ok (0b/1b) |
vfs:walk |
递归遍历(递归函数) | path |
result (list of compounds) |
vfs:create_symlink |
创建符号链接 | path, target |
ok (0b/1b) |
vfs:resolve |
解析路径为实际节点,处理符号链接 | path |
result (node compound) |
- 由于上述函数均需要动态拼接,因此需 Minecraft 1.20.2 及以上版本
4.2 错误处理
API 通过 vfs:error 设置错误码代码 (数字形式) 以提示调用失败
错误码对应表:
| 错误码 | 代码 | 含义 |
|---|---|---|
OK |
0 | 正常运行 |
NOT_FOUND |
1 | 路径不存在 |
NOT_A_DIR |
2 | 期望目录但节点为文件 |
NOT_A_FILE |
3 | 期望文件但节点为目录 |
ALREADY_EXISTS |
4 | 创建时节点已存在 |
DIR_NOT_EMPTY |
5 | 删除非空目录 |
LOOP_SYMLINK |
6 | 符号链接循环(超过 16 层) |
4.3 初始化
VFS 在数据包首次加载时通过 #load 函数初始化:
1 | # vfs:load(在 load.json 中注册) |
五、跨数据包访问
5.1 命名空间约定
MCVFS 统一存储于 vfs:file。跨包访问通过调用 VFS 提供的函数:
1 | # 读取其他数据包的配置 |
5.2 权限边界
stat.owner字段标识节点创建者。- 注意:这只是 约定级别的保护。没有任何机制可以阻止
data modify直接写入他人 storage。 该检查仅在通过标准 API
调用时生效(通过主动设置目标以防止错误修改),直接使用data指令可绕过。
六、局限性
- 1.20.2 以下版本不可用:动态路径依赖宏,无法降级实现。
- NBT 路径深度限制:建议目录深度不超过 8 层。
- 无强制权限隔离:
owner仅约定级别,data modify可绕过。 - 性能较差:调用过程中检查较多。
- 标题: Minecraft 数据包虚拟文件系统协议规范倡议──统一数据包持久化存储格式
- 作者: 771835
- 创建于 : 2026-08-14 03:26:57
- 更新于 : 2026-09-12 05:33:40
- 链接: https://771835.github.io/2026/08/14/Minecraft-数据包虚拟文件系统协议规范倡议──统一数据包持久化存储格式/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。