4 | Creating your first mixin

Creating a mixin

Creating our Mixin class

So, Minecraft is divided into several folders as shown below:

a small portion of the many folders that Minecraft has

The class we want to modify is the Minecraft class, which is located inside the client folder Which means, we should make a client folder inside our mixins folder to house our mixin class

project
    -> src
        -> java
            -> GROUP_NAME
                -> mixins
                    -> client <-- Create this

Since we don't want to pollute Minecraft's namespace, we append the word Mixin to our mixin classes to avoid it clashing with Minecraft class names, which means, inside the client folder we just created, create a class by the name of MinecraftMixinor MixinMinecraft which will act as a mixin for the Minecraft class. An example is shown below:

Creating the mixin

We need to tell the Mixin library what class MixinMinecraft is going mixin to. (a class that will add in it's own code to another class).

This is trivial, as we can use a simple annotation to denote that this is a mixin for the Minecraft class

@Mixin(Minecraft.class)
public class MixinMinecraft {
    ...
}

Now that we have told Mixin that we are going to modify the Minecraft class's methods, we can actually modify a function, but before that, we need to understand the two main ways of doing it

You can use the @Overwrite annotation, this will completely overwrite the code in a function, which is a destructive change, but it can be done like so:

@Overwrite
private void functionNameToOverwrite(int p1, String p2) {
    ...
}

However, since this is a destructive change, you may want to instead inject your code, which allows you to add code at either the HEAD of the function, which is the top of the function, or at the RETURN of the function, which is just before the return statement (or the end of the function), this is a bit more complex, as the @Inject annotation needs quite a bit more information.

You need to supply

  1. The method name in a string

  2. Where you want to inject at

  3. The method parameters for the method to inject, and a CallbackInfo object with provides information about the function and allow you to handle certian things like cancel the function

@Inject(method = "functionNameToInject", at = @At("RETURN"))
private void functionNameToInject(int otherParameters, CallbackInfo ci) {
    ...
}

Now that you know the basics of mixins, we can now attempt to write our first mixin

  1. The class that we're injecting into, Minecraft.java has function startGame which is called when the game is started. This is the function we want to inject into.

  2. We'll be injecting into the HEAD of the function, as that will allow our code to be ran before Minecraft has been initialized. We could inject into the RETURN of the function, but in this case, we want our code to be ran before Minecraft's initialziation.

We can now use our @Inject annotation to inject at the head of startGame

Since we're just starting to learn the basics of mixins, we'll just make it so that it just outputs something to the console.

This can be done as shown:

@Inject(method = "startGame", at = @At("HEAD"))
private void init(CallbackInfo ci) {
    System.out.println("Hello, Mixins!");
}

You might be wondering why our function is named init when we're clearly injecting into startGame . This is because we've already specified that we're injecting at the startGame function using the @Inject annotation -- so Mixin doesn't really care what the function is named.

Mixin doesn't recognize our Injection

Remember the file that we created in 2 | Setting up the workspace, by the name of mixins.PROJECT_NAME.json?

Well, we need to modify that json file to tell Mixin that MixinMinecraft is a mixin that does infact, exist

So, open mixins.PROJECT_NAME.json

project
    -> src
        -> resources
            -> mixins.PROJECT_NAME.json

It should look somewhat similar to this:

{
  "required": true,
  "compatibilityLevel": "JAVA_8",
  "verbose": true,
  "package": "me.ddozzi.exampleclient.mixins",
  "refmap": "mixins.ExampleClient.refmap.json",
  "mixins": []
}

First get the relative path, from your mixins package to your class, so for us it should be client.MixinMinecraft, add that to the mixins array in the refmap file, like so:

{
  "required": true,
  "compatibilityLevel": "JAVA_8",
  "verbose": true,
  "package": "me.ddozzi.exampleclient.mixins",
  "refmap": "mixins.ExampleClient.refmap.json",
  "mixins": [
      "client.MixinMinecraft"
  ]
}

Finishing off

Last updated

Was this helpful?