客户端方块变换器 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的说明。- 变换器列表不可撤销:注册后无法移除,调试期只能靠改注册顺序调整。
相关条目
- BlockManager 数据管理器 — 调用本 API 的 ChunkAPI 数据管理器