diff --git a/build.gradle b/build.gradle index 10f850a8..5c5b7a15 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { } group = "dev.architectury" -def baseVersion = '1.12' +def baseVersion = '1.13' def ENV = System.getenv() def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999" @@ -147,6 +147,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 392d0bda..32292d7e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,8 @@ tiny-remapper = "0.12.0" clazz-tweaker = "0.1.1" mapping-io = "0.7.1" lorenz-tiny = "4.0.2" -mercury = "0.1.4.17" +mercury = "0.4.3" +mercury-mixin = "0.2.1" loom-native = "0.2.0" unpick = "3.0.0-beta.9" @@ -44,6 +45,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 = "dev.architectury: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/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index fcc89378..510c8388 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -46,7 +46,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; @@ -77,10 +76,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { InstallerData getInstallerData(); - void setDependencyManager(LoomDependencyManager dependencyManager); - - LoomDependencyManager getDependencyManager(); - MinecraftMetadataProvider getMetadataProvider(); void setMetadataProvider(MinecraftMetadataProvider metadataProvider); @@ -158,6 +153,16 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { */ boolean isCollectingDependencyVerificationMetadata(); + /** + * When enabled do not remap the output jars. + */ + boolean dontRemapOutputs(); + + /** + * When enabled disable all forms of remapping. + */ + boolean disableObfuscation(); + // =================== // Architectury Loom // =================== diff --git a/src/main/java/net/fabricmc/loom/api/ModSettings.java b/src/main/java/net/fabricmc/loom/api/ModSettings.java index 927992eb..31cd98b2 100644 --- a/src/main/java/net/fabricmc/loom/api/ModSettings.java +++ b/src/main/java/net/fabricmc/loom/api/ModSettings.java @@ -197,4 +197,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(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 0618028a..b675346a 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -65,6 +65,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; @@ -137,9 +138,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(); @@ -222,29 +222,31 @@ 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); - // This needs to run after MinecraftProvider.initFiles and MinecraftLibraryProvider.provide - // but before MinecraftPatchedProvider.provide. - setupDependencyProviders(project, extension); + // This needs to run after MinecraftProvider.initFiles and MinecraftLibraryProvider.provide + // but before MinecraftPatchedProvider.provide. + setupDependencyProviders(project, extension); - // 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); + // 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); - if (extension.isForgeLike()) { - ForgeLibrariesProvider.provide(mappingConfiguration, project); - ((ForgeMinecraftProvider) minecraftProvider).getPatchedProvider().provide(); + if (extension.isForgeLike()) { + ForgeLibrariesProvider.provide(mappingConfiguration, project); + ((ForgeMinecraftProvider) minecraftProvider).getPatchedProvider().provide(); + } + + mappingConfiguration.setupPost(project); + mappingConfiguration.applyToProject(getProject(), mappingsDep); } - mappingConfiguration.setupPost(project); - mappingConfiguration.applyToProject(getProject(), mappingsDep); - if (extension.isForgeLike()) { extension.setForgeRunsProvider(ForgeRunsProvider.create(project)); } @@ -254,7 +256,7 @@ public abstract class CompileConfiguration implements Runnable { } // 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); @@ -267,8 +269,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 6eec2199..ed6f7018 100644 --- a/src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java +++ b/src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java @@ -135,17 +135,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 7c8051b9..a619f1b7 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); @@ -52,4 +59,8 @@ public class LoomDependencyManager { } } } + + 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/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 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 379b6c48..49f013d0 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 @@ -182,15 +182,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 33af3ae2..8beaeff3 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -285,6 +285,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()`"); } @@ -294,6 +298,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"); } @@ -341,6 +349,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; } @@ -376,6 +388,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(); } @@ -389,11 +405,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(); } @@ -468,11 +488,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 @@ -487,11 +515,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; @@ -519,6 +555,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA return jars; } + private boolean notObfuscated() { + return LoomGradleExtension.get(getProject()).disableObfuscation(); + } + @Override public void silentMojangMappingsLicense() { try { diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index d0312667..4a6b176c 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -42,6 +42,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.ForgeExtensionAPI; @@ -62,10 +63,12 @@ import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMi import net.fabricmc.loom.configuration.providers.minecraft.mapped.MojangMappedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider; +import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.Lazy; import net.fabricmc.loom.util.ModPlatform; 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; @@ -89,6 +92,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; // +-------------------+ // | Architectury Loom | @@ -129,6 +134,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."); @@ -149,16 +162,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"); @@ -181,11 +184,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; } @@ -320,6 +331,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()); } @@ -351,6 +366,16 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl return isCollectingDependencyVerificationMetadata; } + @Override + public boolean dontRemapOutputs() { + return dontRemap.get(); + } + + @Override + public boolean disableObfuscation() { + return disableObfuscation.get(); + } + @Override public ForgeExtensionAPI getForge() { ModPlatform.assertPlatform(this, ModPlatform.FORGE); diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java index c4bedbbd..1bc3eef5 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; @@ -64,6 +68,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; @@ -116,6 +121,7 @@ public abstract class AbstractRemapJarTask extends Jar { @Inject public AbstractRemapJarTask() { + from(getProject().zipTree(getInputFile())); getSourceNamespace().convention(MappingsNamespace.NAMED.toString()).finalizeValueOnRead(); getTargetNamespace().convention(getProject().provider(() -> IntermediaryNamespaces.runtimeIntermediary(getProject()))).finalizeValueOnRead(); getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead(); @@ -134,17 +140,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()); @@ -182,8 +182,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(); @@ -218,15 +217,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/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index e92e7a94..c8b3ef6e 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 @@ -422,6 +422,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/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/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 03a953d8..191e64ed 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 @@ -57,7 +57,6 @@ import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; 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; @@ -185,8 +184,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { getInjectedAccessWidenerPath().convention(LoomGradleExtension.get(getProject()).getAccessWidenerPath()); } - @TaskAction - public void run() { + @Override + protected void copy() { + super.copy(); + submitWork(RemapAction.class, params -> { if (getAddNestedDependencies().get()) { params.getNestedJars().from(getNestedJars()); @@ -246,14 +247,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()) @@ -306,20 +309,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/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java index 332691ae..4552d607 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java +++ b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java @@ -72,7 +72,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/task/service/MigrateMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java index 42215856..95398fdb 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; @@ -57,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; @@ -123,7 +126,10 @@ public class MigrateMappingsService 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 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 + } } 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/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/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 diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/fmj/FabricModJsonV1GeneratorTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/fmj/FabricModJsonV1GeneratorTest.groovy index 410b4e5a..e58d42d0 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/fmj/FabricModJsonV1GeneratorTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/fmj/FabricModJsonV1GeneratorTest.groovy @@ -399,7 +399,7 @@ class FabricModJsonV1GeneratorTest extends Specification { "id": "examplemod", "version": "1.0.0", "depends": { - "fabricloader": "fabricloader", + "fabricloader": "\\u003e\\u003d0.14.0", "fabric-api": [ "\\u003e\\u003d0.14.0", "\\u003c0.15.0" @@ -592,23 +592,23 @@ class FabricModJsonV1GeneratorTest extends Specification { ], "accessWidener": "mymod.accesswidener", "depends": { - "fabricloader": "fabricloader", + "fabricloader": "\\u003e\\u003d0.14.0", "fabric-api": [ "\\u003e\\u003d0.14.0", "\\u003c0.15.0" ] }, "recommends": { - "recommended-mod": "recommended-mod" + "recommended-mod": "\\u003e\\u003d1.0.0" }, "suggests": { - "suggested-mod": "suggested-mod" + "suggested-mod": "\\u003e\\u003d1.0.0" }, "conflicts": { - "conflicting-mod": "conflicting-mod" + "conflicting-mod": "\\u003c1.0.0" }, "breaks": { - "broken-mod": "broken-mod" + "broken-mod": "\\u003c1.0.0" }, "name": "Example Mod", "description": "This is an example mod.", 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.