From 5aece1c0617cbb51f06091f6d84585657715422a Mon Sep 17 00:00:00 2001 From: Rongmario Date: Mon, 11 May 2026 13:15:32 +0100 Subject: [PATCH 01/10] Fixed modrinth token exception --- gradle/scripts/publishing.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/scripts/publishing.gradle b/gradle/scripts/publishing.gradle index 6edf1dc7..ec6082e9 100644 --- a/gradle/scripts/publishing.gradle +++ b/gradle/scripts/publishing.gradle @@ -78,7 +78,7 @@ if (propertyBool('publish_to_modrinth')) { assertProperty('release_type') setDefaultProperty('modrinth_debug', false, false) modrinth { - token = System.getenv('MODRINTH_TOKEN') ? "" : System.getenv('MODRINTH_TOKEN') + token = System.getenv('MODRINTH_TOKEN') == null ? "" : System.getenv('MODRINTH_TOKEN') projectId = propertyString('modrinth_project_id') versionNumber = propertyString('mod_version') versionType = propertyString('release_type') From 918a64dc44ad035100e10f2b698d88d1dc19e8b8 Mon Sep 17 00:00:00 2001 From: jbred <47703524+jbredwards@users.noreply.github.com> Date: Fri, 29 May 2026 11:55:42 -0400 Subject: [PATCH 02/10] Update gradle.properties (#55) Include more information about the `mod_update_json` field. --- gradle.properties | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ddefea25..1ea1b7e7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,6 +23,9 @@ mod_name = Mod Name # Mod Metadata (Optional) mod_description = mod_url = +# A url where the mod's update json can be fetched +# Wiki: https://docs.minecraftforge.net/en/1.12.x/gettingstarted/autoupdate/#forge-update-checker +# Also see: https://curseupdate.com + https://docs.modrinth.com/api/operations/forgeupdates mod_update_json = # Delimit authors with commas mod_authors = @@ -123,4 +126,4 @@ coremod_plugin_class_name = # Convenient way to allow downloading of assets from official vanilla Minecraft servers, CurseForge, or any direct links # Documentation: https://github.com/CleanroomMC/AssetMover use_asset_mover = false -asset_mover_version = 2.5 \ No newline at end of file +asset_mover_version = 2.5 From faa5bd23bcd10a20de5f276989cb8ae57a46e42c Mon Sep 17 00:00:00 2001 From: ZZZank <47418975+ZZZank@users.noreply.github.com> Date: Fri, 29 May 2026 23:57:17 +0800 Subject: [PATCH 03/10] Force decompression when there's no source available (#57) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 16141a6d..0aab3350 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ base { archivesName.set(propertyString('mod_id')) } -tasks.decompressDecompiledSources.enabled !propertyBool('change_minecraft_sources') +tasks.decompressDecompiledSources.enabled !propertyBool('change_minecraft_sources') || !project.file("./build/rfg/minecraft-src").exists() java { toolchain { From e5ce281a41f59542b5b719c9533c60a0d64a1419 Mon Sep 17 00:00:00 2001 From: Rongmario Date: Fri, 29 May 2026 17:08:47 +0100 Subject: [PATCH 04/10] Use `ProjectLayout#getBuildDirectory` --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0aab3350..dfd3a55f 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ base { archivesName.set(propertyString('mod_id')) } -tasks.decompressDecompiledSources.enabled !propertyBool('change_minecraft_sources') || !project.file("./build/rfg/minecraft-src").exists() +tasks.decompressDecompiledSources.enabled !propertyBool('change_minecraft_sources') || !layout.buildDirectory.dir('rfg/minecraft-src').get().asFile.exists() java { toolchain { From a7d81c5475bb2da22d4d51760d46f576a9ca91c0 Mon Sep 17 00:00:00 2001 From: Rongmario Date: Fri, 29 May 2026 18:12:39 +0100 Subject: [PATCH 05/10] Throw exception when tags.properties contains empty values --- build.gradle | 8 ++++++-- gradle.properties | 1 + src/main/java/com/example/modid/ExampleMod.java | 1 - 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index dfd3a55f..f87c6ae0 100644 --- a/build.gradle +++ b/build.gradle @@ -94,9 +94,13 @@ minecraft { if (propertyBool('use_tags')) { if (file('tags.properties').exists()) { - Properties props = new Properties().tap { it.load(file('tags.properties').newInputStream()); it } + Properties props = new Properties().tap { it.load(file('tags.properties').newInputStream()); it } if (!props.isEmpty()) { - injectedTags.set(props.collectEntries { k, v -> [(k): interpolate(v)] }) + injectedTags.set(props.collectEntries { k, v -> + def interpolated = interpolate(v) + if (interpolated == null || interpolated.isEmpty()) throw new GradleException("Empty tag value found for key: $k") + [(k): interpolated] + }) } } } diff --git a/gradle.properties b/gradle.properties index 1ea1b7e7..a32e9dd9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,6 +21,7 @@ mod_id = modid mod_name = Mod Name # Mod Metadata (Optional) +# Use tags.properties to bring these values into your Tags class (see below: use_tags) mod_description = mod_url = # A url where the mod's update json can be fetched diff --git a/src/main/java/com/example/modid/ExampleMod.java b/src/main/java/com/example/modid/ExampleMod.java index 4dd9e464..7437eb13 100644 --- a/src/main/java/com/example/modid/ExampleMod.java +++ b/src/main/java/com/example/modid/ExampleMod.java @@ -1,6 +1,5 @@ package com.example.modid; -import com.example.modid.Tags; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import org.apache.logging.log4j.LogManager; From f64cfc13d12443565d7c9576b1677698ffe0bf0c Mon Sep 17 00:00:00 2001 From: Rongmario Date: Fri, 29 May 2026 23:57:05 +0100 Subject: [PATCH 06/10] Update Gradle 9.2.1 => 9.5.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cd4b7aa8..cf71939e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c74317ab8ae8ff3215aa17a5c8087e2400ef37ec Mon Sep 17 00:00:00 2001 From: Rongmario Date: Fri, 29 May 2026 23:57:38 +0100 Subject: [PATCH 07/10] Update JetBrains IDEA ext plugin 1.3 => 1.4.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f87c6ae0..1b143e27 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { id 'java' id 'java-library' id 'maven-publish' - id 'org.jetbrains.gradle.plugin.idea-ext' version '1.3' + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.4.1' id 'com.gtnewhorizons.retrofuturagradle' version '2.0.2' id 'com.matthewprenger.cursegradle' version '1.4.0' apply false id 'com.modrinth.minotaur' version '2.+' apply false From b05d8b16fba228c0768c076d889189ad8521d915 Mon Sep 17 00:00:00 2001 From: Rongmario Date: Fri, 29 May 2026 23:58:33 +0100 Subject: [PATCH 08/10] Remove embed and add shadow plugin with QoL improvements --- build.gradle | 8 +------- gradle/scripts/dependencies.gradle | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 1b143e27..865ed172 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,7 @@ plugins { id 'com.matthewprenger.cursegradle' version '1.4.0' apply false id 'com.modrinth.minotaur' version '2.+' apply false id 'org.jetbrains.changelog' version '2.5.0' + id 'com.gradleup.shadow' version '9.4.+' } apply from: 'gradle/scripts/helpers.gradle' @@ -64,11 +65,6 @@ java { } } -configurations { - embed - implementation.extendsFrom(embed) -} - minecraft { mcVersion.set('1.12.2') @@ -223,8 +219,6 @@ jar { } attributes(attribute_map) } - // Add all embedded dependencies into the jar - from(provider{ configurations.embed.collect {it.isDirectory() ? it : zipTree(it)} }) } idea { diff --git a/gradle/scripts/dependencies.gradle b/gradle/scripts/dependencies.gradle index 66c8208a..c618731b 100644 --- a/gradle/scripts/dependencies.gradle +++ b/gradle/scripts/dependencies.gradle @@ -28,6 +28,11 @@ repositories { mavenLocal() // Must be last for caching to work } +configurations { + shade + implementation.extendsFrom shade +} + dependencies { // Include StripLatestForgeRequirements by default for the dev env, saves everyone a hassle runtimeOnly 'com.cleanroommc:strip-latest-forge-requirements:1.0' @@ -43,6 +48,11 @@ dependencies { // By wrapping a dependency descriptor in rfg.deobf() method call, the dependency is queued for deobfuscation // When deobfuscating, RFG respects the mapping_channel + mapping_version stated in gradle.properties + // Example - Shading dependencies: + // Using the shadow plugin, by using the "shade" configuration, the dependency will be shaded into your output jar + // shade 'mezz:jei:4.31.2' << will shade HadEnoughItems 4.31.2 directly into your jar + // For more configuration options: see the bottom of this file and: https://gradleup.com/shadow/configuration/ + // Example - CurseMaven dependencies: // 'curse.maven:had-enough-items-557549:4543375' << had-enough-items = project slug, 557549 = project id, 4543375 = file id // Full documentation: https://cursemaven.com/ @@ -56,7 +66,7 @@ dependencies { // runtimeOnly = runtime dependency // compileOnly = compile time dependency // annotationProcessor = annotation processing dependencies - // embed = bundle dependencies into final output artifact (no relocation) + // shade = includes dependency in output // Transitive dependencies: // (Dependencies that your dependency depends on) @@ -65,4 +75,17 @@ dependencies { // implementation ('com.google.code.gson:gson:2.8.6') { // transitive = false // } -} \ No newline at end of file +} + +// Need reobfJar to use uber jars, so dependencies that are shaded in are present +tasks.named('reobfJar').configure { + inputJar.set(tasks.named('shadowJar').flatMap({ it.archiveFile })) +} + +// By default, it will use a "uberdev" suffix, and only pack shade configuration dependencies +// Uberdev: dev jar w/ dependencies, NOT a reobfuscated artifact! +// The end result (reobfJar) will have a non-suffixed name, as unlike normal shading envs, reobfJar is the end task +tasks.shadowJar { + archiveClassifier = 'uberdev' + configurations = [ project.configurations.shade ] +} From 9ad7c2fdf89aec97c608430ab14c7ef6f837e364 Mon Sep 17 00:00:00 2001 From: Rongmario Date: Sat, 30 May 2026 00:16:02 +0100 Subject: [PATCH 09/10] Update default MixinBooter version 10.2 => 10.7 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a32e9dd9..7e8ecf34 100644 --- a/gradle.properties +++ b/gradle.properties @@ -102,7 +102,7 @@ access_transformer_locations = ${mod_id}_at.cfg # Wiki: https://github.com/SpongePowered/Mixin/wiki + https://github.com/CleanroomMC/MixinBooter/ + https://cleanroommc.com/wiki/forge-mod-development/mixin/preface # Only use mixins once you understand the underlying structure use_mixins = false -mixin_booter_version = 10.2 +mixin_booter_version = 10.7 # A configuration defines a mixin set, and you may have as many mixin sets as you require for your application. # Each config can only have one and only one package root. # Generate missing configs, obtain from mixin_configs and generate file base on name convention: "mixins.config_name.json" From 522b4f857e8d90266d29718fd2bbe9f9c662d58e Mon Sep 17 00:00:00 2001 From: RuiXuqi <90179819+RuiXuqi@users.noreply.github.com> Date: Sat, 30 May 2026 17:43:07 +0800 Subject: [PATCH 10/10] Polish shadow configuration So we can avoid users messing the configs --- build.gradle | 34 +++++++++++++++++++++++------- gradle.properties | 8 ++++--- gradle/scripts/dependencies.gradle | 31 ++++++++++++--------------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/build.gradle b/build.gradle index 1dacf150..d6f7b689 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,6 @@ assertProperty 'mod_id' assertProperty 'mod_name' assertSubProperties 'use_tags', 'tag_class_name' -assertSubProperties 'use_lombok_ap', 'lombok_version' assertSubProperties 'use_access_transformer', 'access_transformer_locations' assertSubProperties 'use_mixins', 'mixin_booter_version', 'mixin_refmap' assertSubProperties 'is_coremod', 'coremod_includes_mod', 'coremod_plugin_class_name' @@ -64,6 +63,11 @@ java { } } +configurations { + shaded + implementation.extendsFrom shaded +} + minecraft { mcVersion.set('1.12.2') @@ -124,13 +128,6 @@ dependencies { transitive = false // We only care about the 1 annotation class } } - if (propertyBool('use_lombok_ap')) { - compileOnly "org.projectlombok:lombok:${propertyString('lombok_version')}" - annotationProcessor "org.projectlombok:lombok:${propertyString('lombok_version')}" - - testCompileOnly "org.projectlombok:lombok:${propertyString('lombok_version')}" - testAnnotationProcessor "org.projectlombok:lombok:${propertyString('lombok_version')}" - } if (propertyBool('use_asset_mover')) { implementation "com.cleanroommc:assetmover:${propertyString('asset_mover_version')}" } @@ -240,6 +237,27 @@ jar { } } +// Shade deps to the dev jar, so the normal dev jar will contain deps +shadowJar { + archiveClassifier = 'dev' + configurations = [ project.configurations.shaded ] +} + +if (propertyBool('enable_shadow')) { + // Unshaded dev jar get 'plain' as name + tasks.named("jar").configure { + archiveClassifier = "plain" + } + // Here we reobf the shaded dev jar, so the final obf jar will contain deps + tasks.named('reobfJar').configure { + inputJar.set(tasks.named('shadowJar').flatMap { it.archiveFile }) + } +} else { + tasks.named('shadowJar').configure { + enabled = false + } +} + idea { module { inheritOutputDirs = true diff --git a/gradle.properties b/gradle.properties index 567b8c48..6b85077e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,9 +4,6 @@ org.gradle.jvmargs = -Xmx3G # Source Options # Use Modern Java(9+) Syntax (Courtesy of Jabel) use_modern_java_syntax = false -# Use Lombok annotation processor -use_lombok_ap = false -lombok_version = 1.18.46 # Compilation Options generate_sources_jar = true @@ -16,6 +13,11 @@ generate_javadocs_jar = false enable_junit_testing = true show_testing_output = false +# Shadow +# This will rename the 'dev' jar to 'plain' and replace 'dev' with a shaded jar +# Deps will be shaded into the final obf jar with no suffix too +enable_shadow = false + # Mod Information # HIGHLY RECOMMEND complying with SemVer for mod_version: https://semver.org/ mod_version = 1.0.0 diff --git a/gradle/scripts/dependencies.gradle b/gradle/scripts/dependencies.gradle index 72321fc7..97a8858a 100644 --- a/gradle/scripts/dependencies.gradle +++ b/gradle/scripts/dependencies.gradle @@ -22,11 +22,6 @@ repositories { mavenLocal() // Must be last for caching to work } -configurations { - shade - implementation.extendsFrom shade -} - dependencies { // Include StripLatestForgeRequirements by default for the dev env, saves everyone a hassle runtimeOnly 'com.cleanroommc:strip-latest-forge-requirements:1.0' @@ -43,8 +38,8 @@ dependencies { // When deobfuscating, RFG respects the mapping_channel + mapping_version stated in gradle.properties // Example - Shading dependencies: - // Using the shadow plugin, by using the "shade" configuration, the dependency will be shaded into your output jar - // shade 'mezz:jei:4.31.2' << will shade HadEnoughItems 4.31.2 directly into your jar + // Using the shadow plugin, by using the "shaded" configuration, the dependency will be shaded into your output jar + // shaded 'mezz:jei:4.31.2' << will shade HadEnoughItems 4.31.2 directly into your jar // For more configuration options: see the bottom of this file and: https://gradleup.com/shadow/configuration/ // Example - CurseMaven dependencies: @@ -63,7 +58,7 @@ dependencies { // runtimeOnly = runtime dependency // compileOnly = compile time dependency // annotationProcessor = annotation processing dependencies - // shade = includes dependency in output + // shaded = includes dependency in output // Transitive dependencies: // (Dependencies that your dependency depends on) @@ -74,15 +69,15 @@ dependencies { // } } -// Need reobfJar to use uber jars, so dependencies that are shaded in are present -tasks.named('reobfJar').configure { - inputJar.set(tasks.named('shadowJar').flatMap({ it.archiveFile })) -} +tasks.named("shadowJar").configure { + // Exclude specific parts of deps to keep your jar clean + // dependencies { + // exclude 'META-INF/maven/**' + // } + + // Relocate specific parts of deps, so multiple shaded classes in mods will not conflict + // relocate "mezz.jei", "shaded.mezz.jei" -// By default, it will use a "uberdev" suffix, and only pack shade configuration dependencies -// Uberdev: dev jar w/ dependencies, NOT a reobfuscated artifact! -// The end result (reobfJar) will have a non-suffixed name, as unlike normal shading envs, reobfJar is the end task -tasks.shadowJar { - archiveClassifier = 'uberdev' - configurations = [ project.configurations.shade ] + // Remove unused classes automatically. May cause issues if they are accessed by reflection + // minimize() }