V2ConstructionReplacerTransformer

基本信息

属性 值
类 com.mitchej123.jarjar.rfb.transformer.V2ConstructionReplacerTransformer
Transformer ID jarjar-v2-construction-replacer
RFB 排序 sortBefore = ["*"]
目标类(4 个) cpw.mods.fml.common.Loader, cpw.mods.fml.common.ModContainerFactory, cpw.mods.fml.common.discovery.ModDiscoverer, cpw.mods.fml.common.discovery.asm.ASMModParser

FMLTransformer 只能改 INVOKESTATIC 调用;构造表达式 new Loader() / new ModContainerFactory() / new ModDiscoverer() / new ASMModParser(InputStream) 的重写由 V2ConstructionReplacerTransformer 完成。

改写规则

每个目标类有专属的 methodName/desc/originalClass/newClass:

目标类 方法 改写
Loader instance ()Lcpw/mods/fml/common/Loader; NEW cpw/mods/fml/common/Loader → NEW com/mitchej123/jarjar/fml/common/LoaderV2
ModContainerFactory <clinit> ()V NEW cpw/mods/fml/common/ModContainerFactory → NEW com/mitchej123/jarjar/fml/common/ModContainerFactoryV2
ModDiscoverer <init> ()V NEW cpw/mods/fml/common/discovery/ASMDataTable → NEW com/mitchej123/jarjar/fml/common/discovery/ASMDataTableV2
ASMModParser <init> (Ljava/io/InputStream;)V NEW cpw/mods/fml/common/discovery/asm/ModClassVisitor → NEW com/mitchej123/jarjar/fml/common/discovery/asm/ModClassVisitorV2(同时 INVOKESPECIAL owner 改写)

通用方法

private void transformClass(ClassNode cn, String methodName, String desc,
                            String originalClass, String newClass, String newClassDesc, String newNewClassDesc) {
    for (MethodNode mn : cn.methods) {
        if (!(mn.name.equals(methodName) && mn.desc.equals(desc))) continue;
        for (int i = 0; i < mn.instructions.size(); i++) {
            AbstractInsnNode aInsn = mn.instructions.get(i);
            if (aInsn.getOpcode() == Opcodes.NEW && aInsn instanceof TypeInsnNode tInsn) {
                if (tInsn.desc.equals(originalClass)) tInsn.desc = newClass;
            } else if (aInsn.getOpcode() == Opcodes.INVOKESPECIAL && aInsn instanceof MethodInsnNode mInsn) {
                if (mInsn.owner.equals(originalClass) && mInsn.name.equals("<init>") && mInsn.desc.equals(newClassDesc)) {
                    mInsn.owner = newClass;
                }
            }
        }
    }
}

对每个目标方法体里:

  • NEW <originalClass> → 描述符改为 <newClass>
  • INVOKESPECIAL <originalClass>.<init>(<newClassDesc>) → owner 改为 <newClass>

newNewClassDesc 用于 ASMModParser 的特殊情况:原 ModClassVisitor 构造接受 (Lcpw/mods/fml/common/discovery/asm/ASMModParser;)V,新 ModClassVisitorV2 改为 (Lcom/mitchej123/jarjar/fml/common/discovery/asm/ASMModParserV2;)V。transformer 不改 desc —— 描述符变化由 ASMModParserV2 重写 ASMModParser(InputStream) 构造函数实现(在那里 new ModClassVisitor(this) 自动通过 type 推断指向 ModClassVisitorV2)。

shouldTransformClass

return className.equals(LOADER_CLASSNAME) || className.equals(MOD_CONTAINER_FACTORY_CLASSNAME)
    || className.equals(MOD_DISCOVERER_CLASSNAME) || className.equals(ASM_MOD_PARSER_CLASSNAME);

精确匹配 4 个 FML 顶层类,避免对其它类扫描。

与 FMLTransformer 的分工

Transformer 操作 涉及位置
FMLTransformer 静态方法调用 (INVOKESTATIC) 方法体内任意位置
V2ConstructionReplacerTransformer 对象构造 (NEW + INVOKESPECIAL) 类初始化 / 单例获取

两者组合后,调用方既有的 Loader.instance() → LoaderV2.instance(),又有的 MetadataCollection.from(...) → MetadataCollectionV2.from(...)。

相关条目