Перейти к содержанию

Access Transformers#

Автор статьи — Dahaka, с редакцией под 1.15.

Во время написания мода иногда возникают ситуации, когда хочется использовать приватные методы и поля данных, но, к сожалению, мы не можем этого сделать. Первое, что приходит в голову, это использовать возможности рефлексии. И, естественно, это плохое решение проблемы, начиная с того, что падает производительность, заканчивая уродованием кода.

Но решение есть - трансформеры доступа (Access Transformers - AT). Смысл в том, что они позволяют изменить модификаторы доступа к полям и методам в исходниках майнкрафта(но не форджа - с 1.15 использовать трансформеры на его классах нельзя) сразу при сборке рабочего пространства (проекта), и это будет работать в отдельном клиенте из-за того, что forge в runtime (во время выполнения) меняет модификаторы доступа на public.

Перейдем к практике. Необходимо создать файл example_at.cfg в каталоге /src/main/resources/META-INF/. Имя example значения не имеет, можно выбрать любое. Например, <modid>. Но важно, чтобы файл заканчивался на _at.cfg. Сам файл описывает, какие методы и поля должны быть преобразованы.

# Это комментарий.

# Все поля в классе Item станут публичными.
public net.minecraft.item.Item *

# Суффикс -f позволяет снять модификатор final.
# Все поля в классе ItemStack станут публичными, изменяемыми.
public-f net.minecraft.item.ItemStack *

# Все методы в классе ItemStack станут публичными.
# Так делать нельзя, если класс кем-то наследуется. Возможно может не собраться рабочая среда.
# Это происходит из-за того, что в целевом классе модификаторы доступа методов изменятся, а в производных - нет.
# Т.е. будет ошибка компиляции.
public net.minecraft.item.ItemStack *()

# Для обращения к внутренним классам используется '$'.
# Все поля в классе Properties станут публичными.
public net.minecraft.item.Item$Properties *

# Поле maxDamage в классе Item станет публичным.
public net.minecraft.item.Item field_77699_b

# Метод Block#isSolid(BlockState) станет публичным.
public net.minecraft.block.Block func_76220_a(ILjava/lang/String;Lnet/minecraft/item/Item;)V

Магическая строка func_76220_a(ILnet/minecraft/block/BlockState;)V это srg имя с дескриптором. Узнать их можно, например, при помощи программки MCP Mapping Viewer(увы, с версиями выше 1.12.2 она не работает), или напрямую из маппингов. Скачиваем версию маппингов, указаную в build.gradle. Открываем все 3 файла через Notepad++ и ищем по всем файлам имя поля/метода.

После того как создали и заполнили файл example_at.cfg, необходимо найти в файле build.gradle следующую строку:

    // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')

Нам надо раскомментировать и заменить имя файла на своё. Теперь остается выполнить сборку и пересобрать проект. В результате вы увидите, что указанные поля и методы имеют public модификатор.

Заметки.

  1. Указывать можно не только public модификатор, но и protected. Правда я не знаю, для чего это может пригодится. И работать это будет только в сторону снятия инкапсуляции, но не наоборот.
  2. Печально, но иногда трансформер может не примениться, т.е. поле/метод так и останется инкапсулировано. Но это редкость. Зачастую это вставки forge.
  3. Указанные в примере трансформеры относятся к версии 1.15.