User Tools

Site Tools


tutorial:mixin_examples

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
tutorial:mixin_examples [2020/09/14 05:07] – minor improvement siglongtutorial:mixin_examples [2024/01/12 23:26] arkosammy12
Line 1: Line 1:
 ====== Mixin Examples ====== ====== Mixin Examples ======
 This is a collection of frequently used mixins. This is a collection of frequently used mixins.
 +This page is intended as a cheat sheet.
 +See [[tutorial:mixin_introduction|Mixin Introduction]] if you haven't already.
 +
 +===== Mixing into a private inner class =====
 +Use the targets parameter and a ''$'' sign to get the inner class.
 +<code java>
 +@Mixin(targets = "net.minecraft.client.render.block.BlockModelRenderer$AmbientOcclusionCalculator")
 +public class AmbientOcclusionCalculatorMixin {
 +    // do your stuff here
 +}
 +</code>
 +
 +===== Access the this instance of the class your mixin is targeting =====
 +Note: Double casting ''this'' should be avoided when possible. If you intend to use a method or field from the target class, use ''@Shadow''. If the method or field is from a parent of the target class, have your mixin extend the direct parent of the target class.
 +
 +Mixin:
 +<code java>
 +@Mixin(TargetClass.class)
 +public class MyMixin extends EveryThingThatTargetClassExtends implements EverythingThatTargetClassImplements {
 +  @Inject(method = "foo()V", at = @At("HEAD"))
 +  private void injected(CallbackInfo ci) {
 +    TargetClass thisObject = (TargetClass)(Object)this;
 +  }
 +}
 +</code>
 +
 +===== Injecting into the head of a static block =====
 +Mixin:
 +<code java>
 +@Inject(method = "<clinit>", at = @At("HEAD"))
 +private void injected(CallbackInfo ci) {
 +    doSomething3();
 +}
 +</code>
 +
 +Result:
 +<code diff>
 +static {
 ++   injected(new CallbackInfo(“<clinit>”, false));
 +    doSomething1();
 +    doSomething2();
 +}
 +</code>
  
 ===== Injecting into the head of a method ===== ===== Injecting into the head of a method =====
Line 64: Line 107:
 </code> </code>
  
-===== Injecting into before method call =====+===== Injecting into the point before method call =====
 Mixin: Mixin:
 <code java> <code java>
Line 84: Line 127:
 </code> </code>
  
-===== Injecting into after method call =====+===== Injecting into the point after method call =====
 Mixin: Mixin:
 <code java> <code java>
Line 101: Line 144:
 +   injected(new CallbackInfo("foo", false)); +   injected(new CallbackInfo("foo", false));
     doSomething2();     doSomething2();
 +  }
 +</code>
 +
 +===== Injecting into the point with shift amount =====
 +Mixin:
 +<code java>
 +@Inject(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething()V", shift = At.Shift.BY, by = 2))
 +private void injected(CallbackInfo ci) {
 +  doSomething3();
 +}
 +</code>
 +
 +Result:
 +<code diff>
 +  public void foo() {
 +    doSomething1();
 +    Something something = new Something();
 +    something.doSomething();
 +    doSomething2();
 ++   injected(new CallbackInfo("foo", false));
   }   }
 </code> </code>
