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:

  1. 取 chunk.getBlockStorageArray(),按 subChunkMask 跳过未标脏的段 (managers/PseudoBlockManager.java:52-54)。
  2. 把段强转为 EndlessIDs 的 SubChunkBlockHook(managers/PseudoBlockManager.java:56), 取出 B 数组 eid$getB1/B2Low/B2High/B3 与 M 数组 eid$getM1Low/M1High/M2 (managers/PseudoBlockManager.java:58-65)。
  3. 逐位置解包:索引 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 处理。
  4. 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)。
  5. 调 ClientBlockTransformerRegistry.transformBulk(managers/PseudoBlockManager.java:110)。
  6. 把结果写回段内:此处的 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),而本类直接 import com.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), 缺失时会在类加载阶段直接失败而非给出依赖提示。

相关条目