访问转换器

访问转换器

访问转换器(Access Transformer,简称 AT)可以扩大类、方法和字段的可见性,并修改其 final 标记。它使 Mod 开发者能够访问或修改不受自己控制的类中原本不可访问的成员。

可以在 NeoForged 的 GitHub 上查阅规范文档。

添加 AT

在 Mod 项目中添加访问转换器很简单,只需在 build.gradle 中添加相应配置:

访问转换器需要在 build.gradle 中声明。AT 文件可以位于任何位置,只要编译时会被复制到 resources 输出目录即可。

ModDevGradle

默认情况下,这里不需要做任何操作!

NeoGradle

// In build.gradle:
minecraft {
    accessTransformers {
        file 'src/main/resources/META-INF/accesstransformer.cfg'
    }
}

NeoForge 默认查找 META-INF/accesstransformer.cfg。如果在 build.gradle 中指定了其他位置,还需要在 neoforge.mods.toml 中声明相应路径:

# In neoforge.mods.toml:
[[accessTransformers]]
## The file is relative to the output directory of the resources, or the root path inside the jar when compiled
## The 'resources' directory represents the root output directory of the resources
file="META-INF/accesstransformer.cfg"

还可以指定多个 AT 文件,它们会按顺序应用。这对于包含多个包的大型 Mod 很有用。

ModDevGradle

// In build.gradle:
neoForge {
    // ModDevGradle already tries to include 'src/main/resources/META-INF/accesstransformer.cfg' by default
    accessTransformers.from 'src/additions/resources/accesstransformer_additions.cfg'
}

NeoGradle

// In build.gradle:
minecraft {
    accessTransformers {
        file 'src/main/resources/META-INF/accesstransformer.cfg'
        file 'src/additions/resources/accesstransformer_additions.cfg'
    }
}
# In neoforge.mods.toml
[[accessTransformers]]
file="accesstransformer.cfg"

[[accessTransformers]]
file="accesstransformer_additions.cfg"

每次添加或修改访问转换器后,都必须刷新 Gradle 项目,转换才会生效。

访问转换器规范

注释

从 # 到行尾的所有文本都视为注释,不会参与解析。

访问修饰符

访问修饰符决定目标成员转换后的可见性。按可见性从大到小排列如下:

  • public:包内和包外的所有类均可访问。
  • protected:仅同包中的类和子类可访问。
  • default:仅同包中的类可访问。
  • private:仅类内部可访问。

可以在以上修饰符后附加特殊修饰符 +f 或 -f,分别添加或移除 final。final 用于禁止继承、方法重写或字段修改,具体取决于它修饰的目标。

重要警告 指令仅修改它直接引用的方法,不会转换重写该方法的其他方法。应确保转换后的方法不存在仍保留较小可见性的未转换重写方法,否则 JVM 会抛出错误。

通常可以安全转换的方法包括 final 方法(或 final 类中的方法)和 static 方法。private 方法通常也安全,但可能在子类型中造成意外的方法重写,因此需要额外人工检查。

目标与指令

类

指定类的语法:

<access modifier> <fully qualified class name>

内部类通过外部类的完全限定名与内部类名组合表示,中间以 $ 分隔。

字段

指定字段的语法:

<access modifier> <fully qualified class name> <field name>

方法

指定方法时,需要使用特殊语法表示参数和返回类型:

<access modifier> <fully qualified class name> <method name>(<parameter types>)<return type>
指定类型

这些类型表示也称为“描述符”。技术细节可参阅 Java 虚拟机规范 SE 21 的 4.3.2 和 4.3.3 节。

  • B:byte,有符号字节。
  • C:char,UTF-16 中的 Unicode 字符编码单元。
  • D:double,双精度浮点值。
  • F:float,单精度浮点值。
  • I:integer,32 位整数。
  • J:long,64 位整数。
  • S:short,有符号短整数。
  • Z:boolean,值为 true 或 false。
  • [:表示数组的一个维度。
    • 例如,[[S 表示 short[][]。
  • L<class name>;:表示引用类型。
    • 例如,Ljava/lang/String; 表示 java.lang.String 引用类型。注意使用斜杠而非句点。
  • (:表示方法描述符,后面填写参数;没有参数时留空。
    • 例如,<method>(I)Z 表示接受一个整数参数并返回布尔值的方法。
  • V:表示方法没有返回值,只能用于方法描述符末尾。
    • 例如,<method>()V 表示无参数、无返回值的方法。

示例

# Makes public the ByteArrayToKeyFunction interface in Crypt
public net.minecraft.util.Crypt$ByteArrayToKeyFunction

# Makes protected and removes the final modifier from 'random' in MinecraftServer
protected-f net.minecraft.server.MinecraftServer random

# Makes public the 'makeExecutor' method in Util,
# accepting a String and returns a TracingExecutor
public net.minecraft.Util makeExecutor(Ljava/lang/String;)Lnet/minecraft/TracingExecutor;

# Makes public the 'leastMostToIntArray' method in UUIDUtil,
# accepting two longs and returning an int[]
public net.minecraft.core.UUIDUtil leastMostToIntArray(JJ)[I

来源: NeoForged/Documentation(26.1)。中文翻译依据提交 4a680cdd4d15。