Table of Contents
Инжекторы Миксинов
Вступление
Инжекторы позволяют размещать пользовательский код в указанной позиции внутри существующего метода. Для рабочего примера просмотрите категорию внизу этой страницы. Стандартная форма внедрения выглядит так, как показано в коде:
@Inject(method = "", at = @At("INJECTION POINT REFERENCE")) private void injectMethod(METHOD ARGS, CallbackInfo info) { }
Контрольная-Точка-Внедрения определяет, где код внутри тела метода вводится внутри целевого метода. В следующей таблице описаны некоторые из вариантов:
Имя | Описание |
---|---|
HEAD | Верхняя часть метода |
RETURN | Перед каждым оператором return |
INVOKE | При вызове метода |
TAIL | Перед заключительным оператором возврата |
В случае точек внедрения, которые ссылаются на операторы или элементы, целевое значение может быть установлено внутри @At. Целевое значение задается с помощью дескрипторов байт-кода JVM.
Oracle определяет следующее поля дескрипторов:
Дескриптор | Тип | Описание |
---|---|---|
B | byte | Записанный байт |
C | char | Кодовая точка символа Юникода в базовой многоязычной плоскости, закодированная с помощью UTF-16 |
D | double | Значение с плавающей точкой двойной точности |
F | float | Значение с плавающей точкой одинарной точности |
I | int | Целое число |
J | long | Длинное целое число |
LClassName; | reference | экземпляр ClassName |
S | short | Краткая запись |
Z | boolean | true (правда) или false (ложь) |
[ | reference | Одно измерение массива |
Дескриптор метода состоит из имени метода, за которым следует набор круглых скобок, содержащих типы ввода, за которыми следует тип вывода. Метод, определенный в Java как Object m(int i, double[] d, Thread t)
будет иметь дескриптор метода m(I[DLjava/lang/Thread;)Ljava/lang/Object;
.
Типы дженериков не учитываются, так как дженерики не существуют во время выполнения. Значит Pair<Integer, ? extends Task<? super VillagerEntity>>
станет Lcom/mojang/datafixers/util/Pair
.
@Inject методы всегда имеют возвращаемый тип void. Имя метода не имеет значения; лучше всего использовать что-то, описывающее, что делает внедрение. Аргументы целевого метода помещаются первыми в заголовок метода, за которым следует объект “CallbackInfo”. Если целевой метод имеет возвращаемый тип (T), вместо “CallbackInfoReturnable<T>” используется “Callbackinfo”.
Возврат и отмена при внедрении
Чтобы отменить или вернуться раньше внутри метода, используйте CallbackInfo#cancel
или CallbackInfoReturnable<T>#setReturnValue(T)
. Обратите внимание, что “cancel” не обязательно вызывается после “setReturnValue”. В обоих случаях для параметра “cancellable” в аннотации внедрения должно быть установлено значение true:
@Inject(method = "...", at = @At("..."), cancellable = true)
Внедрение в конструкторы
Чтобы внедрить в конструктор, используйте <init>()V
в качестве целевого метода, ()
содержит дескрипторы аргументов конструктора. При вводе в конструкторы “@At” должно быть установлено либо на “TAIL”, либо на “RETURN”. Никакие другие формы внедрения официально не поддерживаются. Обратите внимание, что некоторые классы имеют методы с именем “init”, которые отличаются от “<init>”. Не путайте!
Чтобы внедрить в статический конструктор, используйте “<clinit>” в качестве имени метода.
Пример
В следующем примере вводится оператор печати в верхней части “TitleScreen#init” (примечание: метод “init” является обычным методом, а не конструктором).
@Mixin(TitleScreen.class) public class ExampleMixin { @Inject(at = @At("HEAD"), method = "init()V") private void init(CallbackInfo info) { System.out.println("Эта строка написана модом через миксин!"); } }
Для получения дополнительной информации об этом конкретном примере ознакомьтесь с его использованием в репозитории Fabric Example Mod.