转换器链(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) 的判定顺序:

  1. basicClass == null → 直接 return null。
  2. FoundationTransformers.get(transformedName) 为 null → 原样 return basicClass。 这是一条快速路径:绝大多数类根本不会被解析成 ASM 树。
  3. 否则 ClassReader.accept(cn, 0) 构建 ClassNode,按 get() 返回的 List 顺序逐个 调用 transformer.transform(cn)。
  4. 用 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

相关条目

  • Mixin 清单 - 被本链路重写构造的那个类所对应的 mixin 实现
  • Mixin 配置 - coremod 暴露的 mixin 配置文件与 Gradle 开关
  • 封包数据流 - S22 构造参数 short[] positions 的语义