数据包格式与优先级

基本信息

属性 值
加载器 databack.common.loader.DatapackLoader(类注释自述为「加载世界全部数据包的唯一入口」)
目标格式版本 LOADER_FORMAT_VERSION = 48(DatapackLoader.java:62,仅用于 overlay 解析)
用户数据包目录 <世界存档>/datapacks/(DatapackLoader.java:85)
支持的包形态 目录,或 .zip 文件(后缀判断大小写不敏感,DatapackLoader.java:256)
内置原版包 启动时从 Mojang 下载 MC 26.1 的 data/ 作为最低优先级基线
顺序持久化 世界 NBT 的 Order(顺序表)与 Disabled(禁用集合)两个字符串列表

功能

定义 Databack 如何发现、解析、排序数据包,以及这些状态如何写进世界存档。

候选发现

discoverCandidates(File worldSaveDir)(DatapackLoader.java:69-97)按顺序产出候选:

  1. 原版数据包置索引 0,最低优先级 —— 注释明写「Vanilla datapack at index 0 (lowest priority — every other pack overrides it)」。游戏目录由 worldSaveDir.getParentFile().getParentFile() 推导,即从世界存档目录上溯两级得到 .minecraft(DatapackLoader.java:72-79)
  2. <世界存档>/datapacks/ 下的内容;目录不存在时只记一条 Datapack directory does not exist: ... 的 INFO 日志,不报错(DatapackLoader.java:87-92)
  3. 发出 DatapackGatherEvent(candidates),允许其他模组追加候选(DatapackLoader.java:95)

discover 扫描 datapacks/ 的一级子项:子目录全部纳入;文件仅当小写后缀为 .zip 时纳入;返回顺序为文件系统顺序(DatapackLoader.java:246-261)。包名由 derivePackName 取目录名或去掉 .zip 的文件名(DatapackLoader.java:596-602,.zip 判断在 :598)。

包形态解析:目录走 FolderDatapackSource,压缩包走 ZipDatapackSource;缺少 pack.mcmeta 的候选直接返回 null 被跳过,解析失败则抛 DatapackLoadException(DatapackLoader.java:275-293)。

排序与优先级

优先级规则由源码与指令帮助文本共同确证:

规则 说明 出处
列表靠后者优先级更高 指令帮助明写「Packs at the end/bottom of the list have priority over earlier packs.」 DatapackCommand.java:65
资源迭代从高到低 「Iterates all packs (highest priority first)」,orderedPacks 为低→高顺序,for (oi = size-1; oi >= 0; oi--) 反向遍历 DatapackLoader.java:345-370
排序表内下标越小优先级越低 db$order 用 Comparator.comparingInt(pack -> db$datapackOrder.indexOf(pack.getPackId())) 升序排序,找不到时取 Integer.MAX_VALUE(即沉到末尾) MixinWorldInfo_Datapacks.java:116-134
原版包恒为最低 固定插在候选索引 0 DatapackLoader.java:72

新出现的包在 db$syncPackDeltas(MixinWorldInfo_Datapacks.java:102-113)中被追加到顺序表末尾,因此默认获得较高优先级(:110);已从磁盘消失的包会从顺序表和禁用集合中一并剔除(同方法 removeIf)。

pack.mcmeta 与 overlays

PackMetadata 解析出四组字段:getPack()(PackInfo)、getFilter()(PackFilter)、getOverlays()(PackOverlays)、getFeatures()(PackFeatures)(PackMetadata.java:42-57)。

Overlay 解析规则:

  • 只对目标格式版本 LOADER_FORMAT_VERSION = 48 生效(DatapackLoader.java:376)
  • overlay 目录按列出顺序的反序枚举,即「最后列出者优先」(DatapackLoader.java:378-379)
  • 每个 overlay 目录下的数据前缀是 <dir>/data/(DatapackLoader.java:385)
  • 空 overlay 目录被静默跳过(DatapackLoader.java:388-389)
  • overlay 目录名会经 validateOverlayDirectoryName 校验,注释明写目的是「不包含路径穿越字符」,空目录名抛异常(DatapackLoader.java:431-438)
  • 同一包内 overlay 优先于包基础 data/(DatapackLoader.java:345 注释:先枚举 overlays 再 base)

