-
-
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 Sponge maven repository to our
buildscript
block to provide a source for MixinGradle. - 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.
MixinGradle snapshots are published to the SpongePowered Maven Repository. We will need to add the maven-public
repository to our buildscript dependencies so that gradle knows where to locate the plugin:
Open your build.gradle and locate the buildscript
block at the top of the file. Add the sponge repository below the Minecraft Forge repo as shown:
buildscript {
repositories {
// These repositories are only for Gradle plugins, put any other repositories in the repository block further below
maven { url = 'https://maven.minecraftforge.net' }
// Sponge maven repo for MixinGradle:
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
mavenCentral()
}
Immediately below the repositories
block inside the buildscript
block is the dependencies
block which specifies dependencies required by the build script itself (not the project). We will add the MixinGradle dependency to allow us to load the plugin:
buildscript {
repositories {
...
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
// MixinGradle:
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
}
}
Now that the dependency is registered, we can apply the plugin to our build. Immediately below the buildscript
block you will see that three plugins are already applied. We will add MixinGradle below the existing plugins:
apply plugin: 'net.minecraftforge.gradle'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
// MixinGradle:
apply plugin: 'org.spongepowered.mixin'
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.4
(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.4: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.4:processor'
clientAnnotationProcessor 'org.spongepowered:mixin:0.8.4:processor'
apiAnnotationProcessor 'org.spongepowered:mixin:0.8.4: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