-
-
Notifications
You must be signed in to change notification settings - Fork 194
Mixins on Minecraft Forge
Mixin now ships as a library with Minecraft Forge which means it is no longer necessary, as it was in legacy versions, to shade Mixin into your mod jar. In fact doing so will likely cause issues.
As explained in the Obfuscation and Mixins chapter, certain mixin features require special handling in order to cross the obfuscation boundary when you build your mod for production. This guide explains how to have your mixins function in the forge UserDev environment, and also how to configure your build so that obfuscation information is properly generated for your mixins.
This guide asssumes that you have already created a package to contain your mixins and a mixin config to declare the mixins and options.
We will make the following changes to the build.gradle
in order to configure the project to be run in development, and to manage obfuscation
- Add the MixinGradle plugin.
- Add the Mixin Annotation Processor dependency.
- Configure options for MixinGradle via the
mixin
closure.
For the purposes of this guide, I will assume that your mixin config is named
mixins.mymod.json
and the refmap is namedmixins.mymod.refmap.json
and that you are using only themain
SourceSet.
Open your build.gradle and locate the plugins
block at the top of the file. The plugins
block already contains the necessary plugins for the Forge MDK. We will add the MixinGradle plugin by adding the following line to end of the plugins
block, before the closing curly brace:
id 'org.spongepowered.mixin' version '0.7.+'
The plugins
block should now look like this:
plugins {
id 'eclipse'
id 'maven-publish'
id 'net.minecraftforge.gradle' version '5.1.+'
id 'org.spongepowered.mixin' version '0.7.+'
}
MixinGradle's job is to configure the Mixin Annotation Processor (AP), however the AP is not applied automatically, we need to add it as a dependency. The AP dependency should be the same version or newer as the version used in your project (if you're not sure what version of Mixin you're using, see the section at the end of this guide).
To add the Mixin AP dependency to your project locate the dependencies
block for the project. This is not the dependencies
block in the buildscript
block at the top of your gradle file, but the larger dependencies
block further down the file. For the purposes of this guide we will assume that the version is 0.8.5
(the current release version at the time of writing).
It should currently contain the minecraft
dependency and a bunch of comments, as well as any other dependencies you've added manually. The AP configuration for main
is called annotationProcessor
. Add the Mixin AP dependency to the dependencies
block:
dependencies {
// Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed
// that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.17.1-37.0.70'
// Apply Mixin AP
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
Notice that the AP dependency has the additional classifier
processor
. This is a special fat jar which contains the upstream dependencies required by the Mixin AP so that you don't have to specify them all by hand.
If you only have one SourceSet main
, you can skip this section.
Additional SourceSets will have corresponding gradle configurations which define their dependencies. If you have additional SourceSets which contain mixins then each will require its own Reference Map (more on that below) and each SourceSet configuration will require the Mixin AP dependency.
Let's assume you have additional SourceSets called client
and api
. The corresponding configuration names will be clientAnnotationProcessor
and apiAnnotationProcessor
, add the Mixin AP to each:
dependencies {
// Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed
// that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.17.1-37.0.70'
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
clientAnnotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
apiAnnotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
MixinGradle provides an extension called mixin
which allows us to configure the options for the plugin, MixinGradle will then apply these settings in the appropriate places. To configure the extension specify the extension name and a closure which will contain our settings. This can be placed anywhere in your build, but I recommend placing it after your sourceSets
or dependencies
blocks:
mixin {
// MixinGradle Settings
}
MixinGradle can configure the AP options, but we need to tell it the name of the refmap to generate for each compile task, this must correspond to the refmap name in the config JSON.
Note that configs in the same SourceSet should all specify the same refmap name, regardless of which mixins they contain. This is because refmaps are coupled to the compile task for the SourceSet and don't care about the organisation of mixins within your configs.
We can also specify the name of our mixin config, this will perform two tasks:
- The config will be injected into all of our run configurations
- The config name will be added to the manifest of all obfuscated jars (in the
MixinConfigs
key)
Let's add the refmap name for our main
SourceSet and our config name to the mixin
closure:
mixin {
// MixinGradle Settings
add sourceSets.main, 'mixins.mymod.refmap.json'
config 'mixins.mymod.json'
}
The mixin
closure can also be used to configure options such as Mixin System Properties (for dev runs) and options for the Mixin Annotation Processor. For example I recommend setting the mixin.debug.verbose
and mixin.debug.export
during development. We can set these properties in the mixin
closure for convenience:
mixin {
// MixinGradle Settings
add sourceSets.main, 'mixins.mymod.refmap.json'
config 'mixins.mymod.json'
debug.verbose = true
debug.export = true
}
Remember to regenerate runs using the
genEclipseRuns
,genIntellijRuns
orgenVSCodeRuns
task after changing any settings which affect run configurations!
If you only have one SourceSet main
, you can skip this section.
As well as gradle configurations, each SourceSet in your project gets a corresponding Java compile task which is named after the SourceSet. Since each SourceSet is compiled separately, the AP will run separately each time, hence why each SourceSet requires a separate Reference Map (refmap). Using the example above, let's add refmaps names and configs for our client
and api
SourceSets:
mixin {
add sourceSets.main, 'mixins.mymod.refmap.json'
add sourceSets.client, 'mixins.mymod.client.refmap.json'
add sourceSets.api, 'mixins.mymod.api.refmap.json'
config 'mixins.mymod.json'
config 'mixins.mymod.client.json'
config 'mixins.mymod.api.json'
}
MixinGradle configures the AP with all of the required options. However, the Mixin AP options can be manipulated via the mixin
closure. Some useful options are:
- boolean disableTargetValidator
- Disables the target validator (validates that the mixin targets are sane (eg. superclass exists within target hierarchy)
- boolean disableOverwriteChecker
- Disables the overwrite checker which ensures @Overwrite method javadoc contains @author and @reason tags
- String overwriteErrorLevel
- Sets the error level for the overwrite checker (defaults to warning, can be set to error)
- quiet
- Suppresses the banner message and informational output from the AP
- extraMappings
- Specifies the name of an additional (custom) TRSG mapping file to feed to the AP, this can be used for mapping entries not specified in the main mapping file
mixin {
// AP Settings
disableTargetValidator = true
overwriteErrorLevel = 'error'
quiet
extraMappings file("my_custom_srgs.tsrg")
}
Here is a complete example of what our mixin
closure may look like once we've configured everything:
mixin {
// Refmaps for each SourceSet
add sourceSets.main, 'mixins.mymod.refmap.json'
// Configs to add to runs and jars
config 'mixins.mymod.json'
// Specify options for dev run configs
debug.verbose = true
debug.export = true
dumpTargetOnFailure = true
// Options for the Annotation Processor
quiet
}
If you're not sure which version of Mixin is in use in your project you can find it in several ways:
-
In your IDE, check the list of project dependencies. In eclipse you can look in the
Project and External Dependencies
container for example. -
Use the
gradle dependencies
task to emit the dependency tree for your project to the console and filter it usingfind
(on windows) orgrep
on linux:gradlew --console=plain dependencies | find "mixin"
This should emit several lines into the console and it shouldn't be too hard to identify the mixin dependency version.
-
Run the game in your development environment and then search the
debug.log
for the mixin subsystem version