This is an old revision of the document!
Table of Contents
This is a draft! Feedback is appreciated, but keep in mind this is currently not intended to be read by Wiki users, it is not guaranteed that this page is fully accurate.
Creating an Override in a target class (DRAFT)
Introduction
When mixing into a class, you may want to modify an inherited method's behavior for your target's instances. You may then be tempted to create an override. For this tutorial, we'll use an example situation where we want to call a custom method every time a copper golem gets hurt. Specifically, we'll be using 1.21.10 with Yarn mappings.
The Problem
The class CopperGolemEntity does not have an override for LivingEntity#damage(ServerWorld, DamageSource, float), and we want to call ExampleMod#doSomething() every time a copper golem takes damage. If this were our own class, we would just create an override.
Direct Override: What not to do
We may be tempted to have our mixin class extend the super of CopperGolemEntity and override like so:
@Mixin(CopperGolemEntity.class) abstract class CopperGolemEntityMixin extends GolemEntity { // Dummy constructor from extending GolemEntity protected CopperGolemEntityMixin(EntityType<? extends GolemEntity> entityType, World wolrd) { super(entityType, world) } @Override public boolean damage(ServerWorld world, DamageSource source, float amount) { ExampleMod.doSomething(); return super.damage(world, source, amount); } }
However, this is inherently incompatible with other mods who may want to apply a similar modification, and therefore should be avoided. The rest of this page will walk you through two solutions which are more compatible and do not sacrifice functionality.
Compatible Solutions to the Problem
Injecting an instanceof check in the super
We can inject a check within the method we wish to functionally override, which will execute our custom operations if the this instance is of the intended subclass. In our case, we could create a Mixin like the following:
@Mixin(LivingEntity.class) abstract class LivingEntityMixin { @WrapMethod(method = "damage") private boolean doSomethingForCopperGolem(ServerWorld world, DamageSource source, float amount, Operation<Boolean> original) { if ((Object) this instanceof CopperGolemEntity) { ExampleMod.doSomething(); } return original.call(world, source, amount); } }
Remember of course that other injectors than @WrapMethod may be more fitting depending on your specific use-case. This Mixin only covers our specific situation.
Submixin Pattern
Alternatively, we may use what is known as a submixin pattern. This will require to create two Mixin classes in dedicated files in our project's mixin package. One will target the class containing the method we want to functionally override – we'll call it the “parent” Mixin or the “super” Mixin – and the other will target the class we want to functionally create an override into, which we'll call the “child” Mixin or “sub” Mixin.
For this tutorial, we will call the parent Mixin class LivingEntityMixin, and the child mixin class CopperGolemEntitySubMixin. These will be in separate files registered in our mixins.json config.
The Parent Mixin
The parent Mixin must create a “dummy” injector, with a protected handler method, which will apply no changes by itself:
@Mixin(LivingEntity.class) abstract class LivingEntityMixin { @WrapMethod(method = "damage") protected boolean overrideForCopperGolem(ServerWorld world, DamageSource source, float amount, Operation<Boolean> original) { return original.call(world, source, amount); } }
The Child Mixin
The child Mixin, or submixin, targets the class we want to override behavior for, and extends the parent Mixin:
@Mixin(CopperGolemEntity.class) abstract class CopperGolemEntitySubMixin extends LivingEntityMixin { }
We then override the dummy handler, and apply the actual changes in the override.
@Mixin(CopperGolemEntity.class) abstract class CopperGolemEntitySubMixin extends LivingEntityMixin { @Override protected boolean overrideForCopperGolem(ServerWorld world, DamageSource source, float amount, Operation<Boolean> original) { ExampleMod.doSomething(); return original.call(world, source, amount); } }