- ASM 是一个用于读取、修改和写入 JVM 字节码的 Java 库。
- 它作用于编译后的 .class 文件,因此可以在不重新编译的情况下重写一个类。
- 模组使用它在加载时修补已经编译的游戏。
- 大多数模组制作者使用 Mixin,它位于 ASM 之上并隐藏了细节.
ASM 是一个用于读取、修改和写入 JVM 字节码的 Java 库。它直接操作编译后的 .class 文件,而不是源代码,因此可以在不重新编译的情况下检查或重写类。Minecraft 模组依赖于它,因为它允许在游戏加载时对其进行补丁修改,即使游戏已经编译完成.
ASM 实际上做什么
ASM 将编译后的类转换为程序可以编辑的内容。一个 .class 文件仅仅是字节码,即 Java 虚拟机运行的指令。ASM 解析这些字节码,将方法和字段交给您,并允许您添加、删除或更改指令。然后,它将一个新的有效类写回。
纯粹的 Java 本身无法做到这一点。编译器将您的源代码编译成字节码一次,之后字节码就被固定了。ASM 在字节码层面上进行干预,这位于您通常编写的源代码层之下
它是如何运作的
ASM 使用 ClassReader 读取一个类,并使用 ClassWriter 写入一个类。 在两者之间,你的代码会访问类的各个部分并决定需要更改什么。 有两种方法可以做到这一点。
Visitor 模式会逐个元素地流式处理类。 这种方法速度快且内存占用少,因为它从不一次性持有整个类。 树模式将类加载到你可以自由地遍历和编辑的对象中,这对于较大的更改来说更容易理解,但会占用更多内存。
| 方式 | 工作原理 | 适用场景 |
|---|---|---|
| Visitor API | 读取时流式处理类事件 | 小而快速的编辑,内存占用低 |
| Tree API | 构建类的可编辑对象模型 | 更大或更复杂的重写 |
为什么 Minecraft 他们使用它
模组需要修改他们没有编写且无法重新编译的游戏代码。游戏以编译后的类形式发布,因此唯一的入口点是字节码级别,而 ASM 正好提供了这一点。一个模组可以在游戏方法中注入钩子,重定向调用,或添加字段,所有这些都在启动时完成。
大多数模组制作者不会直接调用 ASM。他们使用 Mixin,这是一个更高级的框架,它建立在 ASM 之上,并将简单的注解转换为底层的字节码修改。你只需要编写一个小的 Java 类来描述更改,框架就会为你处理使用 ASM 的底层工作。特别是 Fabric 模组,尤其依赖于这个链条。
何时需要直接接触 ASM
作为模组作者,你很少需要编写原始的 ASM 代码。它通常出现在工具需要比注解更多的控制权时,例如加载器、混淆器或重写整个类的补丁程序。对于日常模组来说,顶层的注解层就足够了,而且出错的可能性要小得多。
常见问题解答
不是。反汇编器将字节码转换回可读的源代码。ASM直接操作字节码,旨在修改它,而不是恢复源代码。
通常不需要。大多数 Fabric 模组使用 Mixin,它通过注解隐藏了 ASM 的细节。只有在需要精细控制时,才需要直接使用 ASM。
不是。ASM 是一个通用的 Java 库,被广泛应用于处理字节码的各种工具中。Minecraft 模组开发是其常见的用途之一,但并非唯一用途。
您无法这样做。游戏以编译后的形式发布,而不是您可以修改和重新编译的源代码。编辑字节码是修补您不拥有代码的实际方法。