Line 111: Line 174:
   at = @At(   at = @At(
     value = "INVOKE",     value = "INVOKE",
-    target = "La/b/c/Something;doSomething()V"), +    target = "La/b/c/Something;doSomething()V" 
-    slice = @Slice( +  ), 
-      from = @At(value = "INVOKE", target = "La/b/c/Something;doSomething2()V"), +  slice = @Slice( 
-      to = @At(value = "INVOKE", target = "La/b/c/Something;doSomething3()V")))+    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) { private void injected(CallbackInfo ci) {
   doSomething5();   doSomething5();
Line 181: Line 247:
 </code> </code>
  
 +===== Capturing local values =====
 +==== Capture locals without MixinExtras ====
 +
 +Mixin:
 +<code java>
 +@Inject(method = "foo()V", at = @At(value = "TAIL"), locals = LocalCapture.CAPTURE_FAILHARD)
 +private void injected(CallbackInfo ci, TypeArg1 arg1) {
 +  //CAPTURE_FAILHARD: If the calculated locals are different from the expected values, throws an error.
 +  arg1.doSomething4();
 +}
 +</code>
 +
 +Result:
 +<code diff>
 +  public void foo() {
 +    TypeArg1 arg1 = getArg1();
 +    arg1.doSomething1();
 +    arg1.doSomething2();
 +    TypeArg2 arg2 = getArg2();
 +    arg2.doSomething3();
 ++   injected(new CallbackInfo("foo", false), arg1);
 +  }
 +</code>
 +
 +==== Capture locals with MixinExtras ====
 +:!: MixinExtras required Fabric Loader 0.15 or above, or you have to manually specify it in ''build.gradle''.
 +
 +:!: If there are multiple locals with that type, you have to specify ''ordinal'' or it will throw an error.
 +
 +:!: More information about MixinExtra's ''@Local'' annotation can be found in its [[https://github.com/LlamaLad7/MixinExtras/wiki/Local|Wiki]].
 +
 +Mixin:
 +<code java>
 +@Inject(method = "foo()V", at = @At(value = "TAIL"))
 +private void injected(CallbackInfo ci, @Local TypeArg2 arg2) {
 +  arg1.doSomething4();
 +}
 +</code>
 +
 +Result:
 +<code diff>
 +  public void foo() {
 +    TypeArg1 arg1 = getArg1();
 +    arg1.doSomething1();
 +    arg1.doSomething2();
 +    TypeArg2 arg2 = getArg2();
 +    arg2.doSomething3();
 ++   injected(new CallbackInfo("foo", false), arg2);
 +  }
 +</code>
 +
 +==== Capturing one of multiple locals of a type ====
 +Mixin:
 +<code java>
 +@Inject(method = "foo()V", at = @At(value = "TAIL"))
 +private void injected(CallbackInfo ci, @Local(ordinal = 2) TypeArg arg) {
 +  arg1.doSomething4();
 +}
 +</code>
 +
 +Result:
 +<code diff>
 +  public void foo() {
 +    TypeArg arg1 = getArg1();
 +    TypeArg arg2 = getArg2();
 +    TypeArg arg3 = getArg3();
 +    TypeArg arg4 = getArg4();
 +    doSomething();
 ++   injected(new CallbackInfo("foo", false), arg3);
 +  }
 +</code>
 +
 +===== Modifying locals =====
 +This requires MixinExtras.
 +
 +Mixin:
 +<code java>
 +  @Inject(method = "foo()V", at = @At(value = "INVOKE", target = "doSomething()V", shift = At.Shift.AFTER))
 +  private static void injected(CallbackInfo ci, @Local LocalRef<String> localRef) {
 +    localRef.set(localRef.get() + " - modified")
 +  }
 +</code>
 +
 +Result:
 +<code diff>
 +  public void foo() {
 +    String s = "example string";
 +    doSomething();
 ++   s = s + " - modified";
 +    doSomething2(s);
 +  }
 +</code>
 ===== Modifying a return value ===== ===== Modifying a return value =====
 Mixin: Mixin:
Line 296: Line 454:
 @ModifyArgs(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething(IDZ)V")) @ModifyArgs(method = "foo()V", at = @At(value = "INVOKE", target = "La/b/c/Something;doSomething(IDZ)V"))
 private void injected(Args args) { private void injected(Args args) {
-  args.set(0args.<Integer>get(0+ 3); +    int a0 = args.get(0); 
-  args.set(1, args.<Double>get(1* 2.0D); +    double a1 = args.get(1)
-  args.set(2, !args.<Boolean>get(2));+    boolean a2 = args.get(2); 
 +    args.set(0a0 + 3); 
 +    args.set(1, a1 * 2.0D); 
 +    args.set(2, !a2);
 } }
 </code> </code>
Line 353: Line 514:
 +   double d1 = injected(doSomething3() + 0.8D); +   double d1 = injected(doSomething3() + 0.8D);
     double d2 = doSomething4();     double d2 = doSomething4();
 +  }
 +</code>
 +
 +===== Modifying a constant =====
 +Mixin:
 +<code java>
 +@ModifyConstant(method = "foo()V", constant = @Constant(intValue = 4))
 +private int injected(int value) {
 +  return ++value;
 +}
 +</code>
 +
 +Result:
 +<code diff>
 +  public void foo() {
 +-   for (int i = 0; i < 4; i++) {
 ++   for (int i = 0; i < injected(4); i++) {
 +      doSomething(i);
 +    }
   }   }
 </code> </code>
tutorial/mixin_examples.txt · Last modified: 2024/01/13 15:02 by arkosammy12