BetterInject is not maintained anymore, I would recommend that you use MixinExtras, which has pretty much everything that BetterInject provides and much more.
BetterInject provides a new @Inject
annotation to use with Mixin.
The main "issue" that arises when using @Inject
from Mixin is how you write your handler methods. Take the following example:
@Inject(...)
private void handler(MatrixStack stack, int mouseX, int mouseY, float delta, CallbackInfo ci) {
MyMod.onRender(mouseX, mouseY);
}
In this example, we have a handler function that only uses 2 out of the 5 desired arguments. With BetterInject's @Inject
annotation, we only define what we need:
@Inject(...)
private void handler(
@Arg(ordinal = 0) int mouseX,
@Arg(ordinal = 1) int mouseY
) {
MyMod.onRender(mouseX, mouseY);
}
There are many more benefits to using BetterInject, which you will find as you go through this README.
@Inject
is a very commonly-used injector in Mixin. BetterInject aims to provide utilities to improve this injector. We do replace it with our own annotation, but that annotation is designed to work mostly as a drop-in-replacement to Mixin's @Inject
.
The main improvements that BetterInject provides over Mixin's Inject is:
- Having complete control over the arguments in your handler
- Easy to declare, and more expressive local capture
This is open to expansion though! If you have any suggestions, open an issue, or better yet, a pull request!
Note The only feature that will require some porting from Mixin's
@Inject
is if you use their local capture. To see how BetterInject improves local capture, go to the Local Capture section.
The intention of BetterInject is not to overthrow Mixin, or make our own Mixin library. We are simply making an already great library, even better.
You can get BetterInject from JitPack.
implementation("com.github.cbyrneee:BetterInject:0.1.3")
annotationProcessor("com.github.cbyrneee:BetterInject:0.1.3")
For how to initialize BetterInject, check the Initializing in Your Mod section.
For these examples, we will be @Inject
ing into a method with the following signature:
public void render(MatrixStack stack, int mouseX, int mouseY, float delta)
@Inject(method = "render", at = @At("HEAD"))
public void myMod$onRender() {
EventBus.getInstance().post(new MyRenderEvent());
}
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
public void myMod$onRender(CallbackInfo ci) {
boolean cancelled = EventBus.getInstance().postCancellable(new MyRenderEvent());
if (cancelled) {
ci.cancel();
}
}
-
All arguments
@Inject(method = "render", at = @At("HEAD"), cancellable = true) public void myMod$onRender(MatrixStack stack, int mouseX, int mouseY, float delta) { }
-
A single argument
@Arg
is required when you are not using all of the arguments provided by the target method. If you don't use@Arg
, strict mode will be enabled. BetterInject will throw an exception if your handler method's arguments dont match the target method's.@Inject(method = "render", at = @At("HEAD"), cancellable = true) public void myMod$onRender(@Arg float delta) { }
Note
@Arg
without specifying an ordinal (defaulting at-1
) assumes that there is only one parameter of that type on the target function. If there is more than one, an exception will be thrown at runtime. -
Multiple arguments
Use
@Arg(ordinal=)
to specify the ordinal of the argument that you are targeting.@Inject(method = "render", at = @At("HEAD"), cancellable = true) public void myMod$onRender( @Arg MatrixStack stack, // @Arg(ordinal = 0) int mouseX <- If you wanted mouseX @Arg(ordinal = 1) int mouseY ) { }
Warning This is where BetterInject is not compatible with Mixin's local capture. You must adapt your handler methods to the new format.
Local capture has improved with BetterInject.
You can now just apply @Local(ordinal=)
on to an argument in your @Inject
method's signature!
@Inject(method = "render", at = @At("RETURN"))
public void myMod$onRender(
@Local String localString // Default ordinal of -1 (a.k.a. there is only one String in the local variables of this target)
) {
System.out.println("Grabbed local: " + localString);
}
Note
@Local
without an ordinal (defaults at-1
) behaves just like@Arg
. If there is less than or more than 1 local variable with the same type as the one you are targetting, an exception will be thrown at runtime.
-
Fabric
package my.mod; import dev.cbyrne.betterinject.BetterInject; import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; public class PreLaunch implements PreLaunchEntrypoint { @Override public void onPreLaunch() { BetterInject.initialize(); } }
{ ... "entrypoints": { "preLaunch": [ "my.mod.PreLaunch" ] } }