BlockManager 数据管理器
基本信息
| 属性 | 值 |
|---|---|
| 类型 | 特殊机制(ChunkAPI 数据管理器) |
| 实现类 | com.gtnewhorizons.pseudo.managers.PseudoBlockManager(managers/PseudoBlockManager.java:23) |
| 实现的接口 | DataManager.PacketDataManager、DataManager.BlockPacketDataManager |
| domain | pseudo(managers/PseudoBlockManager.java:26-28) |
| id | blockmanager(managers/PseudoBlockManager.java:31-33) |
| maxPacketSize | 1(managers/PseudoBlockManager.java:36-38) |
| 注册位置 | Pseudo.java:21 DataRegistry.registerDataManager(new PseudoBlockManager(), 1000) |
| 注册优先级 | 1000(第二参数,数值越大越先) |
作用
在区块发包 / 单方块更新发包的出口处,把方块 ID 与 metadata 交给
ClientBlockTransformerRegistry 改写,使客户端看到与服务器不同的方块,而无需修改服务器的世界数据。
各接口方法的行为
| 方法 | 是否实现 | 行为 |
|---|---|---|
readFromBuffer |
是 | 实际工作入口,见下 |
writeToBuffer |
是但空实现 | 不做任何序列化(managers/PseudoBlockManager.java:41-43) |
writeBlockToPacket |
是 | 改写 S23PacketBlockChange 的 block/meta(managers/PseudoBlockManager.java:122-128) |
readBlockFromPacket |
是但空实现 | (managers/PseudoBlockManager.java:131-133) |
writeBlockPacketToBuffer |
是 | 仅当 packet 是 CustomPacketBlockChange 时改写(managers/PseudoBlockManager.java:136-147) |
readBlockPacketFromBuffer |
是但空实现 | (managers/PseudoBlockManager.java:150-152) |
三个空实现说明本 mod 是单向的:只改写"发给客户端"的内容,不反向解析。
readFromBuffer 流程
managers/PseudoBlockManager.java:46-119:
- 取
chunk.getBlockStorageArray(),按subChunkMask跳过未标脏的段 (managers/PseudoBlockManager.java:52-54)。 - 把段强转为 EndlessIDs 的
SubChunkBlockHook(managers/PseudoBlockManager.java:56), 取出 B 数组eid$getB1/B2Low/B2High/B3与 M 数组eid$getM1Low/M1High/M2(managers/PseudoBlockManager.java:58-65)。 - 逐位置解包:索引
j的半字节位置为j >> 1,移位量(j & 1) == 0 ? 0 : 4; B 最高 24 位(b1 8 位 + b2Low 4 位 + b2High 4 位 + b3 8 位), M 最高 12 位(m1low 4 位 + m1high 4 位 + m2 8 位) (managers/PseudoBlockManager.java:71-95)。b2/b3 为 null 时对应位段按 0 处理。 flip()后用IntToLongFunction把线性索引还原为打包坐标:x = j & 0xF,z = (j >> 4) & 0xF,y = (j >> 8) & 0xFF, 再加上 chunk 起点chunk.xPosition * 16/chunk.zPosition * 16与ebsY(managers/PseudoBlockManager.java:102-108)。- 调
ClientBlockTransformerRegistry.transformBulk(managers/PseudoBlockManager.java:110)。 - 把结果写回段内:此处的
y是段内局部坐标(j >> 8) & 0x0F, 调eid$setID/eid$setMetadata(managers/PseudoBlockManager.java:111-117)。
数值
| 数值 | 值 | 来源 |
|---|---|---|
| 注册优先级 | 1000 | Pseudo.java:21 |
| maxPacketSize | 1 | managers/PseudoBlockManager.java:37 |
| B 值位宽 | 24 bit | managers/PseudoBlockManager.java:75-84 |
| M 值位宽 | 12 bit | managers/PseudoBlockManager.java:87-93 |
限制
- 变换会写回服务器端段存储:第 6 步用
eid$setID/eid$setMetadata直接改ExtendedBlockStorage,而不是只改发包缓冲区(managers/PseudoBlockManager.java:115-116)。 也就是说变换结果会落进服务器区块数据,并非仅在发包时临时改写。 writeBlockPacketToBuffer传入 null 世界:ClientBlockTransformerRegistry.transformBlock(null, x, y, z, bm)(managers/PseudoBlockManager.java:142),但IClientBlockTransformer的 javadoc 只写@param world The world(api/IClientBlockTransformer.java:25),未声明可为 null, 实现方若直接访问 world 会 NPE。- 依赖硬引用但未在
@Mod声明:@Mod注解无dependencies字段 (Pseudo.java:12),而本类直接 importcom.falsepattern.chunk.*、com.falsepattern.endlessids.mixin.helpers.SubChunkBlockHook、com.gtnewhorizon.gtnhlib.util.data.BlockMeta。这三个在dependencies.gradle中是api依赖(chunkapi-mc1.7.10:0.7.0-alpha-01、endlessids-mc1.7.10:1.6.12、GTNHLib:0.6.40), 缺失时会在类加载阶段直接失败而非给出依赖提示。
相关条目
- 客户端方块变换器 API — 本管理器调用的变换器注册表