Mixins
this tutorial is incomplete, check out the following resources instead,
Mixins are a system for directly changing vanilla code. You can inject your own code into vanilla methods to change behaviour for which Forge does not yet have an event. At runtime, your mixins directly modify the bytecode of the classes you target before they are loaded. Although mixins are more versatile than events, they can be a bit tricky to get right and are generally worse for mod compatibility. You should almost always prefer using the Forge event when one exists.
build.gradleβ
There are a few changes that must be made to your build.gradle to let it know to load your mixins.
mixins.jsonβ
You will define which classes to load as mixins in a special json file. This file will go in your
Mixin Classβ
Create a new package called mixins
and create a class called
Mixin Methodβ
Note that dispite the fact that the target method has a return type, your mixin method returns void. The extra parameter (CallbackInfo
or CallbackInfoReturnable
) allows us to effect the return value of the target method.
Method Descriptorsβ
Use the Minecraft Development Intellij Plugin to generate.
Remappingβ
The method name in your descriptor is automatically remapped according to your project's mappings settings. This allows you to use the readable method names instead of the SRG names (ie. addMix
instead of func_193357_a
). This means there's an extra step if you are trying to mixin to a method that is not obfuscated and subsequently renamed by the mappings (anything outside of a vanilla class, for example something added by forge or another mod). You must set remap
to false in your inject annotation.
@Inject(method = "...", at = @At(...), remap = true)
private void injected(...) {
// whatever code
}
Injection Pointβ
HEAD RETURN
Return a Valueβ
If you want to change the return value of the target method (or just cancel the rest of the method call), you must set cancellable
to true in your mixin method annotation.
The last perameter of your mixin method will be of the type CallbackInfoReturnable<T>
with T
being the type returned by the target method. You can call setReturnValue(value);
to change the return value of the target method. Note that this does not immediately exit your method the way a return;
statement would.
@Inject(method = "...", at = @At(...), cancellable = true)
private void injected(CallbackInfoReturnable<Float> callback) {
callback.setReturnValue(3.14F);
}
Accessing The Objectβ
Shadowingβ
When you need to access methods or fields on the target class from your mixin code, you can use the @Shadow
annotation. Create a null field or an empty method that just throws an error. The @Shadow
annotation will redirect these references to the ones on your target class.
Using this
β
You may want to directly access the object you are mixing into. You may be frustraited to discover that when you use the this
keyword, it is an instance of your mixin class, not of the target class. You can get around this by casting to Object
and then to your target class. This often serves the same purpose as shadowing.
For example, in a method that targets the ItemEntity class, you could use the following code to get the actual object and then any public methods/fields will be available.
ItemEntity item = (ItemEntity) (Object) this;
Also note that the mixin class is not actually present at runtime. Its bytecode is just added to vanilla's. You should not have static fields on the mixin class that you try to reference from other places in your mod's code. However, the code in your mixin methods can access the rest of your mod's classes.
Other Documentationβ
The mixin system used by forge is called SpongeMixin and is developed by Mumfrey. It is also used by Fabric and Sponge so almost any documentation on mixins for those platforms will also apply to Forge.
If you want to read more about how to use mixins, check out the following: