====== Примеры использования Миксинов ======
Это коллекция часто используемых миксинов.
Эта страница предназначена в качестве шпаргалки.
Прочитайте [[ru:tutorial:mixin_introduction|Введение в миксины]] если вы еще этого не сделали.
===== Смешивание с частным внутренним классом =====
Используйте параметр targets и знак ''$'', чтобы получить внутренний класс.
@Mixin(targets = "net.minecraft.client.render.block.BlockModelRenderer$AmbientOcclusionCalculator")
public class Calculator {
// ваш код здесь
}
===== Получите доступ к `этому` экземпляру класса, на который нацелен ваш миксин =====
Миксин:
@Mixin(ClassMyMixinIsTargeting.class)
public class MyMixin {
@Inject(method = "foo()V", at = @At("HEAD"))
private void injected(CallbackInfo ci) {
((ClassMyMixinIsTargeting)(Object)this).functionOfTheTargetClass();
}
}
===== Внедрение сверху метода =====
Миксин:
@Inject(method = "foo()V", at = @At("HEAD"))
private void injected(CallbackInfo ci) {
doSomething4();
}
Результат:
public void foo() {
+ injected(new CallbackInfo("foo", false));
doSomething1();
doSomething2();
doSomething3();
}
===== Внедрение перед заключительным оператором возврата =====
Миксин:
@Inject(method = "foo()V", at = @At("TAIL"))
private void injected(CallbackInfo ci) {
doSomething4();
}
Результат:
public void foo() {
doSomething1();
if (doSomething2()) {
return;
}
doSomething3();
+ injected(new CallbackInfo("foo", false));
}
===== Внедрение в перед каждым оператором return метода =====
Миксин:
@Inject(method = "foo()V", at = @At("RETURN"))
private void injected(CallbackInfo ci) {
doSomething4();
}
Результат:
public void foo() {
doSomething1();
if (doSomething2()) {
+ injected(new CallbackInfo("foo", false));
return;
}
doSomething3();
+ injected(new CallbackInfo("foo", false));
}
===== Внедрение перед вызовом метода =====
Миксин:
@Inject(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething()V"))
private void injected(CallbackInfo ci) {
doSomething3();
}
Результат:
public void foo() {
doSomething1();
Something something = new Something();
+ injected(new CallbackInfo("foo", false));
something.doSomething();
doSomething2();
}
===== Внедрение после вызова метода =====
Миксин:
@Inject(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething()V", shift = At.Shift.AFTER))
private void injected(CallbackInfo ci) {
doSomething3();
}
Результат:
public void foo() {
doSomething1();
Something something = new Something();
something.doSomething();
+ injected(new CallbackInfo("foo", false));
doSomething2();
}
===== Внедрение в определённом диапазоне =====
Миксин:
@Inject(
method = "foo()V",
at = @At(
value = "INVOKE",
target = "La/b/c/Something;doSomething()V"
),
slice = @Slice(
from = @At(value = "INVOKE", target = "La/b/c/Something;doSomething2()V"),
to = @At(value = "INVOKE", target = "La/b/c/Something;doSomething3()V")
)
)
private void injected(CallbackInfo ci) {
doSomething5();
}
Результат:
public class Something {
public void foo() {
this.doSomething1();
+ // Он не будет вводиться сюда, потому что это находится за пределами диапазона
this.doSomething();
this.doSomething2();
+ injected(new CallbackInfo("foo", false));
this.doSomething();
this.doSomething3();
+ // Он не будет вводиться сюда, потому что это находится за пределами диапазона
this.doSomething();
this.doSomething4();
}
}
===== Внедрение и отмена =====
Миксин:
@Inject(method = "foo()V", at = @At("HEAD"), cancellable = true)
private void injected(CallbackInfo ci) {
ci.cancel();
}
Результат:
public void foo() {
+ CallbackInfo ci = new CallbackInfo("foo", true);
+ injected(ci);
+ if (ci.isCancelled()) return;
doSomething1();
doSomething2();
doSomething3();
}
===== Внедрение и отмена с возвращаемым значением =====
Миксин:
@Inject(method = "foo()I;", at = @At("HEAD"), cancellable = true)
private void injected(CallbackInfoReturnable cir) {
cir.setReturnValue(3);
}
Результат:
public int foo() {
+ CallbackInfoReturnable cir = new CallbackInfoReturnable("foo", true);
+ injected(cir);
+ if (cir.isCancelled()) return cir.getReturnValue();
doSomething1();
doSomething2();
doSomething3();
return 10;
}
===== Изменение возвращаемого значения =====
Миксин:
@Inject(method = "foo()I;", at = @At("RETURN"), cancellable = true)
private void injected(CallbackInfoReturnable cir) {
cir.setReturnValue(cir.getReturnValue() * 3);
}
Результат:
public int foo() {
doSomething1();
doSomething2();
- return doSomething3() + 7;
+ int i = doSomething3() + 7;
+ CallbackInfoReturnable cir = new CallbackInfoReturnable("foo", true, i);
+ injected(cir);
+ if (cir.isCancelled()) return cir.getReturnValue();
+ return i;
}
===== Перенаправление вызова метода =====
Миксин:
@Redirect(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething(I)I"))
private int injected(Something something, int x) {
return x + 3;
}
Результат:
public void foo() {
doSomething1();
Something something = new Something();
- int i = something.doSomething(10);
+ int i = injected(something, 10);
doSomething2();
}
===== Перенаправление полученного поля =====
Миксин:
@Redirect(method = "foo()V", at = @At(value = "FIELD", target = "La/b/c/Something;aaa:I", opcode = Opcodes.GETFIELD))
private int injected(Something something) {
return 12345;
}
Результат:
public class Something {
public int aaa;
public void foo() {
doSomething1();
- if (this.aaa > doSomething2()) {
+ if (injected(this) > doSomething2()) {
doSomething3();
}
doSomething4();
}
}
===== Перенаправление поля ввода =====
Миксин:
@Redirect(method = "foo()V", at = @At(value = "FIELD", target = "La/b/c/Something;aaa:I", opcode = Opcodes.PUTFIELD))
private void injected(Something something, int x) {
something.aaa = x + doSomething5();
}
Результат:
public class Something {
public int aaa;
public void foo() {
doSomething1();
- this.aaa = doSomething2() + doSomething3();
+ inject(this, doSomething2() + doSomething3());
doSomething4();
}
}
===== Изменение аргумента =====
Миксин:
@ModifyArg(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething(ZIII)V"), index = 2)
private int injected(int x) {
return x * 3;
}
Результат:
public void foo() {
doSomething1();
Something something = new Something();
- something.doSomething(true, 1, 4, 5);
+ something.doSomething(true, 1, injected(4), 5);
doSomething2();
}
===== Изменение нескольких аргументов =====
Миксин:
@ModifyArgs(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething(IDZ)V"))
private void injected(Args args) {
int a0 = args.get(0);
double a1 = args.get(1);
boolean a2 = args.get(2);
args.set(0, a0 + 3);
args.set(1, a1 * 2.0D);
args.set(2, !a2);
}
Результат:
public void foo() {
doSomething1();
Something something = new Something();
- something.doSomething(3, 2.5D, true);
+ // Actually, synthetic subclass of Args is generated at runtime,
+ // but we omit the details to make it easier to understand the concept.
+ Args args = new Args(new Object[] { 3, 2.5D, true });
+ injected(args);
+ something.doSomething(args.get(0), args.get(1), args.get(2));
doSomething2();
}
===== Изменение параметра =====
Миксин:
@ModifyVariable(method = "foo(ZIII)V", at = @At("HEAD"), ordinal = 1)
private int injected(int y) {
return y * 3;
}
Результат:
public void foo(boolean b, int x, int y, int z) {
+ y = injected(y);
doSomething1();
doSomething2();
doSomething3();
}
===== Изменение локальной переменной при присваивании =====
Миксин:
@ModifyVariable(method = "foo()V", at = @At("STORE"), ordinal = 1)
private double injected(double x) {
return x * 1.5D;
}
Результат:
public void foo() {
int i0 = doSomething1();
double d0 = doSomething2();
- double d1 = doSomething3() + 0.8D;
+ double d1 = injected(doSomething3() + 0.8D);
double d2 = doSomething4();
}
===== Изменение константы =====
Миксин:
@ModifyConstant(method = "foo()V", constant = @Constant(intValue = 4))
private int injected(int value) {
return ++value;
}
Результат:
public void foo() {
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < injected(4); i++) {
doSomething(i);
}
}