存档持久化

顺序与禁用状态存放在 WorldInfo 上,由 Mixin 注入两个字段实现(MixinWorldInfo_Datapacks.java:30、33):

字段 NBT 键 类型 含义
db$datapackOrder Order NBTTagList of NBTTagString 包的启用顺序(升序,末尾优先级最高)
db$disabledDatapacks Disabled NBTTagList of NBTTagString 被 /datapack disable 的包 id 集合

读写链路为 DatapackModContainer(IFMLLoadingPlugin.getModContainerClass() 指定该类,父容器 modid 为 databackcore):

  • 存盘:getDataForWriting 调用 ((DatapackWorldInfo) info).db$saveDatapackInfo()(DatapackModContainer.java:42-44)
  • 读档:readData 调用 db$loadDatapackInfo(tag) 恢复状态,随后 DatapackLoader.load(handler.getWorldDirectory(), ...) 重新加载(DatapackModContainer.java:47-50)
  • 读入 db$loadDatapackInfo 见 MixinWorldInfo_Datapacks.java:35-50,其中 Disabled 列表通过 Mixin 生成的 AccessorNBTTagList 强转遍历字符串列表(:42);写出 db$saveDatapackInfo 见 :61-80
  • WorldInfo 的复制构造器被 Mixin 注入 @Inject(method = "<init>(Lnet/minecraft/world/storage/WorldInfo;)V", at = @At("TAIL")),把源实例的顺序与禁用集合一并复制(MixinWorldInfo_Datapacks.java:52-62)

原版数据包下载

VanillaDatapackDownloader(DatapackLoader.java:76、CommonProxy.java:103-108):

属性 值
目标版本 MC_VERSION = "26.1"(VanillaDatapackDownloader.java:24)
版本清单 https://piston-meta.mojang.com/mc/game/version_manifest_v2.json(VanillaDatapackDownloader.java:25-26)
缓存目录名 vanilla-datapack-26.1(VanillaDatapackDownloader.java:27)
只取 data/ 目录与 pack.mcmeta(类注释 VanillaDatapackDownloader.java:14)
合成 meta 缺失时写出 {"pack":{"pack_format":48,"description":"<版本> datapack"}}(VanillaDatapackDownloader.java:426)
User-Agent Databack-Mod/26.1(VanillaDatapackDownloader.java:377)
失败处理 discoverCandidates 记 ERROR 日志「Failed to obtain vanilla datapack; world generation may be incomplete」并继续;preInit 侧记 ERROR「Failed to download vanilla datapack during boot」

Gradle 侧有配套的构建期任务 downloadVanillaDatapack,用同样的 MC_VERSION = "26.1" 抽取 data/ 到 build/modernData(addon.gradle)。仓库内 misc/test-packs/minecraft/data 是指向 ../../../build/modernData/data 的符号链接。

源码中一处测试用候选路径

discoverCandidates 末尾无条件追加了一条候选(DatapackLoader.java:93):

candidates.add(worldSaveDir.toPath().resolve("..").resolve("..").resolve("..").resolve("..").resolve("misc/test-packs/minecraft").toFile());

即从世界存档目录上溯四级再进入 misc/test-packs/minecraft(仓库内的测试包)。该路径在普通安装的 .minecraft 下并不存在;按 loadCandidate 的规则,缺少 pack.mcmeta 的候选会被跳过。此处仅陈述源码事实,运行时行为未实测。

资源位置组件校验

加载器使用 Pattern.compile("[a-z0-9_.\\-]+") 校验资源位置各组件(DatapackLoader.java:65,注释:「Regex patterns for resource location component validation」)。

相关条目