API 接口(com.falsepattern.chunk.api)
基本信息
| 属性 | 值 |
|---|---|
| API 包 | com.falsepattern.chunk.api |
| 对外类型数 | 4 个:DataManager(含 6 个嵌套接口)、DataRegistry、OrderedManager、ArrayUtil |
| 构建声明 | build.gradle.kts → api { packages = listOf("api") } |
| 许可 | 源码注释声明"This is an API class covered by the additional permissions in the license"(LGPL + 附加条款) |
| 消费方 | 其他 mod 在自己的 init 阶段调用 DataRegistry.registerDataManager 注册自己的数据管理器 |
这个包是整个 mod 存在的唯一理由。它不做任何事,只定义"别人怎么把自己的数据挂进区块里"。真正干活的是 com.falsepattern.chunk.internal 里的 DataRegistryImpl 与 core mod 挂上的 mixin。
api/package-info.java 的定位说明原文:“This package contains the classes that you will use to interact with the ChunkAPI library.”
DataManager — 根接口
DataManager 本身不做任何事,源码注释明确写着:“Note: This interface does nothing by itself, you also need to implement one or more of the internal interfaces.”
它只强制两个纯查询方法,作为 manager 的身份标识:
| 方法 | 返回 | 语义(源码注释原文) |
|---|---|---|
String domain() |
String |
“The domain of this manager. Usually the modid of the mod that owns this manager.” |
String id() |
String |
“The id of this manager. Usually the name of the manager. Unique per domain.” |
两者拼成注册键 domain:id(冒号分隔,见 数据注册表)。
六个嵌套接口
DataManager 内嵌 6 个接口,构成"一个 manager 可以同时是多种身份"的设计。注册表在 DataRegistryImpl.registerDataManager 里用 instanceof 逐个判定,一个类可以同时命中多个集合。
继承关系
| 接口 | 直接父接口 | 语义 |
|---|---|---|
PacketDataManager |
DataManager |
随区块数据包 S→C 同步 |
CubicPacketDataManager |
DataManager |
仅 CubicChunks 用的立方体变体 |
BlockPacketDataManager |
DataManager |
随单方块/多方块变更包同步 |
StorageDataManager |
DataManager |
版本信息 + 升降级提示(“root” 与 “subChunk” 的公共父接口) |
ChunkDataManager |
StorageDataManager |
每区块一次,落盘 |
SubChunkDataManager |
StorageDataManager |
每 ExtendedBlockStorage 一次,每区块 16 次 |
⚠️ 注意 PacketDataManager / CubicPacketDataManager / BlockPacketDataManager 三者都直接继承 DataManager,不继承 StorageDataManager——即一个纯网络 manager 可以完全不做落盘,也不提供版本号。
PacketDataManager
| 成员 | 签名 | 说明 |
|---|---|---|
maxPacketSize() |
int |
该 manager 数据在包里的最大字节数。@implSpec:“This is used to determine the size of the packet compression/decompression buffer. Only called ONCE, during registration!” |
writeToBuffer |
void writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer buffer) |
subChunkMask 控制哪些 subChunk 需要序列化;forceUpdate 为 true 表示这是该区块首次同步 |
readFromBuffer |
void readFromBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer buffer) |
同上,反向 |
subChunkMask 的关键约定(源码注释):“This will be 0 when cubic chunks is present - only chunk-specific information (like biomes) should be sent in this case.”
CubicPacketDataManager(@ApiStatus.Experimental)
| 成员 | 签名 |
|---|---|
maxPacketSizeCubic() |
int |
writeToBuffer |
void writeToBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) |
readFromBuffer |
void readFromBuffer(Chunk chunk, ExtendedBlockStorage blockStorage, ByteBuffer buffer) |
@apiNote 原文解释三方等价关系:“Cubes, subchunks, and ExtendedBlockStorages are equivalent. A cube is a subchunk and a cube contains an EBS. To keep dependencies simple, cube-specific information is not available to this interface, but a cube’s location can be retrieved by combining the chunk location and the EBS Y level. Note that the EBS’s Y level can be <0 and >= 16.”
作者是 RecursivePineapple,@since 0.7.1。
BlockPacketDataManager
| 成员 | 签名 |
|---|---|
writeBlockToPacket |
void writeBlockToPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet) |
readBlockFromPacket |
void readBlockFromPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet) |
writeBlockPacketToBuffer |
void writeBlockPacketToBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException |
readBlockPacketFromBuffer |
void readBlockPacketFromBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException |
前两个方法让 manager 能在服务端构造包时挂额外字段、在客户端收包时读到这些字段;后两个负责字段本身的序列化(由 DataRegistryImpl.writeBlockPacketToBuffer 统一循环调用,见 序列化流水线)。
StorageDataManager
ChunkDataManager 与 SubChunkDataManager 的公共父接口。注释说明:“Contains version information and messages for users attempting to upgrade/remove versions.”
| 成员 | 返回 | 语义 |
|---|---|---|
version() |
@NotNull String |
数据管理器当前版本 |
newInstallDescription() |
@Nullable String |
首次用带此 manager 的 mod 打开世界时给用户看的消息;返回 null 表示无消息且与原版完全兼容 |
uninstallMessage() |
@NotNull String |
卸载此 manager 后仍试图读档时显示的消息(信息存在世界 NBT 里) |
versionChangeMessage(String priorVersion) |
@Nullable String |
升/降级时的警告;返回 null 表示与旧版本完全兼容,不显示警告 |
这四个方法的返回值直接被 DataRegistryImpl.verifyManagerCompatibility 消费,构成读档时的兼容性闸门(详见 核心 mod 与读档闸门)。
ChunkDataManager
| 成员 | 签名 | 说明 |
|---|---|---|
chunkPrivilegedAccess() |
default boolean → false |
@implNote:“This is used internally for reimplementing the vanilla logic. Only change this if you know what you’re doing.” |
writeChunkToNBT |
void writeChunkToNBT(Chunk chunk, NBTTagCompound nbt) |
存盘时序列化 |
readChunkFromNBT |
void readChunkFromNBT(Chunk chunk, NBTTagCompound nbt) |
读档时反序列化 |
cloneChunk |
void cloneChunk(Chunk from, Chunk to) |
区块克隆时直接拷数据 |
chunkPrivilegedAccess() 的语义(源码注释):
false(默认)→ 传入的是新建的 NBT 对象,会被插到关卡 NBT 的domain:id名字下true→ 传入的是未经过滤的原始 level NBT tag
readChunkFromNBT 的 nbt 可能是非 null 但内容为空,源码注释警告:“The NBT may be null if the chunk was saved before this manager was registered (e.g., loading save before the mod was added), and the manager is not privileged. In this case, you should initialize the data to a sane default.”
SubChunkDataManager
与 ChunkDataManager 结构完全对称,只是粒度变成 ExtendedBlockStorage:
| 成员 | 签名 |
|---|---|
subChunkPrivilegedAccess() |
default boolean → false |
writeSubChunkToNBT |
void writeSubChunkToNBT(Chunk chunk, ExtendedBlockStorage subChunk, NBTTagCompound nbt) |
readSubChunkFromNBT |
void readSubChunkFromNBT(Chunk chunk, ExtendedBlockStorage subChunk, NBTTagCompound nbt) |
cloneSubChunk |
void cloneSubChunk(Chunk fromChunk, ExtendedBlockStorage from, ExtendedBlockStorage to) |
⚠️ cloneSubChunk 的第一个参数是 fromChunk(拥有 from 的区块),注释说明用途:“Used by data managers for getting metadata about the world (skylight presence, etc.)” —— 内置的 SkylightManager 正是靠它判断 worldObj.provider.hasNoSky。
源码注释强调调用频率:“This is called once per ExtendedBlockStorage per chunk. (16 times per chunk)”
DataRegistry
@ApiStatus.NonExtendable 的静态门面,把 DataRegistryImpl 的能力暴露出来(完整语义见 数据注册表):
| 方法 | 说明 |
|---|---|
registerDataManager(DataManager, int) |
注册,第二个参数是排序索引 |
registerDataManager(DataManager) |
@Deprecated,隐式 ordering 0 |
disableDataManager(String domain, String id) |
在 postInit 阶段停用 |
getRegisteredManagers() |
@Deprecated |
getRegisteredManagersOrdered() |
返回含排序索引的不可变视图 |
cloneChunk(Chunk, Chunk) |
广播区块克隆请求 |
cloneSubChunk(Chunk, ExtendedBlockStorage, ExtendedBlockStorage) |
广播 subChunk 克隆请求 |
OrderedManager
带 Lombok @RequiredArgsConstructor 的普通类,implements Comparable<OrderedManager>:
| 字段 | 类型 |
|---|---|
ordering |
int |
id |
@NotNull String |
compareTo 先比 ordering,相等时回退比 id 字符串——保证排序稳定且全序。equals/hashCode 按 (ordering, id) 双字段。
ArrayUtil
@ApiStatus.NonExtendable 的工具类,11 个 copyArray 重载,全部是原地传输语义:见 数组工具类。