转换器链(ASM Transformer Chain)
基本信息
| 属性 | 值 |
|---|---|
| 类型 | coremod / ASM 字节码转换 |
| 入口类 | com.gtnewhorizons.foundation.core.FoundationCore |
| 实际转换器 | com.gtnewhorizons.foundation.core.FoundationTransformer |
| 转换器注册表 | com.gtnewhorizons.foundation.core.FoundationTransformers(枚举) |
| 转换器接口 | com.gtnewhorizons.foundation.core.IFoundationTransformer |
| 转换器总数 | 1 个 |
| 生效阶段 | EARLY(由 IEarlyMixinLoader 在类加载早期提供) |
行为
Foundation 自己不直接实现 IClassTransformer。FoundationCore 通过
getASMTransformerClass() 只返回一个类名 FoundationTransformer,由 FML 把它
注入到全局类转换链。FoundationCore 同时实现 IEarlyMixinLoader,用
getMixinConfig() 返回 mixins.foundation.early.json,用
getMixins(Set<String> loadedCoreMods) 交回 IMixins.getEarlyMixins(Mixins.class, loadedCoreMods)
——即 mixin 的筛选与挂载委托给 GTNHLib,详见 Mixin 配置。
FoundationCore(coremod 容器)
继承 DummyModContainer 并实现 IFMLLoadingPlugin、IEarlyMixinLoader。
| 成员 | 返回值 / 内容 | 备注 |
|---|---|---|
@IFMLLoadingPlugin.MCVersion |
1.7.10 |
|
@IFMLLoadingPlugin.TransformerExclusions |
{"com.gtnewhorizons.foundation.core"} |
排除自身 core 包,避免转换器在过早期阶段被 ASM 转换 |
DEFAULT_TRANSFORMERS |
new String[0] |
空数组,全仓库无任何读写(grep 仅命中定义处 core/FoundationCore.java:20) |
getASMTransformerClass() |
{ FoundationTransformer.class.getName() } |
唯一注册的转换器 |
getModContainerClass() |
"com.gtnewhorizons.foundation.core.FoundationCore" |
|
getSetupClass() |
null |
无 setup 阶段 |
injectData(Map<String, Object>) |
空实现 {} |
不读取任何 FML 注入数据 |
getAccessTransformerClass() |
null |
不使用 AT(accessTransformersFile 亦为空) |
getMixinConfig() |
"mixins.foundation.early.json" |
|
getMixins(...) |
IMixins.getEarlyMixins(Mixins.class, loadedCoreMods) |
构造函数把 ModMetadata 设为 autogenerated = true、modId = name = "Foundation Core"、
parent = "foundation"、version = Tags.VERSION。
FoundationTransformer(调度器)
transform(String name, String transformedName, byte[] basicClass) 的判定顺序:
basicClass == null→ 直接return null。FoundationTransformers.get(transformedName)为null→ 原样return basicClass。 这是一条快速路径:绝大多数类根本不会被解析成 ASM 树。- 否则
ClassReader.accept(cn, 0)构建ClassNode,按get()返回的List顺序逐个 调用transformer.transform(cn)。 - 用
MixinClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES)重新写回toByteArray()。
注意第 4 步:无论是否真的被改写,只要该类名命中了任何转换器的目标列表,就会走完整的 树解析 + 帧重算流程。
IFoundationTransformer(扩展接口)
只有两个方法,没有任何排序/优先级字段:
| 方法 | 签名 |
|---|---|
| 目标声明 | String[] getTargetClasses() |
| 改写入口 | void transform(final ClassNode cn) |
没有 order / priority 概念——执行顺序完全由枚举声明顺序(ordinal)决定。
FoundationTransformers(注册表)
枚举,每个常量持有一个 IFoundationTransformer 实例。静态初始化块:
for (final FoundationTransformers entry : values()) {
for (final String className : entry.transformer.getTargetClasses()) {
transformers.putIfAbsent(className, new ArrayList<>());
transformers.get(className).add(entry);
}
}
即:把「目标类全限定名」映射到「命中该类的转换器列表」。get(className) 返回该列表,
无目标类时返回 null(供 FoundationTransformer 走快速路径)。多个转换器若指向同一
目标类会按枚举顺序追加进同一列表,源码因此具备多转换器串联能力,尽管当前只注册了 1 个。
转换器全表
| 枚举常量 | 实现类 | 目标类(getTargetClasses()) |
改写的字节码 |
|---|---|---|---|
S22ConstructorTransformer |
core/transformers/S22ConstructorTransformer.java |
net.minecraft.network.play.server.S22PacketMultiBlockChange |
完全重写描述符 (I[SLnet/minecraft/world/chunk/Chunk;)V 的 <init> 方法体 |
S22ConstructorTransformer 细节
遍历 cn.methods,命中 mn.name.equals("<init>") && mn.desc.equals("(I[SLnet/minecraft/world/chunk/Chunk;)V")
后:
mn.instructions.clear()+mn.tryCatchBlocks.clear()—— 源码注释称之为「 nuking the entire instruction set」,实际效果等同于 ASM 层的@Overwrite。- 重新插入的指令序列(源码
core/transformers/S22ConstructorTransformer.java:30-50):
| 指令 | 说明 |
|---|---|
ALOAD 0 + INVOKESPECIAL net/minecraft/network/Packet.<init>()V |
补回 Packet 父类构造调用 |
ALOAD 0, ILOAD 1, ALOAD 2, ALOAD 3 |
原样传入 this 与构造参数 count / positions / chunk |
INVOKEINTERFACE com/gtnewhorizons/foundation/mixins/interfaces/IMixinS22PacketMultiBlockChange.newConstructor(I[SLnet/minecraft/world/chunk/Chunk;)V |
转发到 mixin 提供的新构造实现 |
RETURN |
补回返回 |
源码注释说明为何绕一圈用 ASM:目标是往 S22PacketMultiBlockChange 注入一个
newConstructor 供调用方读取 Chunk(原版构造丢弃了 chunk 引用),而该构造需要
整体重写;newConstructor 本身由 Mixin 清单 里的
MixinS22PacketMultiBlockChange 提供。
构造实现会在日志打印一行 Foundation.LOG.info("Hello from S22 ASM")(位于
newConstructor 末尾,源码 mixins/early/MixinS22PacketMultiBlockChange.java:40)——
这是该转换链生效的最直接可观测信号。
数值
| 数值 | 值 | 来源 |
|---|---|---|
| 注册的 ASM 转换器数量 | 1 | getASMTransformerClass() |
DEFAULT_TRANSFORMERS 长度 |
0 | FoundationCore.java:20 |
| 目标类数量 | 1 | S22ConstructorTransformer.getTargetClasses() |
| 补帧标志 | COMPUTE_MAXS | COMPUTE_FRAMES |
FoundationTransformer.java:34 |