diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index a1563c0b..bfbe3485 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -69,6 +69,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftPr import net.fabricmc.loom.configuration.sources.ForgeSourcesRemapper; import net.fabricmc.loom.extension.MixinExtension; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.OperatingSystem; public final class CompileConfiguration { @@ -98,7 +99,6 @@ public final class CompileConfiguration { configuration.extendsFrom(serverDeps.get()); configuration.setTransitive(false); }); - extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false)); extension.createLazyConfiguration(Constants.Configurations.LOADER_DEPENDENCIES, configuration -> configuration.setTransitive(false)); extension.createLazyConfiguration(Constants.Configurations.MINECRAFT, configuration -> configuration.setTransitive(false)); @@ -215,7 +215,7 @@ public final class CompileConfiguration { try { setupMinecraft(project); } catch (Exception e) { - throw new RuntimeException("Failed to setup minecraft", e); + throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to setup Minecraft", e); } LoomDependencyManager dependencyManager = new LoomDependencyManager(); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java index 260ec81f..b82ca2dc 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java @@ -29,10 +29,13 @@ import java.util.regex.Pattern; import org.gradle.api.Project; import org.gradle.api.artifacts.ExternalModuleDependency; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.api.tasks.TaskProvider; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomRepositoryPlugin; import net.fabricmc.loom.configuration.providers.BundleMetadata; +import net.fabricmc.loom.task.ExtractNativesTask; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.OperatingSystem; @@ -53,6 +56,18 @@ public class MinecraftLibraryProvider { project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION); } + if (versionInfo.hasNativesToExtract()) { + final TaskContainer tasks = project.getTasks(); + + extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false)); + + TaskProvider extractNativesTask = tasks.register("extractNatives", ExtractNativesTask.class, t -> { + t.setDescription("Extracts the minecraft platform specific natives."); + }); + + tasks.named("configureClientLaunch", configureClientLaunch -> configureClientLaunch.dependsOn(extractNativesTask)); + } + for (MinecraftVersionMeta.Library library : versionInfo.libraries()) { if (overrideLWJGL && library.name().startsWith("org.lwjgl")) { continue; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java index 26612d49..6e38296f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java @@ -56,6 +56,10 @@ public record MinecraftVersionMeta( return this.releaseTime().compareTo(releaseTime) >= 0; } + public boolean hasNativesToExtract() { + return libraries.stream().anyMatch(Library::hasNatives); + } + public record AssetIndex(String id, long totalSize, String path, String sha1, long size, String url) { public String fabricId(String version) { return id.equals(version) ? version : version + "-" + id; @@ -64,17 +68,20 @@ public record MinecraftVersionMeta( public record Library(Downloads downloads, String name, Map natives, List rules, Object extract) { public boolean isValidForOS() { - if (rules == null || rules.isEmpty()) { + if (rules == null) { + // No rules allow everything. return true; } - for (Rule rule : rules) { - if (rule.appliesToOS() && !rule.isAllowed()) { - return false; + boolean valid = false; + + for (Rule rule : this.rules) { + if (rule.appliesToOS()) { + valid = rule.isAllowed(); } } - return true; + return valid; } public boolean hasNatives() { diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index af9a16d3..ca37a3f7 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -54,9 +54,6 @@ public final class LoomTasks { RemapTaskConfiguration.setupRemap(project); - tasks.register("extractNatives", ExtractNativesTask.class, t -> { - t.setDescription("Extracts the minecraft platform specific natives."); - }); tasks.register("downloadAssets", DownloadAssetsTask.class, t -> { t.setDescription("Downloads required assets for Fabric."); }); @@ -80,7 +77,6 @@ public final class LoomTasks { }); tasks.register("configureClientLaunch", task -> { - task.dependsOn(tasks.named("extractNatives")); task.dependsOn(tasks.named("downloadAssets")); task.dependsOn(tasks.named("configureLaunch")); diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 4b615b5d..baa9573c 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -99,6 +99,7 @@ import net.fabricmc.loom.task.service.JarManifestService; import net.fabricmc.loom.task.service.MappingsService; import net.fabricmc.loom.task.service.TinyRemapperService; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.FileSystemUtil; import net.fabricmc.loom.util.LfWriter; import net.fabricmc.loom.util.ModPlatform; @@ -393,7 +394,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { LOGGER.error("Failed to delete output file", ex); } - throw new RuntimeException("Failed to remap", e); + throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to remap", e); } } diff --git a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java index f8e50cd8..0edf757c 100644 --- a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java +++ b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java @@ -50,8 +50,6 @@ import net.fabricmc.loom.util.gradle.SourceSetHelper; public abstract class GenerateDLIConfigTask extends AbstractLoomTask { @TaskAction public void run() throws IOException { - final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath(); - final MinecraftVersionMeta versionInfo = getExtension().getMinecraftProvider().getVersionInfo(); File assetsDirectory = new File(getExtension().getFiles().getUserCache(), "assets"); @@ -63,10 +61,15 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask { .property(!getExtension().isQuilt() ? "fabric.development" : "loader.development", "true") .property(!getExtension().isQuilt() ? "fabric.remapClasspathFile" : "loader.remapClasspathFile", getExtension().getFiles().getRemapClasspathFile().getAbsolutePath()) .property("log4j.configurationFile", getAllLog4JConfigFiles()) - .property("log4j2.formatMsgNoLookups", "true") + .property("log4j2.formatMsgNoLookups", "true"); - .property("client", "java.library.path", nativesPath) - .property("client", "org.lwjgl.librarypath", nativesPath); + if (versionInfo.hasNativesToExtract()) { + String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath(); + + launchConfig + .property("client", "java.library.path", nativesPath) + .property("client", "org.lwjgl.librarypath", nativesPath); + } if (!getExtension().isForge()) { launchConfig diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index 54b0b7ab..ce830912 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -70,6 +70,9 @@ public class Constants { public static final String MINECRAFT_SERVER_DEPENDENCIES = "minecraftServerLibraries"; public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; public static final String MINECRAFT_RUNTIME_DEPENDENCIES = "minecraftRuntimeOnlyLibraries"; + /** + * Not used on Minecraft 1.19-pre1 or later. Natives are all loaded from the classpath. + */ public static final String MINECRAFT_NATIVES = "minecraftNatives"; public static final String MAPPINGS = "mappings"; public static final String MAPPINGS_FINAL = "mappingsFinal"; diff --git a/src/main/java/net/fabricmc/loom/util/ExceptionUtil.java b/src/main/java/net/fabricmc/loom/util/ExceptionUtil.java new file mode 100644 index 00000000..3683301e --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/ExceptionUtil.java @@ -0,0 +1,47 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022 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.util; + +import java.util.function.BiFunction; + +public final class ExceptionUtil { + /** + * Creates a descriptive user-facing wrapper exception for an underlying cause. + * + *

The output format has a message like this: {@code [message], [cause class]: [cause message]}. + * For example: {@code Failed to remap, java.io.IOException: Access denied}. + * + * @param constructor the exception factory which takes in a message and a cause + * @param message the more general message for the resulting exception + * @param cause the causing exception + * @param the created exception type + * @param the cause type + * @return the created exception + */ + public static E createDescriptiveWrapper(BiFunction constructor, String message, C cause) { + String descriptiveMessage = "%s, %s: %s".formatted(message, cause.getClass().getName(), cause.getMessage()); + return constructor.apply(descriptiveMessage, cause); + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy index 76d5c438..a4e81f68 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy @@ -83,4 +83,34 @@ class NativesTest extends Specification implements GradleProjectTestTrait { where: version << STANDARD_TEST_VERSIONS } + + @RestoreSystemProperties + @Unroll + def "1.19 classpath natives (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + + gradle.buildGradle << ''' + loom { + noIntermediateMappings() + } + + dependencies { + minecraft "com.mojang:minecraft:1.19-pre1" + mappings loom.layered() { + // No names + } + } + ''' + + when: + // Run the task twice to ensure its up to date + def result = gradle.run(task: "build") + + then: + result.task(":build").outcome == SUCCESS + + where: + version << STANDARD_TEST_VERSIONS + } }