JavaAgent

虽然FML从未使用过JavaAgent来对Minecraft进行修改,但是这也是一种合理的动态修改方式。 JavaAgent由JVM进行支持,可以在class文件被加载时对其进行动态的修改。

制作方法

JavaAgent由以下几部分组成——premain方法、ClassFileTransformer接口。

premain

premain方法会在Java的入口方法main前执行。 一个典型的写法如下:

package com.example;

import java.lang.instrument.Instrumentation;

public class ExampleAgent {
  public static void premain(String args, Instrumentation instrumentation){
      //TODO: 在此补充代码
  }
}

这个方法可以获得一个Instrumentation的实例,通过这个实例我们可以注册ClassFileTransformer

ExampleTransformer transformer = new ExampleTransformer();
instrumentation.addTransformer(transformer);

premain方法和main方法一样,需要写入Manifest才能使JVM执行,我们可以通过修改gradle.build的方式加入:

jar {
    manifest {
        attributes([
                "Premain-Class": "com.example.ExampleAgent"
        ])
    }

ClassFileTransformer

这个接口只有一个方法transform,需要返回修改完后的class文件byte数组,这个方法会在ClassLoaderdefineClass时被调用,参数如下:

  • loader,当前使用的ClassLoader

  • className,当前加载的class名称

  • classBeingRedefined,为retransform设计,重新加载前的Class对象

  • protectionDomain,保护的域

  • classfileBuffer,class文件的byte数组

一个没有任何作用的ClassFileTransformer如下:

package com.example;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class ExampleTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader,
                            String className,
                            Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer) throws IllegalClassFormatException {
        //TODO: 可以在此写ASM代码
        return classfileBuffer;
    }
}

安装方法

在游戏的JVM参数中加入:

-javaagent:filename=args
  • filename为jar的文件名

  • args为传入premain方法的参数

弊端

  • 需要用户修改JVM参数来使用JavaAgent,相对于其他安装方法较为麻烦

  • 优先级过低,一般情况下都是最后一个对类进行修改

Last updated