Access Transformer
基本信息
| 属性 | 值 |
|---|---|
| 文件 | src/main/resources/META-INF/chunkapi_at.cfg |
| 构建声明 | build.gradle.kts → core { accessTransformerFile = "chunkapi_at.cfg" } |
| 规则数 | 4 条(3 条 public-f + 1 条 public) |
getAccessTransformerClass() |
返回 null |
| 目标类数 | 2 个:NibbleArray、PlayerManager$PlayerInstance |
⚠️ AT 确实生效,但它不经 IFMLLoadingPlugin。CoreLoadingPlugin.getAccessTransformerClass() 返回 null(见 核心 mod 与读档闸门),AT 由 build.gradle.kts 的 accessTransformerFile 交给构建插件注册。只看 getAccessTransformerClass() 会误判本 mod 没有 AT。
全部 4 条规则(verbatim)
public-f net.minecraft.world.chunk.NibbleArray field_76585_a # data
public-f net.minecraft.world.chunk.NibbleArray field_76583_b # depthBits
public-f net.minecraft.world.chunk.NibbleArray field_76584_c # depthBitsPlusFour
public net.minecraft.server.management.PlayerManager$PlayerInstance
| # | 修饰 | 目标 | SRG 字段 | 注释给出的可读名 |
|---|---|---|---|---|
| 1 | public-f(public + final) |
net.minecraft.world.chunk.NibbleArray |
field_76585_a |
data |
| 2 | public-f |
net.minecraft.world.chunk.NibbleArray |
field_76583_b |
depthBits |
| 3 | public-f |
net.minecraft.world.chunk.NibbleArray |
field_76584_c |
depthBitsPlusFour |
| 4 | public(整个类) |
net.minecraft.server.management.PlayerManager$PlayerInstance |
— | — |
⚠️ 前 3 条用 -f 保留 final。源码里 NibbleArray.depthBitsPlusFour 与 depthBits 都被重新赋值(ArrayUtil.copyArray 的 NibbleArray 重载),因此 AT 只公开化而不取消 final——赋值靠的是 mixin 之外另一条路径或 decompiler 产物,属源码层面的不一致(见下)。
用途一:NibbleArray 的三个字段
ArrayUtil.copyArray(NibbleArray, NibbleArray) 直接写 dstArray.depthBits = ... / dstArray.depthBitsPlusFour = ... / dstArray.data = ...,并读 srcArray.data / srcArray.depthBits。这 3 个字段在 1.7.10 原版是 private,没有 AT 就无法编译。见 数组工具类。
⚠️ 源码层面确实与 -f 冲突:ArrayUtil 里两行 dstArray.depthBits = srcArray.depthBits; 与 dstArray.depthBitsPlusFour = srcArray.depthBitsPlusFour; 是对 final 字段的写入。编译器会对 final 实例字段的外部写入报错,除非通过其他手段(如字段可变性的编译期宽松处理)绕过。原仓库能构建通过,说明实际编译环境允许——但 AT 的 -f 与源码写法不一致是客观事实。
对应地,NibbleManager(以及继承它的 4 个 manager)也读 getNibbleArray(subChunk).data,见 内置原版数据管理器。
用途二:PlayerManager$PlayerInstance
第 4 条把整个内部类 PlayerManager$PlayerInstance 公开化,供 PlayerInstanceMixin 混入:
@Mixin(PlayerManager.PlayerInstance.class)
public abstract class PlayerInstanceMixin {
@Redirect(method = "sendChunkUpdate",
at = @At(value = "NEW",
target = "(I[SLnet/minecraft/world/chunk/Chunk;)Lnet/minecraft/network/play/server/S22PacketMultiBlockChange;"),
require = 1)
private S22PacketMultiBlockChange hijackPacket(int count, short[] positions, Chunk chunk) {
val packet = new S22PacketMultiBlockChange();
((CustomPacketMultiBlockChange) packet).chunkapi$init(count, positions, chunk);
return packet;
}
}
见 Mixin 清单。该 mixin 没有任何 @Shadow,全部依赖这条 AT。
⚠️ 这是本 mod 唯一的 public(非 public-f)规则,也是唯一针对内部类($PlayerInstance)的规则。
不经 AT 获取的字段
以下字段访问不由 AT 提供,而是靠 mixin 的 @Shadow 或包内可见性:
| 字段 | 所属类 | 获取方式 |
|---|---|---|
chunk.heightMap |
Chunk |
ChunkMixin 的 @Shadow(但 LightingManager 直接在自己的类里读写 chunk.heightMap —— 依赖 Chunk 的字段可见性,见下) |
chunk.isLightPopulated |
Chunk |
ChunkMixin 的 @Shadow |
packet.field_148883_d、field_148884_e |
S23PacketBlockChange |
S23PacketBlockChangeMixin 的 @Shadow public |
⚠️ LightingManager.writeChunkToNBT / readChunkFromNBT / cloneChunk 在 internal.vanilla 包里直接读写 chunk.heightMap 与 chunk.isLightPopulated,而 ChunkMixin 又把这些字段 @Shadow 了出来。两条路径的可见性需求不同,源码未加注释说明 LightingManager 是靠什么拿到访问权的(既无 AT 规则、也不同包)。
规则数与构建配置的一致性
| 来源 | 内容 |
|---|---|
src/main/resources/META-INF/chunkapi_at.cfg |
4 条规则 |
build.gradle.kts 的 core { accessTransformerFile } |
指向 "chunkapi_at.cfg",位于 META-INF/ 下 |
CoreLoadingPlugin.getAccessTransformerClass() |
null |
build.gradle.kts 的 core { coreModClass } |
"internal.core.CoreLoadingPlugin" |
见 随包资源清单。
相关条目
- Mixin 清单 — 使用这 4 条 AT 的
ArrayUtil与PlayerInstanceMixin - 核心 mod 与读档闸门 —
getAccessTransformerClass()返回 null 的原因 - 数组工具类 —
NibbleArray重载对 3 个字段的直接赋值 - 随包资源清单 — AT 文件在包内的位置