内置区块处理器
基本信息
| 属性 | 值 |
|---|---|
| 类型 | 内置封包数据序列化器 |
| 所在包 | com.gtnewhorizons.foundation.builtin |
| 处理器总数 | 6 个 |
| 同时实现两个接口的 | 2 个(BlockLSBHandler、MetadataHandler) |
| 分配缓冲区总量 | 196,896 字节(固定,按注册累加) |
行为
6 个内置处理器在 Foundation.preInit(FMLPreInitializationEvent) 中被 new 出来并
注册到 处理器注册表。注册顺序即下表顺序,且客户端与服务端必须一致。
注册代码(Foundation.java:29-44):
HandlerRegistry.registerChunkPacketHandler(blockLSBHandler);
HandlerRegistry.registerChunkPacketHandler(metadataHandler);
HandlerRegistry.registerChunkPacketHandler(blockLightHandler);
HandlerRegistry.registerChunkPacketHandler(skylightHandler);
HandlerRegistry.registerChunkPacketHandler(blockMSBHandler);
HandlerRegistry.registerChunkPacketHandler(biomeHandler);
HandlerRegistry.registerBlockPacketHandler(blockLSBHandler);
HandlerRegistry.registerBlockPacketHandler(metadataHandler);
处理器全表
| # | 处理器 | 实现的接口 | maxBytesPerChunk() |
源码注释 | 编解码的数据 |
|---|---|---|---|---|---|
| 1 | BlockLSBHandler |
ChunkPacketHandler, BlockPacketHandler |
4096 * 16 = 65,536 |
16 * 16 * 16 bytes per section * 16 sections |
ExtendedBlockStorage.getBlockLSBArray()(方块 ID 低 8 位,每子区块 4096 字节) |
| 2 | MetadataHandler |
ChunkPacketHandler, BlockPacketHandler |
2048 * 16 = 32,768 |
16 * 16 * 16 / 2 bytes per chunk section |
getMetadataArray()(metadata 半字节数组,4 位/方块) |
| 3 | BlockLightHandler |
ChunkPacketHandler |
2048 * 16 = 32,768 |
同上 | getBlocklightArray()(方块光照半字节数组) |
| 4 | SkylightHandler |
ChunkPacketHandler |
2048 * 16 = 32,768 |
同上 | getSkylightArray()(天空光照半字节数组) |
| 5 | BlockMSBHandler |
ChunkPacketHandler |
(2048 + 2) * 16 = 32,800 |
(16 * 16 * 16 / 2) bytes per section * 16 sections + 2 bytes for flags |
getBlockMSBArray()(方块 ID 高位)+ 每子区块 2 字节 flagMsb |
| 6 | BiomeHandler |
ChunkPacketHandler |
256 | 16 * 16 bytes for biome data |
chunk.getBiomeArray()(每列 1 字节群系 ID) |
累加:65536 + 32768 + 32768 + 32768 + 32800 + 256 = 196,896 字节,
即 HandlerRegistry.getChunkPacketBytes() 的返回值,也是
MixinS21PacketChunkData 分配的静态缓冲区大小。
实际写入量通常远低于该上限:注册表为每个 handler 分配 maxBytesPerChunk()
的定长切片,但只回填真实长度(slice.position()),未用的部分不进入网络数据。
逐个处理器的行为差异
BlockLSBHandler(唯一同时写 block 字段的处理器)
单方块封包路径上,它负责方块 ID 本身:
| 方向 | 实现 |
|---|---|
| 写 | data.writeVarIntToBuffer(Block.getIdFromBlock(info.getBlock())) |
| 读 | info.setBlock(Block.getBlockById(data.readVarIntFromBuffer())) |
用的是 VarInt 而非固定 short,因此 > 32767 的扩展方块 ID 也可传输。
源码 builtin/BlockLSBHandler.java:24 有一个未使用的局部变量
int start = buffer.position();(后续无引用)——不影响输出,因为
处理器注册表 用的是切片返回的 slice.position()。
MetadataHandler(唯一同时写 metadata 字段的处理器)
| 方向 | 实现 |
|---|---|
| 写 | data.writeByte(info.getMetadata()) |
| 读 | info.setMetadata(data.readUnsignedByte()) |
读写不对称:写用 writeByte(有符号,metadata > 127 会变负),
读用 readUnsignedByte(0~255),往返后 metadata 高 8 位的符号位信息不保留。
BlockLightHandler / MetadataHandler(chunk 路径)
逐子区块 get*Array().data 直接 buffer.put / buffer.get 整段拷贝,
写入条件统一为 storageArrays[l] != null && (!sendUpdates || !isEmpty()) && (flagSubChunks & 1 << l) != 0。
SkylightHandler(读写不对称)
| 方向 | 是否检查 hasNoSky |
|---|---|
| 写 | 是 —— 整个方法体包在 if (!chunk.worldObj.provider.hasNoSky) 内,无天空维度不写任何数据 |
| 读 | 否 —— 直接按 flagSubChunks 读入 |
由于注册表按真实长度切片,读取侧即使遇到零长分片也能正确跳过,故此不对称不会造成 错位。代价是无天空维度仍占用 32,768 字节预算。
BlockMSBHandler(唯一两趟写、唯一会改动区块数组结构)
写路径:先 buffer.position(start + 2) 预留 flagMsb 的 2 字节 → 第一趟扫描统计
哪些子区块的 getBlockMSBArray() 非 null 并置位 → 第二趟写入 MSB 数据 → 回退到
start 处 putShort((short) (flagMsb & 65535)) → 恢复 position。
读路径:先读 flagMsb;对置位的子区块,MSB 数组为 null 时先调
createBlockMSBArray() 再读;未置位但 sendUpdates 且 MSB 数组已存在时调
clearMSBArray() 清理。
即 MSB 数组是按需创建的:绝大多数方块 ID < 32768 时 flagMsb 恒为 0,不传输
任何 MSB 数据,但那 32 字节(2 × 16 子区块)仍计入预算。
BiomeHandler(只搬运已有群系 ID)
writeChunkPacket / readChunkPacket 都先判 if (sendUpdates),然后整体
buffer.put(chunk.getBiomeArray()) / buffer.get(biomeArray),共 256 字节。
需要强调:本处理器不定义、不注册、不生成任何群系,它只是把 Chunk 里已存在的
群系 ID 数组搬进封包。因此 Foundation 没有群系维度的内容。
数值
| 数值 | 值 |
|---|---|
| 内置 chunk handler 数 | 6 |
| 内置 block handler 数 | 2(与上表 #1、#2 为同一批对象) |
chunkPacketBytes 合计 |
196,896 |
| 其中 MSB 标志字节 | 32(2 × 16 子区块) |
| 其中群系字节 | 256 |
子区块数(getBlockStorageArray().length) |
16 |
| 单方块封包中 block 字段编码 | VarInt |
| 单方块封包中 metadata 字段编码 | 1 字节(写有符号 / 读无符号) |