客户端方块变换器 API

基本信息

属性 值
类型 特殊机制(供其它 mod 调用的公开 API)
注册表 com.gtnewhorizons.pseudo.api.ClientBlockTransformerRegistry(api/ClientBlockTransformerRegistry.java:13)
变换器接口 com.gtnewhorizons.pseudo.api.IClientBlockTransformer(api/IClientBlockTransformer.java:19)
存储 静态 ArrayList<IClientBlockTransformer> TRANSFORMERS(api/ClientBlockTransformerRegistry.java:15)

功能

让其它 mod 在方块发给客户端之前改写其方块 ID 与 metadata,从而让客户端看到与服务器不同的方块, 而无需真的去改服务器的世界。javadoc 原文(api/IClientBlockTransformer.java:14-18): “transform a block before it is sent to the client … useful for situations where the client must see a non-TE block without mutating the server’s world”。

变换器需要实现什么

唯一抽象方法(api/IClientBlockTransformer.java:31):

boolean transformBlock(World world, int x, int y, int z, BlockMeta blockMeta);
  • blockMeta 是原地修改对象:改这个对象即改结果(api/IClientBlockTransformer.java:28)。
  • 返回 true 表示"我改了",返回 false 表示没动。返回值直接决定是否写回缓冲区 (api/IClientBlockTransformer.java:62-65)。
  • 坐标是世界坐标(x/y/z),不是区块或段内局部坐标。

transformBulk 有默认实现(api/IClientBlockTransformer.java:41-67), 实现者可以只写 transformBlock:默认实现会为每个位置造一个复用的 BlockMeta(初始 Blocks.air, 0),逐个调用 transformBlock,返回 true 时把结果写回 blocks / metas。

注册与调度

API 行为 来源
registerTransformer(IClientBlockTransformer) 追加到列表末尾,无去重、无优先级、无移除接口 api/ClientBlockTransformerRegistry.java:17-19
transformBlock(...) 按注册顺序遍历全部变换器,返回值用 |= 累积,即任一变换器返回 true 即为 true;size 在循环开始时快照(api/ClientBlockTransformerRegistry.java:21-32) 同左
transformBulk(...) 同样按注册顺序全部调用一遍,返回 void api/ClientBlockTransformerRegistry.java:34-41

⚠️ 多个变换器会串联:后一个拿到的 blockMeta 是前一个改完后的结果,顺序即优先级。 注册顺序由各 mod 的 init 阶段决定,本 mod 不做任何排序。

性能辅助:BlockIdCache

IClientBlockTransformer.BlockIdCache(api/IClientBlockTransformer.java:69-95)是内嵌的单槽位缓存, getId(Block) / getBlock(int) 各缓存最后一个查询结果,用于在批量循环里避免反复 Block.getIdFromBlock / Block.getBlockById。

限制与源码问题

  • 批量长度取 capacity() 而非 limit():api/IClientBlockTransformer.java:45 用 blocks.capacity() 决定遍历长度,随后以绝对索引 blocks.get(i) / blocks.put(i, ...) 访问。 当前唯一调用方传入的是 IntBuffer.allocate 后 flip() 的整块缓冲(managers/PseudoBlockManager.java:68-98), 此时 capacity == limit 才碰巧正确;若第三方传入 slice 或未 flip 的缓冲,会读到未初始化数据 或抛 BufferOverflowException。同一问题在 managers/PseudoBlockManager.java:111 重复出现。
  • transformBlock 的 world 可能为 null:见 BlockManager 数据管理器 中 managers/PseudoBlockManager.java:142 的说明。
  • 变换器列表不可撤销:注册后无法移除,调试期只能靠改注册顺序调整。

相关条目