From 371bfe905ac0f4031df52a978f6a522ddf229791 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 30 Oct 2025 07:44:02 +0000 Subject: [PATCH 01/10] Start on 1.13 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index edeb45e2..7f18b2b8 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { } group = 'net.fabricmc' -def baseVersion = '1.12' +def baseVersion = '1.13' def ENV = System.getenv() if (ENV.BUILD_NUMBER) { From 04995cbcf9fb5e55ef928390ede176b2115d2f2c Mon Sep 17 00:00:00 2001 From: feenko Date: Thu, 30 Oct 2025 15:54:17 +0000 Subject: [PATCH 02/10] Fix FMJ generator not resolving dependencies correctly with exactly one version range (#1408) --- .../loom/util/fmj/gen/FabricModJsonV1Generator.java | 2 +- .../unit/fmj/FabricModJsonV1GeneratorTest.groovy | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/util/fmj/gen/FabricModJsonV1Generator.java b/src/main/java/net/fabricmc/loom/util/fmj/gen/FabricModJsonV1Generator.java index 848b197d..8b3662bd 100644 --- a/src/main/java/net/fabricmc/loom/util/fmj/gen/FabricModJsonV1Generator.java +++ b/src/main/java/net/fabricmc/loom/util/fmj/gen/FabricModJsonV1Generator.java @@ -165,7 +165,7 @@ public final class FabricModJsonV1Generator implements FabricModJsonGenerator Date: Thu, 30 Oct 2025 22:10:47 +0200 Subject: [PATCH 03/10] Make remapping tasks use the archive file from the Jar API (#1406) * Make remapping tasks use the archive file from the Jar API Other minor changes: - Exception messages now include the absolute path of the jar file - RemapSourcesJarTask now also uses descriptive wrappers instead of a direct new RuntimeException(...) * Stop overriding Jar.copy with a no-op * Add test for using Jar's API on remapJar and remapSourcesJar --- .../loom/task/AbstractRemapJarTask.java | 44 ++++++--- .../net/fabricmc/loom/task/RemapJarTask.java | 24 ++--- .../loom/task/RemapSourcesJarTask.java | 44 ++++----- .../integration/RemapJarContentsTest.groovy | 62 +++++++++++++ .../projects/remapJarContents/build.gradle | 91 +++++++++++++++++++ .../remapJarContents/gradle.properties | 16 ++++ .../projects/remapJarContents/settings.gradle | 2 + .../java/net/fabricmc/example/ExampleMod.java | 21 +++++ .../fabricmc/example/mixin/ExampleMixin.java | 15 +++ .../src/main/resources/fabric.mod.json | 36 ++++++++ .../src/main/resources/modid.mixins.json | 14 +++ .../projects/remapJarContents/test_file.txt | 1 + .../remapJarContents/test_src_file.txt | 1 + 13 files changed, 314 insertions(+), 57 deletions(-) create mode 100644 src/test/groovy/net/fabricmc/loom/test/integration/RemapJarContentsTest.groovy create mode 100644 src/test/resources/projects/remapJarContents/build.gradle create mode 100644 src/test/resources/projects/remapJarContents/gradle.properties create mode 100644 src/test/resources/projects/remapJarContents/settings.gradle create mode 100644 src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/ExampleMod.java create mode 100644 src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java create mode 100644 src/test/resources/projects/remapJarContents/src/main/resources/fabric.mod.json create mode 100644 src/test/resources/projects/remapJarContents/src/main/resources/modid.mixins.json create mode 100644 src/test/resources/projects/remapJarContents/test_file.txt create mode 100644 src/test/resources/projects/remapJarContents/test_src_file.txt diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java index f2846ee2..4bea2333 100644 --- a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-2025 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,9 @@ package net.fabricmc.loom.task; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -56,6 +58,8 @@ import org.gradle.workers.WorkParameters; import org.gradle.workers.WorkQueue; import org.gradle.workers.WorkerExecutor; import org.jetbrains.annotations.ApiStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; @@ -63,6 +67,7 @@ import net.fabricmc.loom.task.service.ClientEntriesService; import net.fabricmc.loom.task.service.JarManifestService; import net.fabricmc.loom.util.Check; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.ZipReprocessorUtil; import net.fabricmc.loom.util.ZipUtils; import net.fabricmc.loom.util.gradle.SourceSetHelper; @@ -115,6 +120,7 @@ public abstract class AbstractRemapJarTask extends Jar { @Inject public AbstractRemapJarTask() { + from(getProject().zipTree(getInputFile())); getSourceNamespace().convention(MappingsNamespace.NAMED.toString()).finalizeValueOnRead(); getTargetNamespace().convention(MappingsNamespace.INTERMEDIARY.toString()).finalizeValueOnRead(); getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead(); @@ -133,17 +139,11 @@ public abstract class AbstractRemapJarTask extends Jar { usesService(jarManifestServiceProvider); } - @Override - protected void copy() { - // Skip the default copy behaviour of AbstractCopyTask. - } - public final

void submitWork(Class> workAction, Action

action) { final WorkQueue workQueue = getWorkerExecutor().noIsolation(); workQueue.submit(workAction, params -> { - params.getInputFile().set(getInputFile()); - params.getOutputFile().set(getArchiveFile()); + params.getArchiveFile().set(getArchiveFile()); params.getSourceNamespace().set(getSourceNamespace()); params.getTargetNamespace().set(getTargetNamespace()); @@ -181,8 +181,7 @@ public abstract class AbstractRemapJarTask extends Jar { protected abstract Provider getClientOnlyEntriesOptionsProvider(SourceSet clientSourceSet); public interface AbstractRemapParams extends WorkParameters { - RegularFileProperty getInputFile(); - RegularFileProperty getOutputFile(); + RegularFileProperty getArchiveFile(); Property getSourceNamespace(); Property getTargetNamespace(); @@ -217,15 +216,34 @@ public abstract class AbstractRemapJarTask extends Jar { } public abstract static class AbstractRemapAction implements WorkAction { - protected final Path inputFile; + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRemapAction.class); protected final Path outputFile; @Inject public AbstractRemapAction() { - inputFile = getParameters().getInputFile().getAsFile().get().toPath(); - outputFile = getParameters().getOutputFile().getAsFile().get().toPath(); + outputFile = getParameters().getArchiveFile().getAsFile().get().toPath(); } + @Override + public final void execute() { + try { + Path tempInput = Files.createTempFile("loom-remapJar-", "-input.jar"); + Files.copy(outputFile, tempInput, StandardCopyOption.REPLACE_EXISTING); + execute(tempInput); + Files.delete(tempInput); + } catch (Exception e) { + try { + Files.deleteIfExists(outputFile); + } catch (IOException ex) { + LOGGER.error("Failed to delete output file", ex); + } + + throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to remap " + outputFile.toAbsolutePath(), e); + } + } + + protected abstract void execute(Path inputFile) throws IOException; + protected void modifyJarManifest() throws IOException { int count = ZipUtils.transform(outputFile, Map.of(Constants.Manifest.PATH, bytes -> { var manifest = new Manifest(new ByteArrayInputStream(bytes)); diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 745da380..7686e882 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021-2024 FabricMC + * Copyright (c) 2021-2025 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,6 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskProvider; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -64,7 +63,6 @@ import net.fabricmc.loom.task.service.ClientEntriesService; import net.fabricmc.loom.task.service.MixinRefmapService; import net.fabricmc.loom.task.service.TinyRemapperService; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.Pair; import net.fabricmc.loom.util.SidedClassVisitor; import net.fabricmc.loom.util.ZipUtils; @@ -122,8 +120,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { getMixinRefmapServiceOptions().set(MixinRefmapService.createOptions(this)); } - @TaskAction - public void run() { + @Override + protected void copy() { + super.copy(); + submitWork(RemapAction.class, params -> { if (getAddNestedDependencies().get()) { params.getNestedJars().from(getNestedJars()); @@ -165,14 +165,16 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { private @Nullable TinyRemapperService tinyRemapperService; private @Nullable TinyRemapper tinyRemapper; + private Path inputFile; public RemapAction() { } @Override - public void execute() { + protected void execute(Path inputFile) throws IOException { try (var serviceFactory = new ScopedServiceFactory()) { LOGGER.info("Remapping {} to {}", inputFile, outputFile); + this.inputFile = inputFile; this.tinyRemapperService = getParameters().getTinyRemapperServiceOptions().isPresent() ? serviceFactory.get(getParameters().getTinyRemapperServiceOptions().get()) @@ -207,20 +209,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { } LOGGER.debug("Finished remapping {}", inputFile); - } catch (Exception e) { - try { - Files.deleteIfExists(outputFile); - } catch (IOException ex) { - LOGGER.error("Failed to delete output file", ex); - } - - throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to remap", e); } } private void prepare() { - final Path inputFile = getParameters().getInputFile().getAsFile().get().toPath(); - if (tinyRemapperService != null) { tinyRemapperService.getTinyRemapperForInputs().readInputsAsync(tinyRemapperService.getOrCreateTag(inputFile), inputFile); } diff --git a/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java index ffa2adca..4a92c257 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-2025 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ package net.fabricmc.loom.task; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; import javax.inject.Inject; @@ -35,9 +36,6 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.TaskAction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import net.fabricmc.loom.task.service.ClientEntriesService; import net.fabricmc.loom.task.service.SourceRemapperService; @@ -56,8 +54,10 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask { getSourcesRemapperServiceOptions().set(SourceRemapperService.createOptions(this)); } - @TaskAction - public void run() { + @Override + protected void copy() { + super.copy(); + submitWork(RemapSourcesAction.class, params -> { if (!params.namespacesMatch()) { params.getSourcesRemapperServiceOptions().set(getSourcesRemapperServiceOptions()); @@ -75,35 +75,23 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask { } public abstract static class RemapSourcesAction extends AbstractRemapAction { - private static final Logger LOGGER = LoggerFactory.getLogger(RemapSourcesAction.class); - public RemapSourcesAction() { super(); } @Override - public void execute() { - try { - if (!getParameters().namespacesMatch()) { - try (var serviceFactory = new ScopedServiceFactory()) { - SourceRemapperService sourceRemapperService = serviceFactory.get(getParameters().getSourcesRemapperServiceOptions()); - sourceRemapperService.remapSourcesJar(inputFile, outputFile); - } - } else { - Files.copy(inputFile, outputFile, StandardCopyOption.REPLACE_EXISTING); + protected void execute(Path inputFile) throws IOException { + if (!getParameters().namespacesMatch()) { + try (var serviceFactory = new ScopedServiceFactory()) { + SourceRemapperService sourceRemapperService = serviceFactory.get(getParameters().getSourcesRemapperServiceOptions()); + sourceRemapperService.remapSourcesJar(inputFile, outputFile); } - - modifyJarManifest(); - rewriteJar(); - } catch (Exception e) { - try { - Files.deleteIfExists(outputFile); - } catch (IOException ex) { - LOGGER.error("Failed to delete output file", ex); - } - - throw new RuntimeException("Failed to remap sources", e); + } else { + Files.copy(inputFile, outputFile, StandardCopyOption.REPLACE_EXISTING); } + + modifyJarManifest(); + rewriteJar(); } } } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/RemapJarContentsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/RemapJarContentsTest.groovy new file mode 100644 index 00000000..fdf556b5 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/RemapJarContentsTest.groovy @@ -0,0 +1,62 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2025 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.integration + +import java.util.jar.JarFile +import java.util.jar.Manifest + +import spock.lang.Specification +import spock.lang.Unroll + +import net.fabricmc.loom.test.util.GradleProjectTestTrait +import net.fabricmc.loom.util.ZipUtils + +import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class RemapJarContentsTest extends Specification implements GradleProjectTestTrait { + @Unroll + def "use jar apis on remapJar and remapSourcesJar (gradle #version)"() { + setup: + def gradle = gradleProject(project: "remapJarContents", version: version) + + when: + def result = gradle.run(task: "build") + + then: + result.task(":build").outcome == SUCCESS + ZipUtils.contains(gradle.getOutputFile('fabric-example-mod-1.0.0.jar').toPath(), 'test_file.txt') + ZipUtils.contains(gradle.getOutputFile('fabric-example-mod-1.0.0-sources.jar').toPath(), 'test_src_file.txt') + def manifest = readManifest(gradle.getOutputFile('fabric-example-mod-1.0.0.jar')) + manifest.mainAttributes.getValue('Hello-World') == 'test' + + where: + version << STANDARD_TEST_VERSIONS + } + + private static Manifest readManifest(File file) { + return new JarFile(file).withCloseable { it.manifest } + } +} diff --git a/src/test/resources/projects/remapJarContents/build.gradle b/src/test/resources/projects/remapJarContents/build.gradle new file mode 100644 index 00000000..cd411be5 --- /dev/null +++ b/src/test/resources/projects/remapJarContents/build.gradle @@ -0,0 +1,91 @@ +plugins { + id 'fabric-loom' + id 'maven-publish' +} + +version = loom.modVersion +group = project.maven_group + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. +} + +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_version}" + + // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. + // You may need to force-disable transitiveness on them. +} + +test { + enabled = false +} + +base { + archivesName = project.archives_base_name +} + +tasks.withType(JavaCompile).configureEach { + // ensure that the encoding is set to UTF-8, no matter what the system default is + // this fixes some edge cases with special characters not displaying correctly + // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + + // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too + // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. + // We'll use that if it's available, but otherwise we'll use the older option. + def targetVersion = 8 + if (JavaVersion.current().isJava9Compatible()) { + it.options.release = targetVersion + } +} + +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_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + 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. + } +} + +remapJar { + from 'test_file.txt' + + manifest { + attributes 'Hello-World': 'test' + } +} + +remapSourcesJar { + from 'test_src_file.txt' +} diff --git a/src/test/resources/projects/remapJarContents/gradle.properties b/src/test/resources/projects/remapJarContents/gradle.properties new file mode 100644 index 00000000..845c3560 --- /dev/null +++ b/src/test/resources/projects/remapJarContents/gradle.properties @@ -0,0 +1,16 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G + +# Fabric Properties + # check these on https://fabricmc.net/use + minecraft_version=1.16.5 + yarn_mappings=1.16.5+build.5 + loader_version=0.11.2 + +# Mod Properties + maven_group = com.example + archives_base_name = fabric-example-mod + +# Dependencies + # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api + fabric_version=0.31.0+1.16 diff --git a/src/test/resources/projects/remapJarContents/settings.gradle b/src/test/resources/projects/remapJarContents/settings.gradle new file mode 100644 index 00000000..c162c363 --- /dev/null +++ b/src/test/resources/projects/remapJarContents/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = "fabric-example-mod" + diff --git a/src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/ExampleMod.java b/src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/ExampleMod.java new file mode 100644 index 00000000..bdbfb83a --- /dev/null +++ b/src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/ExampleMod.java @@ -0,0 +1,21 @@ +package net.fabricmc.example; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.fabricmc.api.ModInitializer; + +public class ExampleMod implements ModInitializer { + public static final Logger LOGGER = LogManager.getLogger("modid"); + + /** + * @see net.fabricmc.example + */ + @Override + public void onInitialize() { + LOGGER.info("Hello simple Fabric mod!"); + LOGGER.info("Hello World!"); + + net.minecraft.util.Identifier id = null; + } +} diff --git a/src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java b/src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java new file mode 100644 index 00000000..83ee1a89 --- /dev/null +++ b/src/test/resources/projects/remapJarContents/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java @@ -0,0 +1,15 @@ +package net.fabricmc.example.mixin; + +import net.minecraft.client.gui.screen.TitleScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TitleScreen.class) +public class ExampleMixin { + @Inject(at = @At("HEAD"), method = "init()V") + private void init(CallbackInfo info) { + System.out.println("This line is printed by an example mod mixin!"); + } +} diff --git a/src/test/resources/projects/remapJarContents/src/main/resources/fabric.mod.json b/src/test/resources/projects/remapJarContents/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..14ba01fd --- /dev/null +++ b/src/test/resources/projects/remapJarContents/src/main/resources/fabric.mod.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "id": "modid", + "version": "1.0.0", + + "name": "Example Mod", + "description": "This is an example description! Tell everyone what your mod is about!", + "authors": [ + "Me!" + ], + "contact": { + "homepage": "https://fabricmc.net/", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + + "license": "CC0-1.0", + + "environment": "*", + "entrypoints": { + "main": [ + "net.fabricmc.example.ExampleMod" + ] + }, + "mixins": [ + "modid.mixins.json" + ], + + "depends": { + "fabricloader": ">=0.7.4", + "fabric": "*", + "minecraft": "1.16.x" + }, + "suggests": { + "another-mod": "*" + } +} diff --git a/src/test/resources/projects/remapJarContents/src/main/resources/modid.mixins.json b/src/test/resources/projects/remapJarContents/src/main/resources/modid.mixins.json new file mode 100644 index 00000000..21fe73a4 --- /dev/null +++ b/src/test/resources/projects/remapJarContents/src/main/resources/modid.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.fabricmc.example.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + ], + "client": [ + "ExampleMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/test/resources/projects/remapJarContents/test_file.txt b/src/test/resources/projects/remapJarContents/test_file.txt new file mode 100644 index 00000000..40e81bd8 --- /dev/null +++ b/src/test/resources/projects/remapJarContents/test_file.txt @@ -0,0 +1 @@ +This file should end up inside the output file of remapJar. diff --git a/src/test/resources/projects/remapJarContents/test_src_file.txt b/src/test/resources/projects/remapJarContents/test_src_file.txt new file mode 100644 index 00000000..a97263ff --- /dev/null +++ b/src/test/resources/projects/remapJarContents/test_src_file.txt @@ -0,0 +1 @@ +This file should end up inside the output file of remapSourcesJar. From 577e5c8bfd4dd821d50fd277abc8b48d7441ffc0 Mon Sep 17 00:00:00 2001 From: modmuss Date: Thu, 30 Oct 2025 20:11:52 +0000 Subject: [PATCH 04/10] Add 'fabric.loom.disableObfuscation' property to disable all remapping. (#1409) * Add 'fabric.loom.disableObfuscation' property * More work, the test passes now. * Fix --- .../fabricmc/loom/LoomGradleExtension.java | 15 ++++-- .../configuration/CompileConfiguration.java | 34 ++++++------ .../configuration/LoomConfigurations.java | 16 +++--- .../configuration/LoomDependencyManager.java | 17 ++++-- .../decompile/DecompileConfiguration.java | 3 -- .../MinecraftJarProcessorManager.java | 10 +++- .../processors/SpecContextDebofImpl.java | 48 +++++++++++++++++ ...Impl.java => SpecContextRemappedImpl.java} | 8 +-- .../AbstractMappedMinecraftProvider.java | 28 +++++++--- .../mapped/IntermediaryMinecraftProvider.java | 4 ++ .../extension/LoomGradleExtensionApiImpl.java | 42 ++++++++++++++- .../extension/LoomGradleExtensionImpl.java | 45 ++++++++++++---- .../loom/task/RemapTaskConfiguration.java | 2 +- .../task/prod/AbstractProductionRunTask.java | 3 +- .../net/fabricmc/loom/util/Constants.java | 1 + .../test/integration/NotObfuscatedTest.groovy | 54 +++++++++++++++++++ .../loom/test/unit/SpecContextTest.groovy | 12 ++--- 17 files changed, 278 insertions(+), 64 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/configuration/processors/SpecContextDebofImpl.java rename src/main/java/net/fabricmc/loom/configuration/processors/{SpecContextImpl.java => SpecContextRemappedImpl.java} (97%) create mode 100644 src/test/groovy/net/fabricmc/loom/test/integration/NotObfuscatedTest.groovy diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 68474957..a7869ac4 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -37,7 +37,6 @@ import org.jetbrains.annotations.ApiStatus; import net.fabricmc.loom.api.LoomGradleExtensionAPI; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.InstallerData; -import net.fabricmc.loom.configuration.LoomDependencyManager; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; @@ -65,10 +64,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { InstallerData getInstallerData(); - void setDependencyManager(LoomDependencyManager dependencyManager); - - LoomDependencyManager getDependencyManager(); - MinecraftMetadataProvider getMetadataProvider(); void setMetadataProvider(MinecraftMetadataProvider metadataProvider); @@ -126,4 +121,14 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { * @return true when '--write-verification-metadata` is set */ boolean isCollectingDependencyVerificationMetadata(); + + /** + * When enabled do not remap the output jars. + */ + boolean dontRemapOutputs(); + + /** + * When enabled disable all forms of remapping. + */ + boolean disableObfuscation(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 249a4f6c..fe8a640a 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -51,6 +51,7 @@ import org.gradle.api.tasks.TaskContainer; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.api.tasks.javadoc.Javadoc; import org.gradle.api.tasks.testing.Test; +import org.jetbrains.annotations.Nullable; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.InterfaceInjectionExtensionAPI; @@ -120,9 +121,8 @@ public abstract class CompileConfiguration implements Runnable { setupMinecraft(configContext); } - LoomDependencyManager dependencyManager = new LoomDependencyManager(); - extension.setDependencyManager(dependencyManager); - dependencyManager.handleDependencies(getProject(), serviceFactory); + var dependencyManager = new LoomDependencyManager(getProject(), serviceFactory, extension); + dependencyManager.handleDependencies(); } catch (Exception e) { ExceptionUtil.processException(e, DaemonUtils.Context.fromProject(getProject())); disownLock(); @@ -173,20 +173,22 @@ public abstract class CompileConfiguration implements Runnable { extension.setMinecraftProvider(minecraftProvider); minecraftProvider.provide(); - // Realise the dependencies without actually resolving them, this forces any lazy providers to be created, populating the layered mapping factories. - project.getConfigurations().getByName(Configurations.MAPPINGS).getDependencies().toArray(); + if (!extension.disableObfuscation()) { + // Realise the dependencies without actually resolving them, this forces any lazy providers to be created, populating the layered mapping factories. + project.getConfigurations().getByName(Configurations.MAPPINGS).getDependencies().toArray(); - // Created any layered mapping files. - LayeredMappingsFactory.afterEvaluate(configContext); + // Created any layered mapping files. + LayeredMappingsFactory.afterEvaluate(configContext); - // Resolve the mapping files from the configuration - final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS); - final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceFactory(), mappingsDep, minecraftProvider); - extension.setMappingConfiguration(mappingConfiguration); - mappingConfiguration.applyToProject(getProject(), mappingsDep); + // Resolve the mapping files from the configuration + final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS); + final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceFactory(), mappingsDep, minecraftProvider); + extension.setMappingConfiguration(mappingConfiguration); + mappingConfiguration.applyToProject(getProject(), mappingsDep); + } // Provide the remapped mc jars - final IntermediaryMinecraftProvider intermediaryMinecraftProvider = jarConfiguration.createIntermediaryMinecraftProvider(project); + @Nullable IntermediaryMinecraftProvider intermediaryMinecraftProvider = extension.disableObfuscation() ? null : jarConfiguration.createIntermediaryMinecraftProvider(project); NamedMinecraftProvider namedMinecraftProvider = jarConfiguration.createNamedMinecraftProvider(project); registerGameProcessors(configContext); @@ -199,8 +201,10 @@ public abstract class CompileConfiguration implements Runnable { final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(true, extension.refreshDeps(), configContext); - extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider); - intermediaryMinecraftProvider.provide(provideContext); + if (intermediaryMinecraftProvider != null) { + extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider); + intermediaryMinecraftProvider.provide(provideContext); + } extension.setNamedMinecraftProvider(namedMinecraftProvider); namedMinecraftProvider.provide(provideContext); diff --git a/src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java b/src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java index 3586d4ce..fad2cb1a 100644 --- a/src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java +++ b/src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java @@ -134,17 +134,19 @@ public abstract class LoomConfigurations implements Runnable { extendsFrom(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, Constants.Configurations.MAPPING_CONSTANTS); - register(Constants.Configurations.MAPPINGS, Role.RESOLVABLE); - register(Constants.Configurations.MAPPINGS_FINAL, Role.RESOLVABLE); + if (!extension.disableObfuscation()) { + register(Constants.Configurations.MAPPINGS, Role.RESOLVABLE); + register(Constants.Configurations.MAPPINGS_FINAL, Role.RESOLVABLE); + extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL); + extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL); + + extension.createRemapConfigurations(SourceSetHelper.getMainSourceSet(getProject())); + } + register(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Role.RESOLVABLE); register(Constants.Configurations.LOCAL_RUNTIME, Role.RESOLVABLE); extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOCAL_RUNTIME); - extension.createRemapConfigurations(SourceSetHelper.getMainSourceSet(getProject())); - - extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL); - extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL); - extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES); // Add the dev time dependencies diff --git a/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java b/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java index 2728b235..17610851 100644 --- a/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java +++ b/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java @@ -31,9 +31,16 @@ import net.fabricmc.loom.configuration.mods.ModConfigurationRemapper; import net.fabricmc.loom.util.SourceRemapper; import net.fabricmc.loom.util.service.ServiceFactory; -public class LoomDependencyManager { - public void handleDependencies(Project project, ServiceFactory serviceFactory) { - project.getLogger().info(":setting up loom dependencies"); +public record LoomDependencyManager(Project project, ServiceFactory serviceFactory, LoomGradleExtension extension) { + public void handleDependencies() { + if (extension.disableObfuscation()) { + handleNonRemapDependencies(); + } else { + handleRemapDependencies(); + } + } + + private void handleRemapDependencies() { LoomGradleExtension extension = LoomGradleExtension.get(project); SourceRemapper sourceRemapper = new SourceRemapper(project, serviceFactory, true); @@ -47,4 +54,8 @@ public class LoomDependencyManager { project.getLogger().info("fabric-installer.json not found in dependencies"); } } + + private void handleNonRemapDependencies() { + // TODO debof - do we need to do anything? + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/decompile/DecompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/decompile/DecompileConfiguration.java index 4556a04e..c8af9a90 100644 --- a/src/main/java/net/fabricmc/loom/configuration/decompile/DecompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/decompile/DecompileConfiguration.java @@ -27,7 +27,6 @@ package net.fabricmc.loom.configuration.decompile; import org.gradle.api.Project; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider; @@ -37,13 +36,11 @@ public abstract class DecompileConfiguration protected final Project project; protected final T minecraftProvider; protected final LoomGradleExtension extension; - protected final MappingConfiguration mappingConfiguration; public DecompileConfiguration(Project project, T minecraftProvider) { this.project = project; this.minecraftProvider = minecraftProvider; this.extension = LoomGradleExtension.get(project); - this.mappingConfiguration = extension.getMappingConfiguration(); } public abstract String getTaskName(MinecraftJar.Type type); diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java b/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java index ec3eac67..408bb02c 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java @@ -66,7 +66,15 @@ public final class MinecraftJarProcessorManager { processors.add(project.getObjects().newInstance(LegacyJarProcessorWrapper.class, legacyProcessor)); } - return MinecraftJarProcessorManager.create(processors, SpecContextImpl.create(project)); + SpecContext specContext; + + if (extension.disableObfuscation()) { + specContext = SpecContextDebofImpl.create(); + } else { + specContext = SpecContextRemappedImpl.create(project); + } + + return MinecraftJarProcessorManager.create(processors, specContext); } @Nullable diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextDebofImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextDebofImpl.java new file mode 100644 index 00000000..dd2c8561 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextDebofImpl.java @@ -0,0 +1,48 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2025 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.processors; + +import java.util.List; + +import net.fabricmc.loom.api.processor.SpecContext; +import net.fabricmc.loom.util.fmj.FabricModJson; + +// TODO debof - fixme +public record SpecContextDebofImpl(List modDependencies, + List localMods) implements SpecContext { + public static SpecContext create() { + return new SpecContextDebofImpl(List.of(), List.of()); + } + + @Override + public List modDependenciesCompileRuntime() { + return List.of(); + } + + @Override + public List modDependenciesCompileRuntimeClient() { + return List.of(); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextRemappedImpl.java similarity index 97% rename from src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java rename to src/main/java/net/fabricmc/loom/configuration/processors/SpecContextRemappedImpl.java index 0585746c..e54d870c 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextRemappedImpl.java @@ -56,18 +56,18 @@ import net.fabricmc.loom.util.fmj.FabricModJsonHelpers; * @param localMods Mods found in the current project. * @param compileRuntimeMods Dependent mods found in both the compile and runtime classpath. */ -public record SpecContextImpl( +public record SpecContextRemappedImpl( List modDependencies, List localMods, List compileRuntimeMods) implements SpecContext { - public static SpecContextImpl create(Project project) { + public static SpecContextRemappedImpl create(Project project) { return create(new SpecContextProjectView.Impl(project, LoomGradleExtension.get(project))); } @VisibleForTesting - public static SpecContextImpl create(SpecContextProjectView projectView) { + public static SpecContextRemappedImpl create(SpecContextProjectView projectView) { AsyncCache> fmjCache = new AsyncCache<>(); - return new SpecContextImpl( + return new SpecContextRemappedImpl( getDependentMods(projectView, fmjCache), projectView.getMods(), getCompileRuntimeMods(projectView, fmjCache) diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java index 10fca71d..d11b8a29 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java @@ -173,15 +173,19 @@ public abstract class AbstractMappedMinecraftProvider extends AbstractMappedMinecraftProvider permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.LegacyMergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl { public IntermediaryMinecraftProvider(Project project, M minecraftProvider) { super(project, minecraftProvider); + + if (extension.disableObfuscation()) { + throw new UnsupportedOperationException("Intermediary Minecraft providers cannot be used when obfuscation is disabled"); + } } @Override diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index b7ccb43f..4ab91c17 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -238,6 +238,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public Dependency officialMojangMappings() { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot use Mojang mappings in a non-obfuscated environment"); + } + if (layeredSpecBuilderScope.get()) { throw new IllegalStateException("Use `officialMojangMappings()` when configuring layered mappings, not the extension method `loom.officialMojangMappings()`"); } @@ -247,6 +251,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public Dependency layered(Action action) { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot configure layered mappings in a non-obfuscated environment"); + } + if (hasEvaluatedLayeredMappings) { throw new IllegalStateException("Layered mappings have already been evaluated"); } @@ -294,6 +302,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public SetProperty getKnownIndyBsms() { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot configure known indyBsms in a non-obfuscated environment"); + } + return knownIndyBsms; } @@ -329,6 +341,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public IntermediateMappingsProvider getIntermediateMappingsProvider() { + if (LoomGradleExtension.get(getProject()).disableObfuscation()) { + throw new UnsupportedOperationException("Cannot get intermediate mappings provider in a non-obfuscated environment"); + } + return intermediateMappingsProvider.get(); } @@ -342,11 +358,15 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA T provider = getProject().getObjects().newInstance(clazz); configureIntermediateMappingsProviderInternal(provider); action.execute(provider); - intermediateMappingsProvider.set(provider); + setIntermediateMappingsProvider(provider); } @Override public File getMappingsFile() { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot get mappings file in a non-obfuscated environment"); + } + return LoomGradleExtension.get(getProject()).getMappingConfiguration().tinyMappings.toFile(); } @@ -421,11 +441,19 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public NamedDomainObjectList getRemapConfigurations() { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot get remap configurations in a non-obfuscated environment"); + } + return remapConfigurations; } @Override public RemapConfigurationSettings addRemapConfiguration(String name, Action action) { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot add remap configuration in a non-obfuscated environment"); + } + final RemapConfigurationSettings configurationSettings = getProject().getObjects().newInstance(RemapConfigurationSettings.class, name); // TODO remove in 2.0, this is a fallback to mimic the previous (Broken) behaviour @@ -440,11 +468,19 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public void createRemapConfigurations(SourceSet sourceSet) { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot create remap configurations in a non-obfuscated environment"); + } + RemapConfigurations.setupForSourceSet(getProject(), sourceSet); } @Override public void addRemapperExtension(Class> remapperExtensionClass, Class parametersClass, Action parameterAction) { + if (notObfuscated()) { + throw new UnsupportedOperationException("Cannot add remapper extension in a non-obfuscated environment"); + } + final ObjectFactory objectFactory = getProject().getObjects(); final RemapperExtensionHolder holder; @@ -472,6 +508,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA return jars; } + private boolean notObfuscated() { + return LoomGradleExtension.get(getProject()).disableObfuscation(); + } + // This is here to ensure that LoomGradleExtensionApiImpl compiles without any unimplemented methods private final class EnsureCompile extends LoomGradleExtensionApiImpl { private EnsureCompile() { diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 47ac3c3c..951f738a 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -39,6 +39,7 @@ import org.gradle.api.configuration.BuildFeatures; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider; @@ -55,8 +56,10 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager; import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider; +import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.download.Download; import net.fabricmc.loom.util.download.DownloadBuilder; +import net.fabricmc.loom.util.gradle.GradleUtils; public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implements LoomGradleExtension { private final Project project; @@ -78,6 +81,8 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl private final boolean configurationCacheActive; private final boolean isolatedProjectsActive; private final boolean isCollectingDependencyVerificationMetadata; + private final Property disableObfuscation; + private final Property dontRemap; @Inject protected abstract BuildFeatures getBuildFeatures(); @@ -108,6 +113,14 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl configurationCacheActive = getBuildFeatures().getConfigurationCache().getActive().get(); isolatedProjectsActive = getBuildFeatures().getIsolatedProjects().getActive().get(); isCollectingDependencyVerificationMetadata = !project.getGradle().getStartParameter().getWriteDependencyVerifications().isEmpty(); + disableObfuscation = project.getObjects().property(Boolean.class); + dontRemap = project.getObjects().property(Boolean.class); + + disableObfuscation.set(project.provider(() -> GradleUtils.getBooleanProperty(getProject(), Constants.Properties.DISABLE_OBFUSCATION))); + disableObfuscation.finalizeValueOnRead(); + + dontRemap.set(disableObfuscation.map(notObfuscated -> notObfuscated || GradleUtils.getBooleanProperty(getProject(), Constants.Properties.DONT_REMAP))); + dontRemap.finalizeValueOnRead(); if (refreshDeps) { project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower."); @@ -128,16 +141,6 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl return loomFiles; } - @Override - public void setDependencyManager(LoomDependencyManager dependencyManager) { - this.dependencyManager = dependencyManager; - } - - @Override - public LoomDependencyManager getDependencyManager() { - return Objects.requireNonNull(dependencyManager, "Cannot get LoomDependencyManager before it has been setup"); - } - @Override public MinecraftMetadataProvider getMetadataProvider() { return Objects.requireNonNull(metadataProvider, "Cannot get MinecraftMetadataProvider before it has been setup"); @@ -160,11 +163,19 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl @Override public MappingConfiguration getMappingConfiguration() { + if (disableObfuscation()) { + throw new UnsupportedOperationException("Cannot get mappings configuration in a non-obfuscated environment"); + } + return Objects.requireNonNull(mappingConfiguration, "Cannot get MappingsProvider before it has been setup"); } @Override public void setMappingConfiguration(MappingConfiguration mappingConfiguration) { + if (disableObfuscation()) { + throw new UnsupportedOperationException("Cannot set mappings configuration in a non-obfuscated environment"); + } + this.mappingConfiguration = mappingConfiguration; } @@ -278,6 +289,10 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl @Override public Collection getLayeredMappingFactories() { + if (disableObfuscation()) { + throw new UnsupportedOperationException("Cannot get layered mapping factories in a non-obfuscated environment"); + } + hasEvaluatedLayeredMappings = true; return Collections.unmodifiableCollection(layeredMappingsDependencyMap.values()); } @@ -308,4 +323,14 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl public boolean isCollectingDependencyVerificationMetadata() { return isCollectingDependencyVerificationMetadata; } + + @Override + public boolean dontRemapOutputs() { + return dontRemap.get(); + } + + @Override + public boolean disableObfuscation() { + return disableObfuscation.get(); + } } diff --git a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java index 0da6a9ed..8f6f4994 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java +++ b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java @@ -67,7 +67,7 @@ public abstract class RemapTaskConfiguration implements Runnable { SyncTaskBuildService.register(getProject()); - if (GradleUtils.getBooleanProperty(getProject(), Constants.Properties.DONT_REMAP)) { + if (extension.dontRemapOutputs()) { extension.getUnmappedModCollection().from(getTasks().getByName(JavaPlugin.JAR_TASK_NAME)); return; } diff --git a/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java b/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java index 55a28789..d1b3a546 100644 --- a/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java +++ b/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java @@ -61,7 +61,6 @@ import net.fabricmc.loom.configuration.InstallerData; import net.fabricmc.loom.task.AbstractLoomTask; import net.fabricmc.loom.task.RemapTaskConfiguration; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.gradle.GradleUtils; /** * This is the base task for running the game in a "production" like environment. Using intermediary names, and not enabling development only features. @@ -129,7 +128,7 @@ public abstract sealed class AbstractProductionRunTask extends AbstractLoomTask getJavaLauncher().convention(getJavaToolchainService().launcherFor(defaultToolchain)); getRunDir().convention(getProject().getLayout().getProjectDirectory().dir("run")); - if (!GradleUtils.getBooleanProperty(getProject(), Constants.Properties.DONT_REMAP)) { + if (!getExtension().dontRemapOutputs()) { getMods().from(getProject().getTasks().named(RemapTaskConfiguration.REMAP_JAR_TASK_NAME)); } diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index c051f3c1..8565c59f 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -142,6 +142,7 @@ public class Constants { public static final class Properties { public static final String DONT_REMAP = "fabric.loom.dontRemap"; + public static final String DISABLE_OBFUSCATION = "fabric.loom.disableObfuscation"; public static final String DISABLE_REMAPPED_VARIANTS = "fabric.loom.disableRemappedVariants"; public static final String DISABLE_PROJECT_DEPENDENT_MODS = "fabric.loom.disableProjectDependentMods"; public static final String LIBRARY_PROCESSORS = "fabric.loom.libraryProcessors"; diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/NotObfuscatedTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/NotObfuscatedTest.groovy new file mode 100644 index 00000000..51b2df48 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/NotObfuscatedTest.groovy @@ -0,0 +1,54 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2025 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.integration + +import spock.lang.Specification +import spock.lang.Unroll + +import net.fabricmc.loom.test.util.GradleProjectTestTrait + +import static net.fabricmc.loom.test.LoomTestConstants.PRE_RELEASE_GRADLE +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class NotObfuscatedTest extends Specification implements GradleProjectTestTrait { + @Unroll + def "Not Obfuscated"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE) + gradle.buildGradle << ''' + dependencies { + minecraft 'com.mojang:minecraft:1.21.10' + api "net.fabricmc.fabric-api:fabric-api:0.134.1+1.21.10" + } + ''' + gradle.getGradleProperties() << "fabric.loom.disableObfuscation=true" + + when: + def result = gradle.run(task: "build") + + then: + result.task(":build").outcome == SUCCESS + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/SpecContextTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/SpecContextTest.groovy index ac966241..aba0c357 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/SpecContextTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/SpecContextTest.groovy @@ -39,8 +39,8 @@ import spock.lang.TempDir import net.fabricmc.loom.LoomGradleExtension import net.fabricmc.loom.api.RemapConfigurationSettings import net.fabricmc.loom.api.fmj.FabricModJsonV1Spec -import net.fabricmc.loom.configuration.processors.SpecContextImpl import net.fabricmc.loom.configuration.processors.SpecContextProjectView +import net.fabricmc.loom.configuration.processors.SpecContextRemappedImpl import net.fabricmc.loom.test.util.GradleTestUtil import net.fabricmc.loom.util.ZipUtils import net.fabricmc.loom.util.fmj.gen.FabricModJsonV1Generator @@ -98,7 +98,7 @@ class SpecContextTest extends Specification { ) when: - def specContext = SpecContextImpl.create(projectView) + def specContext = SpecContextRemappedImpl.create(projectView) then: specContext.modDependencies().size() == 0 @@ -117,7 +117,7 @@ class SpecContextTest extends Specification { ) when: - def specContext = SpecContextImpl.create(projectView) + def specContext = SpecContextRemappedImpl.create(projectView) then: specContext.modDependencies().size() == 1 @@ -136,7 +136,7 @@ class SpecContextTest extends Specification { ) when: - def specContext = SpecContextImpl.create(projectView) + def specContext = SpecContextRemappedImpl.create(projectView) then: specContext.modDependencies().size() == 1 @@ -155,7 +155,7 @@ class SpecContextTest extends Specification { ) when: - def specContext = SpecContextImpl.create(projectView) + def specContext = SpecContextRemappedImpl.create(projectView) then: specContext.modDependencies().size() == 1 @@ -175,7 +175,7 @@ class SpecContextTest extends Specification { ) when: - def specContext = SpecContextImpl.create(projectView) + def specContext = SpecContextRemappedImpl.create(projectView) then: specContext.modDependencies().size() == 1 From f8a465377ca83941f51a71e70e50fec0041804b4 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:52:23 +0200 Subject: [PATCH 05/10] Fix using Enigma mappings with mod-provided javadoc (#1411) - Fixes using formats with inherently multiple namespaces by actually only checking for the presence of dst names instead of dst namespaces. - Fixes using formats without namespace ids by replacing the fallback namespaces with intermediary and named. --- .../processors/ModJavadocProcessor.java | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/ModJavadocProcessor.java b/src/main/java/net/fabricmc/loom/configuration/processors/ModJavadocProcessor.java index 2b74dfb2..2e9abbc3 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/ModJavadocProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/ModJavadocProcessor.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2022 FabricMC + * Copyright (c) 2022-2025 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import javax.inject.Inject; @@ -50,7 +51,12 @@ import net.fabricmc.loom.api.processor.SpecContext; import net.fabricmc.loom.util.Checksum; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.fmj.FabricModJson; +import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.MappingUtil; +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor; +import net.fabricmc.mappingio.adapter.MappingNsRenamer; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; @@ -127,7 +133,16 @@ public abstract class ModJavadocProcessor implements MinecraftJarProcessor fallbackNamespaceReplacements = Map.of( + MappingUtil.NS_SOURCE_FALLBACK, MappingsNamespace.INTERMEDIARY.toString(), + MappingUtil.NS_TARGET_FALLBACK, MappingsNamespace.NAMED.toString() + ); + final MappingNsRenamer renamer = new MappingNsRenamer(mappings, fallbackNamespaceReplacements); + final DstNameCheckingVisitor checker = new DstNameCheckingVisitor(modId, renamer); + MappingReader.read(reader, checker); } } catch (IOException e) { throw new UncheckedIOException("Failed to read javadoc from mod: " + modId, e); @@ -137,10 +152,6 @@ public abstract class ModJavadocProcessor implements MinecraftJarProcessor Date: Fri, 31 Oct 2025 13:16:27 +0000 Subject: [PATCH 06/10] Add mercury mixin to migrate mappings task. (#1413) --- build.gradle | 1 + gradle/libs.versions.toml | 2 ++ .../net/fabricmc/loom/task/service/MigrateMappingsService.java | 2 ++ 3 files changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 7f18b2b8..c4f76b13 100644 --- a/build.gradle +++ b/build.gradle @@ -132,6 +132,7 @@ dependencies { // source code remapping implementation libs.fabric.mercury + implementation libs.fabric.mercury.mixin implementation libs.fabric.unpick implementation libs.fabric.unpick.utils diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bc51d2a7..9d7ee039 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ clazz-tweaker = "0.1.1" mapping-io = "0.7.1" lorenz-tiny = "4.0.2" mercury = "0.4.2" +mercury-mixin = "0.1.0" loom-native = "0.2.0" unpick = "3.0.0-beta.9" @@ -34,6 +35,7 @@ fabric-clazz-tweaker = { module = "net.fabricmc:class-tweaker", version.ref = "c fabric-mapping-io = { module = "net.fabricmc:mapping-io", version.ref = "mapping-io" } fabric-lorenz-tiny = { module = "net.fabricmc:lorenz-tiny", version.ref = "lorenz-tiny" } fabric-mercury = { module = "net.fabricmc:mercury", version.ref = "mercury" } +fabric-mercury-mixin = { module = "net.fabricmc:mercurymixin", version.ref = "mercury-mixin" } fabric-loom-nativelib = { module = "net.fabricmc:fabric-loom-native", version.ref = "loom-native" } fabric-unpick = { module = "net.fabricmc.unpick:unpick", version.ref = "unpick" } fabric-unpick-utils = { module = "net.fabricmc.unpick:unpick-format-utils", version.ref = "unpick" } diff --git a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java index 152f364f..302e7219 100644 --- a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java +++ b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java @@ -32,6 +32,7 @@ import java.nio.file.Path; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.mercury.Mercury; +import org.cadixdev.mercury.mixin.MixinRemapper; import org.cadixdev.mercury.remapper.MercuryRemapper; import org.gradle.api.IllegalDependencyNotation; import org.gradle.api.JavaVersion; @@ -133,6 +134,7 @@ public class MigrateMappingsService extends Service Date: Fri, 31 Oct 2025 14:52:24 +0000 Subject: [PATCH 07/10] Fix ordering of mercury processors --- .../net/fabricmc/loom/task/service/MigrateMappingsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java index 302e7219..9adf1f9e 100644 --- a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java +++ b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java @@ -133,8 +133,8 @@ public class MigrateMappingsService extends Service Date: Fri, 31 Oct 2025 21:34:31 +0000 Subject: [PATCH 08/10] Add back getModSourceSets(), as its used by mc dev to do nothing. (#1415) --- src/main/java/net/fabricmc/loom/api/ModSettings.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/net/fabricmc/loom/api/ModSettings.java b/src/main/java/net/fabricmc/loom/api/ModSettings.java index b2e0b300..935b2723 100644 --- a/src/main/java/net/fabricmc/loom/api/ModSettings.java +++ b/src/main/java/net/fabricmc/loom/api/ModSettings.java @@ -181,4 +181,10 @@ public abstract class ModSettings implements Named { project.apply(Map.of("plugin", LoomCompanionGradlePlugin.NAME)); } + + // DO NOT USE THIS!!! + // Added back because the Minecraft dev plugin uses it. + @ApiStatus.Internal + @Deprecated(forRemoval = true) + public abstract ListProperty getModSourceSets(); } From 4fb75cf33613f27f4b213b0a72255d0c9848f280 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Fri, 31 Oct 2025 23:38:25 +0200 Subject: [PATCH 09/10] Include source mapping hash in decompiler cache key (#1414) * Include source mapping hash in decompiler cache key Fixes #1410. * Mark source mappings hash property as optional, improve name --- .../loom/task/GenerateSourcesTask.java | 9 ++++++- .../task/service/SourceMappingsService.java | 25 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index 1fc99793..d1565202 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2016-2022 FabricMC + * Copyright (c) 2016-2025 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -407,6 +407,13 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { sj.add(unpick.getUnpickCacheKey()); } + SourceMappingsService mappingsService = serviceFactory.get(getMappings()); + String mappingsHash = mappingsService.getProcessorHash(); + + if (mappingsHash != null) { + sj.add(mappingsHash); + } + getLogger().info("Decompile cache data: {}", sj); return Checksum.of(sj.toString()).sha256().hex(); diff --git a/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java index 5173169e..bb19944d 100644 --- a/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java +++ b/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2024 FabricMC + * Copyright (c) 2024-2025 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,8 +34,12 @@ import java.nio.file.Path; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Optional; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,17 +65,23 @@ public class SourceMappingsService extends Service getProcessorHash(); // the hash of the processors applied to the mappings } public static Provider create(Project project) { - final Path mappings = getMappings(project); + final Property hash = project.getObjects().property(String.class); + final Path mappings = getMappings(project, hash); return TYPE.create(project, options -> { options.getMappings().from(project.file(mappings)); + options.getProcessorHash().set(hash); }); } - private static Path getMappings(Project project) { + private static Path getMappings(Project project, Property hashProperty) { final LoomGradleExtension extension = LoomGradleExtension.get(project); final MinecraftJarProcessorManager jarProcessor = MinecraftJarProcessorManager.create(project); @@ -80,8 +90,11 @@ public class SourceMappingsService extends Service Date: Sat, 1 Nov 2025 08:25:46 +0000 Subject: [PATCH 10/10] Migrate mapping improvements. (#1416) * Migrate mapping improvements. * Revert to old logic * Fix * Add --overrideInputsIHaveABackup * Skip task when input is empty * Fix again * Update MM --- gradle/libs.versions.toml | 4 +- .../net/fabricmc/loom/task/LoomTasks.java | 21 ++++- .../loom/task/MigrateMappingsTask.java | 19 ++++ .../task/service/MigrateMappingsService.java | 15 +++- .../loom/util/gradle/SourceSetHelper.java | 14 +++ .../integration/MigrateMappingsTest.groovy | 87 +++++++++++++++++++ 6 files changed, 154 insertions(+), 6 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9d7ee039..4be88cdd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,8 +8,8 @@ tiny-remapper = "0.12.0" clazz-tweaker = "0.1.1" mapping-io = "0.7.1" lorenz-tiny = "4.0.2" -mercury = "0.4.2" -mercury-mixin = "0.1.0" +mercury = "0.4.3" +mercury-mixin = "0.2.1" loom-native = "0.2.0" unpick = "3.0.0-beta.9" diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 7bddb6a9..98cf79b2 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -49,6 +49,7 @@ import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.LoomVersions; import net.fabricmc.loom.util.Platform; import net.fabricmc.loom.util.gradle.GradleUtils; +import net.fabricmc.loom.util.gradle.SourceSetHelper; public abstract class LoomTasks implements Runnable { @Inject @@ -59,8 +60,24 @@ public abstract class LoomTasks implements Runnable { @Override public void run() { - getTasks().register("migrateMappings", MigrateMappingsTask.class, t -> { - t.setDescription("Migrates mappings to a new version."); + SourceSetHelper.getSourceSets(getProject()).all(sourceSet -> { + if (SourceSetHelper.isMainSourceSet(sourceSet)) { + getTasks().register("migrateMappings", MigrateMappingsTask.class, t -> { + t.setDescription("Migrates mappings to a new version."); + }); + + return; + } + + if (!SourceSetHelper.getFirstSrcDir(sourceSet).exists()) { + return; + } + + getTasks().register(sourceSet.getTaskName("migrate", "mappings"), MigrateMappingsTask.class, t -> { + t.setDescription("Migrates mappings to a new version."); + t.getInputDir().set(SourceSetHelper.getFirstSrcDir(sourceSet)); + t.getOutputDir().convention(getProject().getLayout().getProjectDirectory().dir(sourceSet.getTaskName("remapped", "src"))); + }); }); var generateLog4jConfig = getTasks().register("generateLog4jConfig", GenerateLog4jConfigTask.class, t -> { diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 0024570d..5c60d2ff 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -24,17 +24,22 @@ package net.fabricmc.loom.task; +import java.nio.file.Files; +import java.nio.file.Path; + import org.gradle.api.file.DirectoryProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.SkipWhenEmpty; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.UntrackedTask; import org.gradle.api.tasks.options.Option; import net.fabricmc.loom.task.service.MigrateMappingsService; +import net.fabricmc.loom.util.DeletingFileVisitor; import net.fabricmc.loom.util.service.ScopedServiceFactory; @UntrackedTask(because = "Always rerun this task.") @@ -44,6 +49,7 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask { public abstract Property getMappings(); @InputDirectory + @SkipWhenEmpty @Option(option = "input", description = "Java source file directory") public abstract DirectoryProperty getInputDir(); @@ -51,6 +57,10 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask { @Option(option = "output", description = "Remapped source output directory") public abstract DirectoryProperty getOutputDir(); + @Input + @Option(option = "overrideInputsIHaveABackup", description = "Override input files with the remapped files") + public abstract Property getOverrideInputs(); + @Nested protected abstract Property getMigrationServiceOptions(); @@ -58,6 +68,7 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask { getInputDir().convention(getProject().getLayout().getProjectDirectory().dir("src/main/java")); getOutputDir().convention(getProject().getLayout().getProjectDirectory().dir("remappedSrc")); getMigrationServiceOptions().set(MigrateMappingsService.createOptions(getProject(), getMappings(), getInputDir(), getOutputDir())); + getOverrideInputs().convention(false); } @TaskAction @@ -66,5 +77,13 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask { MigrateMappingsService service = serviceFactory.get(getMigrationServiceOptions().get()); service.migrateMapppings(); } + + if (getOverrideInputs().get()) { + Path inputPath = getInputDir().getAsFile().get().toPath(); + Path outputPath = getOutputDir().getAsFile().get().toPath(); + + DeletingFileVisitor.deleteDirectory(inputPath); + Files.move(outputPath, inputPath); + } } } diff --git a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java index 9adf1f9e..4ab5415f 100644 --- a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java +++ b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java @@ -58,6 +58,8 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.TinyMappingsService; +import net.fabricmc.loom.util.DeletingFileVisitor; +import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.service.Service; import net.fabricmc.loom.util.service.ServiceFactory; import net.fabricmc.loom.util.service.ServiceType; @@ -117,7 +119,10 @@ public class MigrateMappingsService extends Service iterator = sourceSet.getJava().getSrcDirs().iterator(); + + if (iterator.hasNext()) { + return iterator.next(); + } + + throw new IllegalStateException("SourceSet " + sourceSet.getName() + " has no source directories."); + } } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy index aab06c36..f784b012 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy @@ -157,4 +157,91 @@ class MigrateMappingsTest extends Specification implements GradleProjectTestTrai where: version << STANDARD_TEST_VERSIONS } + + @Unroll + def "Migrate client mappings (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + gradle.buildGradle << """ + loom { + splitEnvironmentSourceSets() + } + + dependencies { + minecraft 'com.mojang:minecraft:24w36a' + mappings 'net.fabricmc:yarn:24w36a+build.6:v2' + } + """.stripIndent() + + def sourceFile = new File(gradle.projectDir, "src/client/java/example/Test.java") + sourceFile.parentFile.mkdirs() + sourceFile.text = """ + package example; + + import net.minecraft.predicate.entity.InputPredicate; + + public class Test { + public static void main(String[] args) { + InputPredicate cls = null; + } + } + """ + + when: + def result = gradle.run(tasks: [ + "migrateClientMappings", + "--mappings", + "net.minecraft:mappings:24w36a" + ]) + def remapped = new File(gradle.projectDir, "remappedClientSrc/example/Test.java").text + + then: + result.task(":migrateClientMappings").outcome == SUCCESS + remapped.contains("import net.minecraft.advancements.critereon.InputPredicate;") + + where: + version << STANDARD_TEST_VERSIONS + } + + @Unroll + def "Override inputs (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + gradle.buildGradle << """ + dependencies { + minecraft 'com.mojang:minecraft:24w36a' + mappings 'net.fabricmc:yarn:24w36a+build.6:v2' + } + """.stripIndent() + + def sourceFile = new File(gradle.projectDir, "src/main/java/example/Test.java") + sourceFile.parentFile.mkdirs() + sourceFile.text = """ + package example; + + import net.minecraft.predicate.entity.InputPredicate; + + public class Test { + public static void main(String[] args) { + InputPredicate cls = null; + } + } + """ + + when: + def result = gradle.run(tasks: [ + "migrateMappings", + "--mappings", + "net.minecraft:mappings:24w36a", + "--overrideInputsIHaveABackup" + ]) + def remapped = new File(gradle.projectDir, "src/main/java/example/Test.java").text + + then: + result.task(":migrateMappings").outcome == SUCCESS + remapped.contains("import net.minecraft.advancements.critereon.InputPredicate;") + + where: + version << STANDARD_TEST_VERSIONS + } }