存档目录与文件命名(save-directory-layout)
基本信息
| 属性 | 值 |
|---|---|
| 区域名载体 | cubicchunks.regionlib.api.region.key.RegionKey,只有 getName() 一个字符串字段 |
| 名字的用途 | 直接当文件名(打包区)或目录名(.ext),所以 equals / hashCode 都只基于 name |
| 顶层布局 | SaveCubeColumns.create(Path) 建 region2d/ 与 region3d/ 两个子目录 |
命名规则表
三种 key 类型的 getRegionKey() 与 getId() 打包方式(全部逐字取自源码):
| key 类 | LOC_BITS |
每区域条目数 | 区域名格式 | 正则(IKeyProvider.isValid) |
|---|---|---|---|---|
EntryLocation2D |
5 |
32 × 32 = 1024 |
<regX>.<regZ>.2dr |
-?\d+\.-?\d+\.2dr |
EntryLocation3D |
4 |
16 × 16 × 16 = 4096 |
<regX>.<regY>.<regZ>.3dr |
-?\d+\.-?\d+\.-?\d+\.3dr |
MinecraftChunkLocation |
5 |
32 × 32 = 1024 |
r.<regX>.<regZ>.<extension> |
r\.-?\d+\.-?\d+\.<extension>(构造时拼串) |
其中 regX = entryX >> LOC_BITS(entryY / entryZ 同理),负坐标靠算术右移自然带出 -。
id 打包
| key 类 | getId() |
|---|---|
EntryLocation2D |
((entryX & 31) << 5) | (entryZ & 31) —— X 在高位 |
EntryLocation3D |
((entryX & 15) << 8) | ((entryY & 15) << 4) | (entryZ & 15) |
MinecraftChunkLocation |
((entryZ & 31) << 5) | (entryX & 31) —— Z 在高位,与 EntryLocation2D 相反 |
MinecraftChunkLocation.getRegionKey()用"r." + regX + "." + regZ + "." + extension(先 X 后 Z),但getId()是 Z 在高位。而EntryLocation2D是getRegionKey()先 X 后 Z、getId()也 X 在高位。三者互不相同,切勿混用。
<extension> 取值
MinecraftSaveSection.MinecraftRegionType 只有 MCR 与 MCA 两个枚举值,createAt 里用 type.name().toLowerCase() 转小写,所以最终文件名是:
| 枚举 | 区域名 | 文件名 |
|---|---|---|
MCR |
r.<regX>.<regZ>.mcr |
r.<regX>.<regZ>.mcr |
MCA |
r.<regX>.<regZ>.mca |
r.<regX>.<regZ>.mca |
目录树
SaveCubeColumns.create(Path directory)(impl/SaveCubeColumns.java):
<directory>/
├── region2d/ # SaveSection2D.createAt
│ ├── <regX>.<regZ>.2dr # 打包区域文件(512 B/扇区)
│ └── <regX>.<regZ>.2dr.ext/ # ExtRegion 目录
│ └── <id> # 例如 0 / 1 / 1023
└── region3d/ # SaveSection3D.createAt
├── <regX>.<regY>.<regZ>.3dr
└── <regX>.<regY>.<regZ>.3dr.ext/
└── <id>
写入过程中的 <id>.tmp 也短暂出现在 .ext 目录里(构造函数的位图构建会忽略非数字名)。
MinecraftSaveSection.createAt(Path, MinecraftRegionType) 不建子目录,直接用传入的 directory 存 r.X.Z.mcr / r.X.Z.mca。
命名约束(javadoc 声明 vs 实际实现不一致)
IKey.getRegionKey() 的 javadoc 写:
The name may be used as a file name, so names not matching
^[a-z0-9\._\-]+$are not supported. Uppercase characters are not allowed to avoid case-sensitivity issues across different operating systems.
但三个 isValid 正则都以 -?\d+ 开头,允许数字和 - 之外的场景不匹配——$ 之外还漏了 [0-9]。也就是说:负坐标生成的区域名(如 -1.0.2dr)并不满足 javadoc 声明的字符集,却恰恰是 isValid 认可的合法名字。javadoc 与实现存在矛盾,以实现为准。
枚举已有区域
SimpleRegionFactory.allRegions():
return Files.list(this.directory)
.map(Path::getFileName)
.map(Path::toString)
.map(RegionKey::new)
.filter(this.keyProvider::isValid);
| 特性 | 行为 |
|---|---|
| 过滤 | 只保留能通过 keyProvider.isValid 的名字,.ext 目录等一律排除 |
| 目录不存在 | Files.list 抛 java.nio.file.NoSuchFileException(无 try-catch) |
| 资源释放 | 没有 try-with-resources,返回的 Stream 未被关闭(SimpleRegionFactory.java:89-94)——调用方必须自己关(各 allRegions 的 javadoc 也都强调了这点) |
| 流语义 | 只保证"调用时刻已创建"的区域一定出现,迭代期间新建的不保证 |
SharedCachedRegionProvider.allKeys() 在此之上还会对每个区域 for (int id = 0; id < keyCount; id++) 逐 id 造 key,再一次性 forExistingRegion + removeIf(r -> !r.hasValue(key)) 过滤——注释说明这样比 IRegionProvider#fromRegionAndId 慢的方式快(ArrayList#removeIf)。
本 mod 仓库里随包发布的数据文件
没有。 ls -d src/main/resources → No such file or directory;git ls-files | grep -v '\.java$' 只返回构建脚本、许可与 CI 配置。无 mcmod.info、无语言文件、无任何 JSON/YAML 数据文件——所有区域/扇区布局都是代码里硬编码的常量(上表那些 LOC_BITS / .2dr / .ext 字面量),不存在可被玩家改写的配置文件。
相关条目
- 区域文件格式 -
<regionName>那个文件的内部布局 .ext回退格式 -<regionName>.ext/目录的内部布局- 多提供者回退链
- SaveSection2D -
region2d/的提供者装配 - SaveSection3D -
region3d/的提供者装配 - Minecraft 原版存档区 -
r.X.Z.mcr/r.X.Z.mca