From eebfe8fa4db294480060f44daea4db28c62fa817 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 27 Sep 2026 04:51:28 +0200 Subject: [PATCH] Switch the root build scripts to Kotlin and limit parallel remaps - settings.gradle, stonecutter.gradle and the root build.gradle become .kts. Loom's version for the Stonecutter versions moves to the root gradle.properties (loom_version), read by pluginManagement, since the Kotlin plugins block can't read properties. The old mc- projects keep their Groovy scripts until they're folded in. - buildAll ran all eight remapJar tasks at once. Each loads a Minecraft classpath and remaps a ~50 MB jar, which doesn't fit in the 3 GB daemon heap: a cold build stalled in garbage collection for 40+ minutes, and earlier runs failed. A shared build service now lets two remaps run together; a cold buildAll takes about 2 minutes. - port.sh and VERSION_GUIDE follow the .kts file names. The 1.21.11 jar is the same as with the Groovy scripts. Co-Authored-By: Claude Opus 5.5 --- VERSION_GUIDE.md | 8 +-- build.gradle | 101 ----------------------------- build.gradle.kts | 81 +++++++++++++++++++++++ gradle.properties | 3 + scripts/port.sh | 10 +-- settings.gradle | 40 ------------ settings.gradle.kts | 43 ++++++++++++ stonecutter.gradle | 73 --------------------- stonecutter.gradle.kts | 71 ++++++++++++++++++++ versions/1.21.11/gradle.properties | 1 - 10 files changed, 207 insertions(+), 224 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts delete mode 100644 stonecutter.gradle create mode 100644 stonecutter.gradle.kts diff --git a/VERSION_GUIDE.md b/VERSION_GUIDE.md index e851152..444dd1f 100644 --- a/VERSION_GUIDE.md +++ b/VERSION_GUIDE.md @@ -10,11 +10,11 @@ Saturn is moving from one full copy of the version-specific code per Minecraft v - `src/`: the version-specific code (providers, refs, mixins and the three mixin configs) for the versions built by Stonecutter, currently **1.21.11**. It's one copy: where Minecraft's API differs between them, the code goes behind version comments (see below). Each of these versions is the Gradle project `:`, and `versions//` holds only its `gradle.properties` (Minecraft, Yarn, Fabric Loader and Fabric API versions), `build/` and `run/`. - `versions//src/`: the versions not moved yet (1.21.4 to 1.21.10), each a full copy, as the Gradle project `:mc-` with its own `build.gradle`. -`settings.gradle` lists the Stonecutter versions in `stonecutterVersions` and includes every other folder under `versions/` as `:mc-`. The root `build.gradle` builds each Stonecutter version, and `stonecutter.gradle` configures the root project (shared repositories, the `common` wiring and `buildAll`). +`settings.gradle.kts` lists the Stonecutter versions in `stonecutterVersions` and includes every other folder under `versions/` as `:mc-`. The root `build.gradle.kts` builds each Stonecutter version, and `stonecutter.gradle.kts` configures the root project (shared repositories, the `common` wiring and `buildAll`). Loom's version for the Stonecutter versions is `loom_version` in the root `gradle.properties`. ## Version-specific code with Stonecutter -The code in `src/` is always plain Java for the **active** version (1.21.11, set in `stonecutter.gradle`). Code for other versions sits in comments that Stonecutter swaps before building each version: +The code in `src/` is always plain Java for the **active** version (1.21.11, set in `stonecutter.gradle.kts`). Code for other versions sits in comments that Stonecutter swaps before building each version: ```java //? if >=1.21.9 { @@ -58,7 +58,7 @@ The **Check** workflow runs the same compile on every pull request, so a version Add new versions to Stonecutter rather than copying a folder: -1. Create `versions//gradle.properties` with `minecraft_version`, `yarn_mappings`, `loader_version` and `fabric_api_version` (copy 1.21.11's and change the values; they're listed at ). -2. Add `` to `stonecutterVersions` in `settings.gradle`. +1. Create `versions//gradle.properties` with `minecraft_version`, `yarn_mappings`, `loader_version` and `fabric_api_version` (copy 1.21.11's and change the values; they're listed at ). Loom's version is shared, in the root `gradle.properties`. +2. Add `` to `stonecutterVersions` in `settings.gradle.kts`. 3. Build it with `./gradlew ::compileJava` and put what Minecraft changed behind version comments. Check the mixin configs in `src/main/resources/*.mixins.json` as well: a mixin whose target changed fails at startup, not at compile time, so launch it with `./gradlew ::runClient`. 4. The release workflow builds everything through `buildAll`, and "Publish to Modrinth" takes the game version from each jar's name, so neither needs changing. diff --git a/build.gradle b/build.gradle deleted file mode 100644 index b40015c..0000000 --- a/build.gradle +++ /dev/null @@ -1,101 +0,0 @@ -plugins { - id 'net.fabricmc.fabric-loom-remap' version "${loom_version}" - id 'maven-publish' -} - -version = "${project.mod_version}+${project.minecraft_version}" -group = project.maven_group - -base { - archivesName = project.archives_base_name -} - -repositories { - maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' } -} - -dependencies { - // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" - - // Saturn's emote library (limb bending, Emotecraft emotes) - include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}") - - implementation project(":common") - - include implementation("dev.selimaj:session-java:0.2.0") - include implementation("de.javagl:obj:0.4.0") - include implementation("com.formdev:svgSalamander:1.1.4") - include implementation("com.fasterxml.jackson.core:jackson-databind:2.17.0") - include implementation("com.fasterxml.jackson.core:jackson-annotations:2.17.0") - include implementation("com.fasterxml.jackson.core:jackson-core:2.17.0") -} - -/* - * ================================================================ - * Resource Processing - * ================================================================ - * Injects version values into fabric.mod.json. - */ -processResources { - inputs.property "version", project.version - inputs.property "minecraft_version", project.minecraft_version - inputs.property "loader_version", project.loader_version - filteringCharset "UTF-8" - - filesMatching("fabric.mod.json") { - expand( - "version": project.version, - "minecraft_version": project.minecraft_version, - "loader_version": project.loader_version - ) - } -} - -tasks.withType(JavaCompile).configureEach { - it.options.release = 21 -} - -java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. - withSourcesJar() - - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 -} - -jar { - inputs.property "archivesName", project.base.archivesName - - from("LICENSE") { - rename { "${it}_${inputs.properties.archivesName}"} - } - - from project(":common").sourceSets.main.output - duplicatesStrategy = DuplicatesStrategy.EXCLUDE -} - -// configure the maven publication -publishing { - publications { - create("mavenJava", MavenPublication) { - artifactId = project.archives_base_name - from components.java - } - } - - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. - } -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..5faa9c2 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,81 @@ +// Builds one Minecraft version from the shared src/. Stonecutter runs this for each version in +// stonecutterVersions (settings.gradle.kts), with that version's versions//gradle.properties. +plugins { + id("net.fabricmc.fabric-loom-remap") + `maven-publish` +} + +val minecraftVersion = property("minecraft_version") as String +val loaderVersion = property("loader_version") as String + +version = "${property("mod_version")}+$minecraftVersion" +group = property("maven_group") as String + +base { + archivesName = property("archives_base_name") as String +} + +dependencies { + minecraft("com.mojang:minecraft:$minecraftVersion") + mappings("net.fabricmc:yarn:${property("yarn_mappings")}:v2") + modImplementation("net.fabricmc:fabric-loader:$loaderVersion") + modImplementation("net.fabricmc.fabric-api:fabric-api:${property("fabric_api_version")}") + + // Saturn's emote library (limb bending, Emotecraft emotes) + include(modImplementation("org.saturnclient:emotes-fabric:${property("emotes_version")}+$minecraftVersion")!!) + + implementation(project(":common")) + + for (library in listOf( + "dev.selimaj:session-java:0.2.0", + "de.javagl:obj:0.4.0", + "com.formdev:svgSalamander:1.1.4", + "com.fasterxml.jackson.core:jackson-databind:2.17.0", + "com.fasterxml.jackson.core:jackson-annotations:2.17.0", + "com.fasterxml.jackson.core:jackson-core:2.17.0", + )) { + include(implementation(library)!!) + } +} + +// Injects the version values into fabric.mod.json. +tasks.processResources { + val values = mapOf( + "version" to project.version.toString(), + "minecraft_version" to minecraftVersion, + "loader_version" to loaderVersion, + ) + inputs.properties(values) + filteringCharset = "UTF-8" + filesMatching("fabric.mod.json") { expand(values) } +} + +tasks.withType().configureEach { + options.release = 21 +} + +java { + // Loom attaches the sources jar to remapSourcesJar and build. + withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +tasks.jar { + val archivesName = base.archivesName + inputs.property("archivesName", archivesName) + from("LICENSE") { + rename { "${it}_${archivesName.get()}" } + } + from(project(":common").extensions.getByType()["main"].output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +publishing { + publications { + create("mavenJava") { + artifactId = property("archives_base_name") as String + from(components["java"]) + } + } +} diff --git a/gradle.properties b/gradle.properties index a898428..947409b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,3 +10,6 @@ mod_version=0.1.1-beta # Saturn's emote library (git.selimaj.dev/saturnclientmc/emotes) emotes_version=0.1.0 + +# Loom, for the Stonecutter versions (settings.gradle.kts). Old mc- projects set their own. +loom_version=1.17.21 diff --git a/scripts/port.sh b/scripts/port.sh index 5f22636..2715fd5 100755 --- a/scripts/port.sh +++ b/scripts/port.sh @@ -6,9 +6,9 @@ # normal merge conflicts only where a version really differs. Only source is # ported; build.gradle and gradle.properties are version-specific on purpose. # -# Versions moved to Stonecutter (stonecutterVersions in settings.gradle) share -# the top-level src/, which counts as one version: the active one set in -# stonecutter.gradle. The others keep their own copy in versions//src. +# Versions moved to Stonecutter (stonecutterVersions in settings.gradle.kts) +# share the top-level src/, which counts as one version: the active one set in +# stonecutter.gradle.kts. The others keep their own copy in versions//src. # # Usage: # scripts/port.sh [--from VERSION] [--to V1,V2,...] [--commit REV] [--dry-run] @@ -43,8 +43,8 @@ while [ $# -gt 0 ]; do done # Versions sharing the Stonecutter src/, and the one that stands for them. -stonecutter_versions=$(sed -n 's/^def stonecutterVersions = \[\(.*\)\]/\1/p' settings.gradle | tr -d '" ' | tr ',' ' ') -stonecutter_active=$(sed -n 's/^stonecutter\.active "\(.*\)"/\1/p' stonecutter.gradle 2>/dev/null || true) +stonecutter_versions=$(sed -n 's/^val stonecutterVersions = listOf(\(.*\))/\1/p' settings.gradle.kts | tr -d '" ' | tr ',' ' ') +stonecutter_active=$(sed -n 's/^stonecutter active "\(.*\)"/\1/p' stonecutter.gradle.kts 2>/dev/null || true) is_stonecutter() { printf '%s\n' $stonecutter_versions | grep -qx "$1" diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 95f2676..0000000 --- a/settings.gradle +++ /dev/null @@ -1,40 +0,0 @@ -pluginManagement { - repositories { - maven { url "https://maven.fabricmc.net/" } - maven { url "https://maven.kikugie.dev/releases" } - gradlePluginPortal() - mavenCentral() - } -} - -plugins { - id "dev.kikugie.stonecutter" version "0.9.8" -} - -rootProject.name = "saturn-client" - -include("common") - -// Versions built by Stonecutter from the shared src/ (see stonecutter.gradle). Each one's -// versions//gradle.properties holds its Minecraft, Yarn and Fabric API versions. -def stonecutterVersions = ["1.21.11"] - -stonecutter { - kotlinController = false // stonecutter.gradle configures the root project - centralScript = "build.gradle" // build.gradle configures each version - create(rootProject) { - versions(*stonecutterVersions) - vcsVersion = "1.21.11" - } -} - -// Versions not moved to Stonecutter yet still build from their own copy in versions//src, -// as projects named mc-. -file("versions").eachDir { dir -> - if (dir.name in stonecutterVersions) { - return - } - def projectName = "mc-${dir.name}" - include(projectName) - project(":${projectName}").projectDir = dir -} diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..69f2e22 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,43 @@ +pluginManagement { + repositories { + maven("https://maven.fabricmc.net/") + maven("https://maven.kikugie.dev/releases") + gradlePluginPortal() + mavenCentral() + } + + // Loom's version, for the Stonecutter versions' build.gradle.kts (the old mc- projects set + // their own in versions//gradle.properties). + val loom_version: String by settings + plugins { + id("net.fabricmc.fabric-loom-remap") version loom_version + } +} + +plugins { + id("dev.kikugie.stonecutter") version "0.9.8" +} + +rootProject.name = "saturn-client" + +include("common") + +// Versions built by Stonecutter from the shared src/ (see stonecutter.gradle.kts). Each one's +// versions//gradle.properties holds its Minecraft, Yarn and Fabric API versions. +val stonecutterVersions = listOf("1.21.11") + +stonecutter { + create(rootProject) { + versions(stonecutterVersions) + vcsVersion = "1.21.11" + } +} + +// Versions not moved to Stonecutter yet still build from their own copy in versions//src, +// as projects named mc-. +file("versions").listFiles { file -> file.isDirectory && file.name !in stonecutterVersions }!! + .sortedBy { it.name } + .forEach { dir -> + include("mc-${dir.name}") + project(":mc-${dir.name}").projectDir = dir + } diff --git a/stonecutter.gradle b/stonecutter.gradle deleted file mode 100644 index 131f357..0000000 --- a/stonecutter.gradle +++ /dev/null @@ -1,73 +0,0 @@ -plugins { - id "dev.kikugie.stonecutter" -} - -// The version whose code is uncommented in src/. Switch with "Set active project to ", and run -// "Reset active project" before committing. -stonecutter.active "1.21.11" - -subprojects { - apply plugin: "java" - - repositories { - maven { url "https://maven.fabricmc.net/" } - maven { url "https://git.selimaj.dev/api/packages/selimaj-dev/maven" } - maven { url "https://git.selimaj.dev/api/packages/saturnclientmc/maven" } - mavenCentral() - } - - dependencies { - implementation "de.javagl:obj:0.4.0" - implementation "com.formdev:svgSalamander:1.1.4" - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.0' - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.0' - } -} - -configure(subprojects.findAll { it.name != "common" }) { - dependencies { - implementation project(":common") - } - - sourceSets { - main { - resources { - srcDir project(":common").file("src/main/resources") - } - } - } -} - -tasks.register("buildAll") { - group = "build" - description = "Builds all subprojects and collects their remapped jars" - - // Only build remapped jars (not full build) - dependsOn subprojects.collect { proj -> - proj.tasks.matching { it.name == "remapJar" } - } - - doLast { - def outputDir = file("$buildDir/allJars") - outputDir.mkdirs() - - subprojects.each { proj -> - def remapTask = proj.tasks.findByName("remapJar") - - if (remapTask != null) { - def jarFile = remapTask.archiveFile.get().asFile - - if (jarFile.exists() && !jarFile.name.contains("sources")) { - copy { - from jarFile - into outputDir - rename { "${jarFile.name}" } - } - } - } - } - - println "All remapped jars collected in: $outputDir" - } -} diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts new file mode 100644 index 0000000..ba6ec10 --- /dev/null +++ b/stonecutter.gradle.kts @@ -0,0 +1,71 @@ +plugins { + id("dev.kikugie.stonecutter") +} + +// The version whose code is uncommented in src/. Switch with "Set active project to ", and run +// "Reset active project" before committing. +stonecutter active "1.21.11" + +subprojects { + apply(plugin = "java") + + repositories { + maven("https://maven.fabricmc.net/") + maven("https://git.selimaj.dev/api/packages/selimaj-dev/maven") + maven("https://git.selimaj.dev/api/packages/saturnclientmc/maven") + mavenCentral() + } + + dependencies { + "implementation"("de.javagl:obj:0.4.0") + "implementation"("com.formdev:svgSalamander:1.1.4") + "implementation"("com.fasterxml.jackson.core:jackson-databind:2.17.0") + "implementation"("com.fasterxml.jackson.core:jackson-annotations:2.17.0") + "implementation"("com.fasterxml.jackson.core:jackson-core:2.17.0") + } +} + +// Every Minecraft version builds on common and ships its resources. +configure(subprojects.filter { it.name != "common" }) { + dependencies { + "implementation"(project(":common")) + } + + extensions.configure { + named("main") { + resources.srcDir(project(":common").file("src/main/resources")) + } + } +} + +// remapJar loads a whole Minecraft classpath and remaps a ~50 MB jar. Eight at once don't fit in the +// daemon's heap (org.gradle.jvmargs) and the build stalls in garbage collection, so only two run +// together. Everything else still builds in parallel. +abstract class RemapLimit : BuildService + +val remapLimit = gradle.sharedServices.registerIfAbsent("remapLimit", RemapLimit::class) { + maxParallelUsages = 2 +} + +subprojects { + tasks.matching { it.name == "remapJar" }.configureEach { + usesService(remapLimit) + } +} + +tasks.register("buildAll") { + group = "build" + description = "Builds every Minecraft version's remapped jar and collects them in build/allJars" + + val remapJars = subprojects.flatMap { it.tasks.matching { task -> task.name == "remapJar" } } + dependsOn(remapJars) + + doLast { + val outputDir = layout.buildDirectory.dir("allJars").get().asFile + outputDir.mkdirs() + remapJars.map { (it as AbstractArchiveTask).archiveFile.get().asFile } + .filter { it.exists() && !it.name.contains("sources") } + .forEach { it.copyTo(outputDir.resolve(it.name), overwrite = true) } + println("All remapped jars collected in: $outputDir") + } +} diff --git a/versions/1.21.11/gradle.properties b/versions/1.21.11/gradle.properties index ef10f0c..48f9b6d 100644 --- a/versions/1.21.11/gradle.properties +++ b/versions/1.21.11/gradle.properties @@ -10,7 +10,6 @@ org.gradle.configuration-cache=false minecraft_version=1.21.11 yarn_mappings=1.21.11+build.4 loader_version=0.19.0 -loom_version=1.17.21 fabric_api_version=0.141.3+1.21.11