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.