User Tools

Site Tools


ru:tutorial:reflection

Рефлексия

По сравнению с обычной разработкой Java, поскольку Minecraft был переназначен между официальными (запутанными), промежуточными именами и именами маппингов (yarn или mojmap), поиск определенных полей или методов для рефлексии и дескрипторов методов требует особой осторожности. Если классы найдены по буквальным строковым именам, как в Class.forName, они также требуют особого внимания. (Постоянные ссылки, такие как MinecraftClient.class обрабатываются ремапперами)

Ремаппинг

Смотрите также: Маппинги

Рекомендуется ссылаться на методы и поля по их промежуточным именам при поиске их для рефлексии, потому что промежуточные имена в основном остаются неизменными в разных версиях 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(); // это общедоступный метод
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 обрабатывается Proguard, который удаляет информацию о записях из классов Minecraft, эти классы записей будут иметь такое поведение во время выполнения, несмотря на то, что они декомпилированы как записи в исходном коде:

recordClass.isRecord() == false
recordClass.getRecordComponents() == null

Как следствие, вы не можете найти компоненты записи классов ванилы с рефлексией.

Смотрите документацию по JDK 17 API для isRecord() и getRecordComponents().

Кроме того, Proguard также удаляет подпись (которая указывает общую информацию) из классов записей (но не из их методов). Маппинги Yarn определяют маппинги подписей для этих классов. Это влияет на результаты рефлексии при вызовах некоторых методов рефлексии, таких как recordClass.getTypeParameters(), и вызывающий getGenericReturnType() в методах, которые ссылаются на отсутствующие параметры типа в записях, может вызвать исключение MalformedParameterizedTypeException.

ru/tutorial/reflection.txt · Last modified: 2022/03/12 15:04 by 127.0.0.1