Target Matrix

Target Matrix

The matrix is what lets one source tree build and publish against many Minecraft versions. A target is a named coordinate (Minecraft version + Java level + platform dependency versions); adding one is a single edit to a properties file, never a change to build scripts or CI.

targets.properties

Each target is a prefix in gradle/targets.properties. The target= line at the top is the default target used when no -Ptarget= is passed:

target=mc12110mc12110.minecraft=1.21.10mc12110.java=21mc12110.yarn=1.21.10+build.3mc12110.loader=0.18.3mc12110.fabric_api=0.138.4+1.21.10mc12110.paper=1.21.11-R0.1-SNAPSHOTmc12110.neoforge=21.10.64mc12110.pb4_placeholder_api=2.8.1+1.21.10mc12110.miniplaceholders_api=3.1.0

Every module compiles against the target's java level (via options.release), while a single modern toolchain (JDK 25) compiles all targets. So you never provision a separate JDK per Minecraft version.

Per-target Fabric Java requirement

A module that ships a fabric.mod.json declares its Java requirement as the literal token "java": "@MC_JAVA@" rather than a hardcoded >=21. During the build the shared java-library plugin substitutes it with >=<target.java>, so a mod built for a 1.20.1 (Java 17) branch requires Java 17 and a 1.21.10 (Java 21) branch requires Java 21 — from one manifest, resolved per target. This prevents a lower-Java branch from being wrongly rejected by the Fabric loader. The token is a plain string, not a ${...} placeholder, because Loom expands ${version} and would fail on an unknown ${} key. All modules that carry a fabric.mod.json — including the common ones (commands, logger, config, lang, placeholders) — get the substitution.

Library vs runtime Minecraft

The published coordinate branch normally follows minecraft. When the version you publish against differs from the runtime one (for example a Paper build that targets Java 21 on 1.20.5+), set <target>.library_minecraft and consumers resolve against that branch:

mc12110.library_minecraft=1.21.10

The magicMatrix DSL

magicMatrix { } in settings.gradle.kts declares the module layout and how targets map to platforms. This is the single source of truth for the whole build:

kotlin
magicMatrix {    targetsFile = "gradle/targets.properties"    publishingFile = "gradle/publishing.properties"    defaultTarget = "mc12110"    // Your own platform-neutral module(s). Most consumers keep their own module    // names, so no name remapping is needed here.    commonProjects("common")    // Platform module groups. The third argument disables a platform on    // specific target prefixes (here NeoForge only on the 1.20.1 target).    platform("bukkit", listOf("bukkit"))    platform("fabric", listOf("fabric"))    platform("neoforge", listOf("neoforge"), listOf("mc1201"))    // Named build selections for CI and local work.    scenario("workspace", listOf("bukkit", "fabric", "neoforge"), "Everything")    scenario("fabric", listOf("fabric"), "Fabric only")}

moduleNamePrefix(...) / moduleName(project, artifact) remap a subproject name to a published artifact id (for example platform-bukkit -> magicutils-bukkit). MagicUtils itself uses them; most consumers keep their own module names and can skip both.

Key methods:

MethodPurpose
targetsFile / publishingFilePaths to the properties files.
defaultTargetTarget used when -Ptarget is absent.
moduleNamePrefix(...) / moduleName(project, artifact)Artifact id naming.
commonProjects(...)Platform-neutral modules (built once).
platform(name, projects [, disabledTargetPrefixes])A platform's module group, optionally disabled on some targets.
scenario(name, platforms [, description])A named subset of platforms.
smoke { } / modrinth { }Compatibility smoke and Modrinth release config (see the other pages).

Selecting A Target Or Scenario

At invocation time you pick a target and a scenario with Gradle properties:

bash
# Build everything for the default target./gradlew buildWorkspace# Build just the Fabric scenario on a specific target./gradlew buildFabric -Ptarget=mc262# Publish the common modules on one target to Maven Local./gradlew publishCommonMatrix -Ptarget=mc2611

Scenario aggregate tasks (build<Scenario>, check<Scenario>, publishToMavenLocal<Scenario>) are generated from your scenario(...) declarations.

Inspecting The Matrix

These tasks print what the matrix resolves to, and feed CI:

TaskOutput
magicutilsHelpHuman-readable summary of targets, scenarios, and usage.
listBuildMatrixThe resolved target, platforms, scenario, and included projects.
printBuildMatrixJSON array of every target (for a CI build fan-out).
printPublishMatrixJSON of every target with its publish tasks (publish fan-out).
printReleaseMatrixJSON rows of (platform × smoke entry) for a release fan-out.

Because the target list comes from targets.properties, adding a Minecraft version never touches a workflow file: CI reads the matrix from these tasks.