The first parameter is method , it tells the mixin what method we're going to modify
Now for the @At statement:
value = "INVOKE"
This tells the mixin that we're looking for the invocation of the method.
target = "Lnet/example/Dummy;dummy()V")
This tells the mixin where the method we're modifying is located
Now, lets break down the syntax of "Lnet/example/Dummy;dummy()V"
The L represents a class name, so Lnet/example/Dummy; is the path to the class where the method dummy , is located.
The dummy represents the method name inside the Dummy class.
Inside the brackets, we see another class (Ljava/lang/String;), this is the path to the String class, as String is actually a class, just one in the standard library, which doesn't need to be imported, everything inside these brackets are the parameters for dummy
Just after the brackets there is a V, which simply means void specifying that the println function doesn't return any value
The table below shows the different characters with their different meanings.
FieldType term
Type
Interpretation
B
byte
signed byte
C
char
Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16
Lets dissect this; First, we start off with defining our method, in this case, it's target() then we define the @At statement, which houses our value and our target.
Oh, but what's that? It's the cancellable statement!
The cancellable statement, can only be used at TAIL or RETURN . It's job is to inject code into a target method, and if ci.cancel is called, it returns after the mixin is done executing.
So, if we were to apply our mixin to our target() function, we would have a result similar, if not exactly like this:
Congrats! Now you hold the power of injecting code to your heart's content!