10 KiB
Minecraft Version Bump Checklist
gradle.properties minecraftVersion is the single source of truth for the target Minecraft
version. Most build outputs derive from it. This document lists every edit required to move Iris
to a new Minecraft version, in order.
Source of truth
gradle.properties:
minecraftVersion— target MC version (e.g.26.2). Drives the Bukkit pluginapi-version,BuildConstants.MINECRAFT_VERSION, thecom.mojang:minecraftcoordinate, all mod-metadata minecraft ranges, and every dist/jar artifact name.fabricLoaderVersion— Fabric Loader version.forgeVersion— Forge version (<mc>-<forge>).neoForgeVersion— NeoForge version.irisVersion— bump the trailing-<mc>suffix to match (e.g.4.0.0-26.2->4.0.0-27.0).
Ordered steps
-
Edit
gradle.properties: updateminecraftVersion,fabricLoaderVersion,forgeVersion,neoForgeVersion, and theirisVersionsuffix. -
Edit
gradle/libs.versions.toml:spigot— the Spigot/Paper API pin used to compile against (<mc>-R0.1-SNAPSHOT).fabricApi-*— the ten Fabric API module versions, if the new MC requires different Fabric API builds. Each module is versioned independently (<version>+<build-hash>). The ten arebase,registrySync,resourceLoader,lifecycleEvents,commandApi,eventsInteraction,networking,rendering,keyMapping,permission. Every one of them is bundled jar-in-jar and must be declared infabric.mod.jsonjars— see step 7.
-
Edit
core/src/main/java/art/arcane/iris/core/nms/datapack/DataVersion.java(manual, structural):- Append a new enum constant
V<major>_<minor>("<mc>", <packFormat>, <DataFixer>::new). packFormatcomes from https://minecraft.wiki/w/Pack_format.getLatest()returns the last enum constant, so append; do not reorder.- Add a matching
IDataFixerimplementation undercore/src/main/java/art/arcane/iris/core/nms/datapack/if the datapack format changed.
- Append a new enum constant
-
Register the new Bukkit NMS binding module:
settings.gradle— addinclude(':adapters:bukkit:nms:v<major>_<minor>_R<rev>').build.gradle— add the binding to thenmsBindingsmap:v<major>_<minor>_R<rev>: '<spigot-nms-build-version>'(e.g.'26.2.build.25-alpha').- Create the binding sources under
adapters/bukkit/nms/v<major>_<minor>_R<rev>/.
-
Update loader version-range metadata (manual floors/ranges only; the
minecraftranges are templated fromminecraftVersionand need no edit):adapters/fabric/src/main/resources/fabric.mod.json—minecraftis~${minecraftVersion}(auto). Update thefabricloaderfloor (currently>=0.19.3) if the loader minimum changes, and thejarslist if the bundled Fabric API modules change.adapters/forge/src/main/resources/META-INF/mods.toml—minecraftversionRange is[${minecraftVersion}](auto). UpdateloaderVersion(currently[65,)) and theforgedependency versionRange (also[65,)) for the new Forge line. Both are hand-maintained.adapters/neoforge/src/main/resources/META-INF/neoforge.mods.toml—minecraftversionRange is[${minecraftVersion}](auto).loaderVersion(currently[3,)) is the javafml specification version, not the NeoForge version, and rarely moves. TheneoforgedependencyversionRangeis hardcoded (currently[26.2,)) and is not templated fromminecraftVersion— hand-edit it on every bump or the mod will load on the wrong NeoForge line.
-
Re-verify the mapping-coupled files. Six files name Mojang-mapped classes, fields, and method descriptors directly. Nothing templates them, nothing fails fast at build time if a name moved, and a stale entry surfaces as a silent no-op or a load-time crash. Check every one against the new MC jar.
Access widener (Fabric) —
accessWidener v2 official, so the names are Mojang-mapped:-
adapters/fabric/src/main/resources/irisworldgen.accesswidenerMinecraftServer.levelsLjava/util/Map;MinecraftServer.executorLjava/util/concurrent/Executor;MinecraftServer.storageSourceLnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;PackRepository.sourcesLjava/util/Set;(accessible and mutable)
Verify: each field still exists with that exact descriptor. Loom fails the build on an unresolvable AW entry, so a rename shows up as an AW error — read it, do not delete the line.
Access transformers (Forge and NeoForge) — must stay in sync with each other and with the AW:
-
adapters/forge/src/main/resources/META-INF/accesstransformer.cfg -
adapters/neoforge/src/main/resources/META-INF/accesstransformer.cfg- both:
public net.minecraft.server.MinecraftServer levels/executor/storageSource
Verify: the three ATs match the first three AW entries. Note the ATs have no
PackRepositoryentry — Forge/NeoForge reach the pack sources through their own hooks, so do not add one without a reason. Wired viaminecraft { accessTransformer.from(...) }(Forge) andneoForge { accessTransformers.from(...) }(NeoForge). - both:
Mixin configs — three JSONs, eight mixin classes, all targeting Mojang-mapped members:
-
adapters/fabric/src/main/resources/irisworldgen.mixins.json(packageart.arcane.iris.fabric.mixin,compatibilityLevelJAVA_25, Fabric only)BlockItemMixin->BlockItem.placeBlock,@At("RETURN")BlockMixin->Block.getDrops(...)with a full descriptor (BlockState, ServerLevel, BlockPos, BlockEntity, Entity, ItemInstance) — the highest-churn entry in the repo; the parameter list changes across MC versionsPackRepositoryMixin->PackRepository.<init>,@At("RETURN")
-
adapters/modded-common/src/main/resources/irisworldgen.entity.mixins.json(packageart.arcane.iris.modded.mixin,compatibilityLevelJAVA_21, all three loaders)EntityPersistenceMixin->Entity.shouldBeSavedLivingEntityLootMixin->LivingEntity.dropFromLootTable(ServerLevel, DamageSource, boolean)— full descriptorMobAwarenessMixin->Mob.serverAiStep, injecting at a field target (Lnet/minecraft/world/entity/Mob;noActionTime:I) — verify the field, not just the method
-
adapters/modded-common/src/main/resources/irisworldgen.client.mixins.json(packageart.arcane.iris.client.mixin, client-only)IrisWorldOpenFlowsMixin->WorldOpenFlows.confirmWorldCreationandWorldOpenFlows.openWorldCheckWorldStemCompatibilityIrisWorldTypeEntryMixin->WorldCreationUiState.WorldTypeEntry.describePreset, plus a@Shadowmember — shadows break silently if the field is renamed
The client mixin config lives in
modded-common/src/main/resourcesbut the classes live inadapters/client-common/src/main/java/art/arcane/iris/client/mixin/; the modded mixin classes live inadapters/modded-common/src/main/java/art/arcane/iris/modded/mixin/. All three adapters add both shared source dirs, so one edit hits every loader.Registration differs per loader and each place must list the same configs:
- Fabric —
fabric.mod.jsonmixins(all three; the client one gated on"environment": "client"). - NeoForge —
[[mixins]]blocks inneoforge.mods.toml(entity + client). - Forge — no toml entry. The jar manifest attribute
MixinConfigsinadapters/forge/build.gradleplus--mixin.configargs on therunClient/runServerconfigurations (entity + client). Adding a mixin config on Forge means editing the manifest attribute and the run args.
injectors.defaultRequireis1in all three configs, so a mixin that no longer applies fails the run instead of degrading quietly. Treat any "mixin apply failed" line as a bump blocker, and run bothrunClientandrunServerper loader — client-only mixins are not exercised by a server run.
-
-
Reconcile the Fabric jar-in-jar list.
adapters/fabric/build.gradleadds every Fabric API module to thejijconfiguration, which theshadowJarcopies intoMETA-INF/jarswith the version stripped from the filename. Thejijconfiguration istransitive = false, so the bundled set is exactly the declared set, andfabric.mod.jsonjarsmust list exactly those filenames. After changing the module list, confirm the jar agrees:unzip -l "dist/Iris v<version> [Fabric] <mc>+<loader>.jar" | grep META-INF/jarsAn entry in
jarswith no matching nested jar makes the loader refuse the mod; a nested jar missing fromjarsis dead weight the loader never mounts. -
Build and verify:
./gradlew :core:check./gradlew buildBukkit./gradlew buildFabric./gradlew buildForge./gradlew buildNeoforge
Derived automatically (do not hand-edit on a version bump)
- Bukkit plugin
api-version—adapters/bukkit/plugin/build.gradlereadsminecraftVersion. BuildConstants.MINECRAFT_VERSION— stamped by thegenerateTemplatestask incore/build.gradlefromminecraftVersion; consumed byTasks.supportedVersions.- Mod-metadata
minecraftversion ranges — templated fromminecraftVersionatprocessResources. - Dist/jar artifact names and the
com.mojang:minecraftcoordinate — composed fromminecraftVersionin the build scripts.
Notes
build.gradle, the adapterbuild.gradlefiles, andsettings.gradlecarry.getOrElse('26.2')defensive defaults for the version properties.gradle.propertiesalways overrides them, so a bump does not require touching those fallbacks; refresh them only if the checked-in default should track the current release.- The Java literal
"26.2"intentionally remains inDataVersion.java(structural enum constant),core/src/test/java/art/arcane/iris/core/nms/MinecraftVersionTest.java, andcore/src/test/java/art/arcane/iris/core/lifecycle/PaperLibBootstrapTest.java. The test files use MC version strings as parser fixtures, not as a version source; update them only when the version string formats they exercise change.