Highly Suspect Agency

How to at least *start* updating your mod to 1.21

what's 9 + 10

Getting the damn thing to compile again

You know how it is with Minecraft projects, if you sneeze the toolchain breaks, so here's a way to at least get the project into a known-working state.

In my shell I set up JDK8, JDK17, and JDK21 aliases pointing to the respective installation's JAVA_HOME. When something stupid happens, JAVA_HOME=$JDK17 ./gradlew ... is a good first fix.

If it's a project I really havent touched in a while, I like to do all this in the terminal before opening the IDE. IntelliJ users should remember to set the project JDK to something reasonable in the "Project Structure" dialog, remember to double-check that Settings -> "Build, Execution, Deployment" -> Build Tools -> Gradle has the JDK set to "project JDK", and remember that their terminal might have a different JAVA_HOME than their IDE.

After this you should be able to at least look around, ./gradlew clean, compile the project, etc.

Getting on Gradle 8

If you use subprojects for Fabric and Forge in the same tree, now's a good time to comment them out of your build.gradle. The newest versions of Minecraft ecosystem plugins require Gradle 8 and there's no combination of versions where ./gradlew version works and the Minecraft plugins work. If you don't use subprojects, rename build.gradle again.

After that, run ./gradlew wrapper --gradle-version 8.10.1, which is the current latest version of Gradle 8.

The standard Gradle 8 growing pain: if you used the gradle toolchains feature at all, don't forget to paste

plugins {
    id "org.gradle.toolchains.foojay-resolver-convention" version "0.8.0"
}

into your settings.gradle.

Updating Fabric Loom projects

The latest stable version of Fabric Loom, at the time of writing, is 1.7.4. Might soon be 1.8. Don't use a -SNAPSHOT and don't use a 1.7.+ version bound, it's not worth it.

I changed the Loom version, uncommented it from settings.gradle, and refreshed Gradle. This took a few minutes since Loom decided to redownload everything but the process was otherwise uneventful.

Updating minivan projects

(Tooting my own horn here: if you're one of the three people who use minivan to manage a loader-independent subproject, the latest version is 0.5. And it supports access transformers!)

Updating ForgeGradle projects

First update ForgeGradle to version 6.0.29, a version that supports Gradle 8. Again, don't use a -SNAPSHOT and don't use a 6.0.+ version bound.

If your project did not already use official mappings (unlikely if you're doing multiloader stuff), get on them now. NeoForge has basically removed mappings.

To NeoForge

Get on NeoGradle. Their Maven is a bit of a maze (NeoGradle was renamed several times); the correct group is net.neoforged.gradle and artifact is userdev.

First, change the plugin. Remove MixinGradle if you used it; it's not compatible with NeoForge and is not needed.

buildscript {
    repositories {
        mavenCentral()
        maven { url = "https://maven.neoforged.net/releases" } //change
    
    //this maven is still needed for "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:1.1.6"?
    //what da hell
        maven { url = "https://repo.spongepowered.org/repository/maven-public/" }
    }
    dependencies {
        classpath "net.neoforged.gradle:userdev:7.0.163" //change
    }
}
apply plugin: "java"
apply plugin: "net.neoforged.gradle.userdev" //change

Under NeoGradle, Minecraft lives in the implementation source set, no custom minecraft set needed:

//old
minecraft "net.minecraftforge:forge:${forge_version}"

//new
implementation "net.neoforged:forge:${neoforge_version}"

(Since this is till a 1.20.1 mod, we're in the NeoForge compatibility period. They shipped under the net.neoforged:forge group/artifact during this period. Versions range from 1.20.1-47.1.5 to 1.20.1-47.1.106.)

Remove the minecraft { } block entirely, including the mappings channel: line, since NeoForge removed mappings.

Hoist runs to the top level. Run configs are very different:

I removed my entire runs block and replaced it with this:

runs.configureEach {
    workingDirectory file("./run")
    modSource project.sourceSets.main
}

Don't add your :xplat project to modSource. NeoForge will try to load the build directory of your xplat project as a mod and will fail spectacularly.

Mixins

MixinGradle is not needed and is not supported. You can remove it.

During the 1.20.1 transitional period, the [[mixins]] block in mods.toml is not yet supported by NeoForge. This is fine since we're just using 1.20 NeoForge as a stepping stone, but if you really want to work with Mixin on Neoforge 1.20.1, you'd have to mention your mixin config file in MANIFEST.MF the way MixinGradle did:

MixinConfigs: mymod.mixins.json

and probably do something about refmaps.

During 1.21, rename mods.toml to neoforge.mods.toml, and add this to the bottom:

[[mixins]]
config = "my_mod.mixins.json"

Another knock-on effect of NeoForge standardizing mappings: they've removed the need for refmaps. If you build your mod and don't find a refmap in the jar, that's normal and it will work in production.

Multiloader shit

NeoGradle is pissy about the multiloader-template style fatjars.

Too fucking bad! I'm doing it anyway.

Breather

What has been accomplished so far:

All of this stuff is 1.21 ready and Java 21 ready. It's time.

Java 21

Record patterns/pattern-matching-for-switch, those funny sequenced collections interfaces, green threads (which are not too relevant in a game context), and Generational ZGC (proving that Minecraft truly is for Gen Z).

In IntelliJ, set the project JDK to 21, and since you did remember to set Settings -> "Build, Execution, Deployment" -> Build Tools -> Gradle (right), this will cause Gradle to be invoked with Java 21.

Fabric

Head to fabricmc.net/develop to check the latest fabric-loader and fabric-api versions, as usual.

For Rebind Narrator everything worked fine on 1.21 out of the box, although it does only use two fabric-api modules.

NeoForge

Head to the NeoForged homepage to check the latest version of NeoForge. Currently the latest version is broken on NeoGradle but 21.1.47 seems to work.

This is past the compatibility period, so you'll have to do porting work. This means changing the package of all forge classes, taking the IEventBus through your mod's constructor rather than new IFMLJavaModLoadingEventBusGetterFactory().createFMLJavaModLoadingEventBusGetter().get().getEventBus().getBus().pleaseGiveMeTheBus() or whatever it was, etc etc.

Non-satisfying ending to this post. I was planning on writing a small "things I noticed when porting to 1.21" guide, but getting to this point has already taken several more hours than I thought it would, so I only had time to port an extremely small mod.