# 3 | Creating a tweaker

### What is a tweaker?

A tweaker allows arguments to be passed into it, and then allow you to inject your mixins into the Minecraft class loader

### Making the class <a href="#making-the-class" id="making-the-class"></a>

So first, go to the mixins folder in your project heirachy

```
project
    -> src
        -> java
            -> group_name
                -> project_name
                    -> mixins <-- Go here
```

In the previous tutorial, in the `build.gradle` file, we set the tweakclass variable to something like so

```java
tweakClass = "me.ddozzi.exampleclient.mixins.ExampleClientTweaker"
```

Take the last part of that (the tweaker class name), and in the mixins folder create a class by that name. An image is shown below.

![A tweaker class inside the path specified in the build.gradle](https://4250098061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MiA6dBhw40h7Hy8268O%2F-MiDA_WL3fIWVD1oZXKw%2F-MiIYHjJvdiboXu_4iFZ%2FScreen%20Shot%202021-08-29%20at%204.15.03%20PM.png?alt=media\&token=a7f571f5-6443-4f6e-be16-0976176b7ec3)

### Writing the tweaker

First, you need to implement the `ITweaker` interface, just add `implements ITweaker` to your class definition

```java
public class ExampleClientTweaker implements ITweaker {
}
```

Next, you should add the launch arguments array, this will store any launch arguments needed for later

```java
/**
    * This stores the Minecraft launch arguments  
    */
private List<String> launchArgs = new ArrayList<>();
```

Now we need to handle the launch arguments, or options, so you can simply just override `acceptOptions`

```java
/**
/**
    * This handles the launch arguments passed towards minecraft
    * @param args The launch arguments
    * @param gameDir The game directory (ie: .minecraft)
    * @param assetsDir The assets directory
    * @param profile The game profile
    */
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
    ...
}
```

Add the args to our `launchArgs` array, so we can use them later

```java
// Add the launch arguments to our launchArgs array
this.launchArgs.addAll(args);
```

We're going to only deal with 3 options, so we can easily define them as a set of constants

```java
// Constants
final String VERSION = "--version";
final String ASSET_DIR = "--assetDir";
final String GAME_DIR = "--gameDir";
```

Now we need to

1. Check if the launch args contains each constant, if not add it
2. Check if the profile isn't `null` (profile contains metadata about the game, for example, the version)

We can do this by checking with a few `if` statements like so

```java
// Check if version is passed as a launch argument, if not add it
if (!args.contains(VERSION) && profile != null) {
    launchArgs.add(VERSION);
    launchArgs.add(profile);
}

// Check if assetDir is passed as a launch argument, if not add it
if (!args.contains(ASSET_DIR) && profile != null) {
    launchArgs.add(ASSET_DIR);
    launchArgs.add(profile);
}

// Check if gameDir is passed as a launch argument, if not add it
if (!args.contains(GAME_DIR) && profile != null) {
    launchArgs.add(GAME_DIR);
    launchArgs.add(profile);
}
```

You also need to define a function for injection into the class loader

```java
/**
    * Inject into the MC class loader
    * @param classLoader The class loader
    */
@Override
public final void injectIntoClassLoader(LaunchClassLoader classLoader) {
    ...
}
```

For the injection function, you must first initialize `MixinBootsrap`, which is trivially done

```java
MixinBootstrap.init();
```

Next, we need to register out mixin configuration file and retrieve the default mixin environment

Just like in the `build.gradle` file, substitute `PROJECT_NAME` with your project's name

```java
// Retrieve the default mixin environment and register the config file
MixinEnvironment environment = MixinEnvironment.getDefaultEnvironment();

environment.addConfiguration("mixins.PROJECT_NAME.json");
```

Now we just need to check if there is no current obfuscation set, then set the obfuscation context to the `notch` obfuscation

```java
// Check if the obfuscation context is null
if (environment.getObfuscationContext() == null) {
    environment.setObfuscationContext("notch");
}
```

Now we need to inform Minecraft that this modification is running on the client side

```java
// This is a client side, client :)
environment.setSide(MixinEnvironment.Side.CLIENT);
```

Lastly, we just add the boiler plate which allows Minecraft to retrieve the launch arguments and the launch target

```java
@Override
public String getLaunchTarget() {
    return MixinBootstrap.getPlatform().getLaunchTarget();
}

@Override
public String[] getLaunchArguments() {
    return launchArgs.toArray(new String[0]);
}
```

{% hint style="info" %}
Having trouble? Check out the full [tweaker souce code here](https://gist.github.com/ddozzi/2292f9c25349e6b1f30b9808dd54193e).
{% endhint %}

{% hint style="success" %}
You should now be able to run the client!&#x20;
{% endhint %}

![Nice! We've launched Mixin Minecraft!](https://4250098061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MiA6dBhw40h7Hy8268O%2F-MiIl4jWleJYEg4zE2Qq%2F-MiIvJzXe6XPla4wC1E6%2FScreen%20Shot%202021-08-29%20at%206.00.03%20PM.png?alt=media\&token=d12cef8b-e8de-4153-ac9f-2927823cc08f)
