我正在尝试为 Minecraft 1.12.2 编写一个 Forge mod。我想对主菜单进行修改(某些模组会这样做,所以我知道这是可能的),但我想要更改的内容(其他模组也会这样做)是私有变量。我这样做是通过扩展 GuiMainMenu 来实现的,但是我在使用私有变量时遇到了问题。特别是,我想将
GuiMainMenu.MINECRAFT_TITLE_TEXTURE
(这是一个 private static final
)绑定到纹理管理器,以便我可以像在香草主菜单中一样绘制 Minecraft 标题纹理,并且我想添加启动文本选项(如下所示: this.splashText = "example_splash";
)。 GuiMainMenu.splashText
是 private String
到目前为止,人们似乎使用反射来解决此类问题,这就是我尝试过的方法,代码如下:
private Field splashTextField;
private static Field minecraftTitleTextureField;
static {
initField("MINECRAFT_TITLE_TEXTURES", minecraftTitleTextureField);
}
private static void initField(String fieldName, Field destinationField) {
try {
// Accessing private variable using reflection
destinationField = GuiMainMenu.class.getDeclaredField(fieldName);
destinationField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace(); // Handle the exception appropriately
}
}
// Wrapper methods to handle IllegalAccessException
private static void setFieldValue(Object target, Field field, Object value) {
try {
field.set(target, value);
} catch (IllegalAccessException e) {
e.printStackTrace(); // Handle the exception appropriately
}
}
private static Object getFieldValue(Object target, Field field) {
try {
return field.get(target);
} catch (IllegalAccessException e) {
e.printStackTrace(); // Handle the exception appropriately
return null;
}
}
但是当我这样做时,当我尝试对这些变量中的任何一个执行任何操作时,我都会收到 NullPointerExceptions。我做错了什么?
评论者已经对如何使用反射进行修复给出了很好的解释,但对于后人来说,我发现为 Minecraft Forge Mod 开发执行此操作的常用方法是使用访问变压器,它可以完成所有正确的反射评论者提到,您不需要自己编写反射代码。反射仍然会影响性能,但使用访问转换器可以轻松做到这一点。
这涉及将
accesstransformer.cfg
添加到 src/main/resources/META-INF/
文件夹,并添加 github、这些文档 或 这些文档 上指定的行。然后,需要通过添加到minecraft块来在build.gradle文件中启用Access Transformer:
minecraft {
//// stuff before
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
//// stuff after
}
但是,如果你只这样做,它就会编译,并且当你这样做时它可能会正常运行
./gradlew runClient
,但是当你将 mod .jar 文件复制到 mods 文件夹中时,它将无法工作。这是因为需要告诉 forge modloader 有一个 Access Transformer 文件及其名称,以便它知道在运行时执行适当的反射。这是必要的,因为访问转换是由 forge 完成的,而不是由 mod 本身完成的。构建只需添加到minecraft{}块即可进行,因为这会对构建环境进行必要的更改才能成功构建。这有点像 Linux 中的链接器和 ld
。
因此,要使其在运行时工作,您需要将访问转换器文件添加到清单中,这应该通过 build.gradle 文件完成,如下所示:
jar {
manifest {
attributes([
"Specification-Title" : "sometitle",
"FMLAT": 'accesstransformer.cfg' // The name of the accesstransformer file
])
}
}
FMLAT 代表 Forge ModLoader 访问变压器。
(我对访问变压器也进行反射的看法可能是错误的,但我认为我的理解是正确的)