====== 反射 ====== 与常规的 Java 开发相比,由于 Minecraft 在官方(混淆)、中间名和映射的(yarn 或者 mojmap)名称之间重映射,因此,通过反射寻找特定的字段或者方法需要格外小心。如果类是由原始的字符串名称找到的,例如 [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html#forName(java.lang.String)|Class.forName]],这些类也需要格外小心。(常量引用,如 MinecraftClient.class,由重映射器处理。) ===== 重映射 ===== //参见:[[mappings]]// 反射查找方法或字段时,建议通过中间名引用,因为在不同的 Minecraft 版本之间,中间名往往是保持恒定的(借助匹配),反射的代码可以在新版本的 Minecraft 中运行而无需发布新的模组版本。 例子: // 我们将使用解析器将中间名转换为运行时名称 MappingResolver resolver = FabricLoader.getInstance().getMappingResolver(); Class cls; // 将中间类名转化为运行时类名的例子 cls = Class.forName(resolver.mapClassName("intermediary", "net.minecraft.class_2960")); // 你也可以只适用类的常量引用,重映射器会处理: cls = Identifier.class; // 为 Identifier.getNamespace 创建一个方法处理: MethodHandles.Lookup lookup = MethodHandles.publicLookup(); // public 方法 MethodHandle namespaceGetter = lookup.findVirtual(cls, resolver.mapMethodName( "intermediary", // 反映射的例子,简单输出 "net.minecraft.class_2960" resolver.unmapClassName("intermediary", cls.getName()), "method_12836", "()Ljava/lang/String;" ), MethodType.methodType(String.class) ); ===== 记录 ===== 自从 1.18,原版 Minecraft 在代码中开始使用 [[https://docs.oracle.com/en/java/javase/16/language/records.html|记录]]。但是,由于 Minecraft 是使用 Proguard 处理的,会从 Minecraft 类中移除记录信息,因此这些记录类会在运行时有如下的行为,尽管在代码中反编译成了记录: recordClass.isRecord() == false recordClass.getRecordComponents() == null 结果就是,您无法通过反射找到原版类的记录组件。 参见 [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html#isRecord()|isRecord()]] 和 [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html#getRecordComponents()|getRecordComponents()]] 的 JDK 17 API 文档。 而且,proguard 会移除从记录中移除表示通用信息的签名(但不会从方法中移除)。Yarn 映射为这些类定义签名映射。这会影响对一些反射方法的调用的反射结果,例如 [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html#getTypeParameters()|recordClass.getTypeParameters()]],在引用了没有类型参数的记录的方法中调用 [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Method.html#getGenericReturnType()|getGenericReturnType()]] 可能会造成 MalformedParameterizedTypeException。