使用 Access Transformer
由于 Minecraft 的部分代码一开始设计时并没有希望外部代码进行调用,所以说当你希望访问一个非公有(Public)的字段或方法时,事情就变得麻烦了起来。虽然你可能会通过使用反射(Reflection)的方式使用这些字段或方法,但由于 MCP 的存在,你不得不考虑两种不同的名称——用于开发环境的 MCP 名以及用于生产环境的 Searge 名。
作为示例,你可能会使用反射的方式调用 tick()
方法,这一方法在开发环境中的名字为 tick
,而在生产环境中的名字为 func_71217_p
。对于插件的重混淆(Reobfuscation)操作只会修改针对方法或字段的直接引用,而通过反射引用的字符串名称不会发生变化。
ForgeGradle 提供了一种名为 Access Transformer 的解决方案。该方案会将开发者指定的方法或字段的访问级设置为公有,这样你就可以直接引用它们,而不是使用诸如反射的间接方式。虽然这主要应用于 Minecraft 的源代码,但你也可以将其应用到一些第三方项目的类上。一旦你将 Access Transformer 的配置在 JAR 的 Manifest 文件中指明,SpongeVanilla 和 Forge 就会在生产环境中自动应用它们。
設定
ForgeGradle 会自动在你的资源文件夹(Resource Folder)中寻找以 _at.cfg
结尾的配置文件。如果你想要在运行时使用 Access Transformer,你需要在你的资源文件夹下新建一个名为 META-INF
的文件夹,并将你的配置文件,如 META-INF/myplugin_at.cfg
放进去。
有三种不同类型的 AT,分别用于对类、字段、和方法作出修改。Access Transformer配置中的每一行由两个(对于类而言)或三个(对于方法和字段而言)部分,部分与部分之间使用空格隔开。
用于修改方法或字段的访问级标识符,如
public
或protected
等。如果你还想同时去除final
修饰符,你可以在其后添加-f
标记,如public-f
一个类的全名,如
net.minecraft.server.MinecraftServer
字段或方法的 Searge 名(方法需要添加相应的方法签名),如
field_54654_a
或func_4444_a()V
小訣竅
你可以通过添加 #
前缀以添加注释。一个良好的习惯是为每行 AT 都写相应的注释,这样每一个字段或方法的引用就一目了然。
下面是几行 Access Transformer 的示例:
public-f net.minecraft.server.MinecraftServer field_71308_o # anvilFile
public net.minecraft.server.MinecraftServer func_71260_j()V # stopServer
public-f net.minecraft.item.ItemStack
如果你想要在你的开发环境中应用 Access Transformer,你需要重新运行一遍名为 setupDecompWorkspace
的 Gradle 任务,同时更新你的 Gradle 项目。
gradle setupDecompWorkspace
小訣竅
你可以使用 MCP Bot 以快速地获取用于字段和方法的 Access Transformer 配置。MCP Bot 在 MCP 和 Sponge 的 IRC 频道中都有提供。你也可以在 MCP 的 Discord 服务器的 #bot-spam
频道找到 MCP Bot。当使用诸如 !gm <mcp method name>
或 !gf <mcp field name>
的方式查找字段和方法对应的 AT 配置后,你只需要直接地把输出复制进你的 AT 配置就可以了。
備註
AT 并不支持使字段或方法的访问级变严格(如 public
-> private
)的行为。
生产环境
如果你想要把 AT 应用于生产环境,你需要在你的插件 JAR Manifest 中添加 FMLAT
选项,并注明你的位于 META-INF
目录下的 Access Transformer 配置文件名。
jar {
manifest.attributes('FMLAT': 'myplugin_at.cfg')
}