From 9e04ddb5d05370b4d76d73ca22b448cd9aaa4b65 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 21 Mar 2026 23:28:24 +0900 Subject: [PATCH] Implement non-deobf for NeoForge 26.1 (albeit ugly, will fix), add integration test for NF 26.1-snapshot-11 --- gradle/runtime.libs.versions.toml | 2 +- .../loom/forge/ForgeSourcesService.java | 44 ++++++++------ .../dependency/ForgeLibrariesProvider.java | 5 +- .../minecraft/MinecraftPatchedProvider.java | 50 ++++++++++++++-- .../loom/mcpconfig/McpConfigData.java | 11 +++- .../loom/mcpconfig/McpConfigFunction.java | 17 +++++- .../loom/mcpconfig/McpConfigProvider.java | 8 +++ .../loom/mcpconfig/McpExecutor.java | 7 +++ .../loom/mcpconfig/McpExecutorBuilder.java | 15 ++++- .../fabricmc/loom/LoomGradleExtension.java | 4 ++ .../configuration/CompileConfiguration.java | 21 +++++-- .../neoforge/NeoForge261Test.groovy | 58 +++++++++++++++++++ .../projects/neoforge/261/build.gradle | 50 ++++++++++++++++ .../projects/neoforge/261/gradle.properties | 10 ++++ .../projects/neoforge/261/settings.gradle | 1 + 15 files changed, 263 insertions(+), 40 deletions(-) create mode 100644 src/test/groovy/net/fabricmc/loom/test/integration/neoforge/NeoForge261Test.groovy create mode 100644 src/test/resources/projects/neoforge/261/build.gradle create mode 100644 src/test/resources/projects/neoforge/261/gradle.properties create mode 100644 src/test/resources/projects/neoforge/261/settings.gradle diff --git a/gradle/runtime.libs.versions.toml b/gradle/runtime.libs.versions.toml index 8e1814be..a0cccc5d 100644 --- a/gradle/runtime.libs.versions.toml +++ b/gradle/runtime.libs.versions.toml @@ -23,7 +23,7 @@ access-transformers = "3.0.1" access-transformers-new = "8.0.5" access-transformers-neo = "10.0.2" unprotect = "2.0.2" -asm = "9.7" +asm = "9.9.1" access-transformers-log4j = "2.17.1" forge-installer-tools = "1.2.0" neoforge-installer-tools = "4.0.6" diff --git a/src/main/java/dev/architectury/loom/forge/ForgeSourcesService.java b/src/main/java/dev/architectury/loom/forge/ForgeSourcesService.java index d1c50489..79bc4e34 100644 --- a/src/main/java/dev/architectury/loom/forge/ForgeSourcesService.java +++ b/src/main/java/dev/architectury/loom/forge/ForgeSourcesService.java @@ -29,6 +29,7 @@ import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; import org.jspecify.annotations.Nullable; import net.fabricmc.loom.LoomGradleExtension; @@ -55,6 +56,7 @@ public final class ForgeSourcesService extends Service getSourceRemapperService(); @@ -74,25 +76,27 @@ public final class ForgeSourcesService extends Service { - final MappingsNamespace sourceNamespace = IntermediaryNamespaces.intermediaryNamespace(project); - final String targetNamespace = MappingsNamespace.NAMED.toString(); + if (!extension.isUnobfuscatedForge()) { + options.getSourceRemapperService().set(SourceRemapperService.TYPE.create(project, sro -> { + final MappingsNamespace sourceNamespace = IntermediaryNamespaces.intermediaryNamespace(project); + final String targetNamespace = MappingsNamespace.NAMED.toString(); - sro.getMappings().set(MappingsService.createOptionsWithProjectMappings( - project, - project.provider(sourceNamespace::toString), - project.provider(() -> targetNamespace) - )); - sro.getJavaCompileRelease().set(SourceRemapperService.getJavaCompileRelease(project)); - sro.getClasspath().from(DependencyDownloader.download(project, LoomVersions.JETBRAINS_ANNOTATIONS.mavenNotation())); - sro.getClasspath().from(extension.getMinecraftJars(sourceNamespace)); - sro.getClasspath().from(project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES)); + sro.getMappings().set(MappingsService.createOptionsWithProjectMappings( + project, + project.provider(sourceNamespace::toString), + project.provider(() -> targetNamespace) + )); + sro.getJavaCompileRelease().set(SourceRemapperService.getJavaCompileRelease(project)); + sro.getClasspath().from(DependencyDownloader.download(project, LoomVersions.JETBRAINS_ANNOTATIONS.mavenNotation())); + sro.getClasspath().from(extension.getMinecraftJars(sourceNamespace)); + sro.getClasspath().from(project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES)); - TinyRemapperHelper.JSR_TO_JETBRAINS.forEach((from, to) -> { - Pair mapping = new Pair<>(from, to); - sro.getAdditionalClassMappings().add(mapping); - }); - })); + TinyRemapperHelper.JSR_TO_JETBRAINS.forEach((from, to) -> { + Pair mapping = new Pair<>(from, to); + sro.getAdditionalClassMappings().add(mapping); + }); + })); + } options.getShouldShowVerboseStderr().set(ForgeToolExecutor.shouldShowVerboseStderr(project)); @@ -174,8 +178,10 @@ public final class ForgeSourcesService extends Service dependencies = new ArrayList<>(); @@ -145,7 +146,7 @@ public class ForgeLibrariesProvider { isFancyModLoader10OrNewer = true; } - if (isFML || isFancyML) { + if ((isFML || isFancyML) && mappingConfiguration != null) { // If FML, remap it. try (var serviceFactory = new ScopedServiceFactory()) { if (isFML) { diff --git a/src/main/java/dev/architectury/loom/forge/minecraft/MinecraftPatchedProvider.java b/src/main/java/dev/architectury/loom/forge/minecraft/MinecraftPatchedProvider.java index db960003..1c4cd649 100644 --- a/src/main/java/dev/architectury/loom/forge/minecraft/MinecraftPatchedProvider.java +++ b/src/main/java/dev/architectury/loom/forge/minecraft/MinecraftPatchedProvider.java @@ -157,7 +157,9 @@ public class MinecraftPatchedProvider { minecraftProvider.setJarPrefix(patchId); - final String intermediateId = getExtension().isNeoForge() ? "mojang" : "srg"; + final String intermediateId = getExtension().isNeoForge() + ? (getExtension().isUnobfuscatedForge() ? "official" : "mojang") + : "srg"; minecraftIntermediateJar = forgeWorkingDir.resolve("minecraft-" + type.id + "-" + intermediateId + ".jar"); minecraftPatchedIntermediateJar = forgeWorkingDir.resolve("minecraft-" + type.id + "-" + intermediateId + "-patched.jar"); minecraftPatchedIntermediateAtJar = forgeWorkingDir.resolve("minecraft-" + type.id + "-" + intermediateId + "-at-patched.jar"); @@ -231,14 +233,40 @@ public class MinecraftPatchedProvider { public void remapJar(ServiceFactory serviceFactory) throws Exception { if (dirty) { - remapPatchedJar(serviceFactory); + if (getExtension().isUnobfuscatedForge()) { + mergeUnobfuscatedPatchedJar(); + } else { + remapPatchedJar(serviceFactory); + } + fillClientExtraJar(serviceFactory); } + if (getExtension().isUnobfuscatedForge()) { + DependencyProvider.addDependency(project, getForgeJar(), Constants.Configurations.FORGE_EXTRA); + } + DependencyProvider.addDependency(project, minecraftClientExtra, Constants.Configurations.FORGE_EXTRA); } + private void mergeUnobfuscatedPatchedJar() throws IOException { + logger.lifecycle(":merging userdev into minecraft"); + Path mcOutput = minecraftPatchedJar; + Path forgeUserdevJar = getForgeUserdevJar().toPath(); + + Files.deleteIfExists(mcOutput); + Files.copy(minecraftPatchedIntermediateAtJar, mcOutput); + + copyUserdevFiles(forgeUserdevJar, mcOutput); + applyLoomPatchVersion(mcOutput); + } + private void createPrePatchJar() throws IOException { + if (getExtension().isUnobfuscatedForge()) { + createUnobfuscatedPrePatchJar(); + return; + } + if (shouldUseNeoForgeInstallerToolsToCreatePrePatchJar()) { createNeoForgeInstallerToolsPrePatchJar(); return; @@ -253,6 +281,16 @@ public class MinecraftPatchedProvider { } } + private void createUnobfuscatedPrePatchJar() throws IOException { + try (var tempFiles = new TempFiles(); var serviceFactory = new ScopedServiceFactory()) { + McpExecutorBuilder builder = createMcpExecutor(tempFiles.directory("loom-mcp")); + builder.enqueue("preProcessJar"); + McpExecutor executor = serviceFactory.get(builder.build()); + Path output = executor.execute(); + Files.copy(output, minecraftIntermediateJar, StandardCopyOption.REPLACE_EXISTING); + } + } + private void createNeoForgeInstallerToolsPrePatchJar() throws IOException { try (var tempFiles = new TempFiles()) { final Path mappings = tempFiles.file("mappings", ".txt"); @@ -300,7 +338,11 @@ public class MinecraftPatchedProvider { // The manifest includes a Minecraft-Dists attribute that specifies the dists in the current dev env, // as well as Minecraft-Dist attributes on every dist-only file. private void generateNeoForgeDistManifest(ServiceFactory serviceFactory, Path manifestPath) throws IOException { - MemoryMappingTree mappings = getMappingTree(serviceFactory); + // For unobfuscated NeoForge the classes are already in official namespace; an empty tree is safe + // because SidedJarIndexGenerator falls back to the original name when no mapping is found. + MemoryMappingTree mappings = getExtension().isUnobfuscatedForge() + ? new MemoryMappingTree() + : getMappingTree(serviceFactory); Manifest manifest = new Manifest(); manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); @@ -527,7 +569,7 @@ public class MinecraftPatchedProvider { copyMissingClasses(minecraftIntermediateJar, minecraftPatchedIntermediateJar); deleteParameterNames(minecraftPatchedIntermediateJar); - if (getExtension().isForgeLikeAndNotOfficial()) { + if (getExtension().isForgeLikeAndNotOfficial() && !getExtension().isUnobfuscatedForge()) { fixParameterAnnotation(minecraftPatchedIntermediateJar); } diff --git a/src/main/java/dev/architectury/loom/mcpconfig/McpConfigData.java b/src/main/java/dev/architectury/loom/mcpconfig/McpConfigData.java index 4ba0a356..89f299c9 100644 --- a/src/main/java/dev/architectury/loom/mcpconfig/McpConfigData.java +++ b/src/main/java/dev/architectury/loom/mcpconfig/McpConfigData.java @@ -31,13 +31,14 @@ import java.util.Map; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import org.jspecify.annotations.Nullable; /** * Data extracted from the MCPConfig JSON file. * * @param version the Minecraft version - the value of the {@code version} property * @param data the value of the {@code data} property - * @param mappingsPath the path to srg mappings inside the MCP zip + * @param mappingsPath the path to srg mappings inside the MCP zip, or {@code null} if absent (spec 6+) * @param official the value of the {@code official} property * @param steps the MCP step definitions by environment type * @param functions the MCP function definitions by name @@ -45,15 +46,19 @@ import com.google.gson.JsonObject; public record McpConfigData( String version, JsonObject data, - String mappingsPath, + @Nullable String mappingsPath, boolean official, Map> steps, Map functions ) { + public boolean hasMappings() { + return mappingsPath != null; + } + public static McpConfigData fromJson(JsonObject json) { String version = json.get("version").getAsString(); JsonObject data = json.getAsJsonObject("data"); - String mappingsPath = data.get("mappings").getAsString(); + @Nullable String mappingsPath = data.has("mappings") ? data.get("mappings").getAsString() : null; boolean official = json.has("official") && json.getAsJsonPrimitive("official").getAsBoolean(); JsonObject stepsJson = json.getAsJsonObject("steps"); diff --git a/src/main/java/dev/architectury/loom/mcpconfig/McpConfigFunction.java b/src/main/java/dev/architectury/loom/mcpconfig/McpConfigFunction.java index b5bd30be..aba9a72a 100644 --- a/src/main/java/dev/architectury/loom/mcpconfig/McpConfigFunction.java +++ b/src/main/java/dev/architectury/loom/mcpconfig/McpConfigFunction.java @@ -47,6 +47,7 @@ import org.jspecify.annotations.Nullable; */ public record McpConfigFunction(String version, List args, List jvmArgs, @Nullable String repo) implements Serializable { private static final String VERSION_KEY = "version"; + private static final String CLASSPATH_KEY = "classpath"; private static final String ARGS_KEY = "args"; private static final String JVM_ARGS_KEY = "jvmargs"; private static final String REPO_KEY = "repo"; @@ -82,11 +83,21 @@ public record McpConfigFunction(String version, List args, List args = json.has(ARGS_KEY) ? configValuesFromJson(json.getAsJsonArray(ARGS_KEY)) : List.of(); List jvmArgs = json.has(JVM_ARGS_KEY) ? configValuesFromJson(json.getAsJsonArray(JVM_ARGS_KEY)) : List.of(); - JsonElement repoJson = json.get(REPO_KEY); - @Nullable String repo = repoJson.isJsonPrimitive() ? repoJson.getAsString() : null; + @Nullable JsonElement repoJson = json.get(REPO_KEY); + @Nullable String repo = repoJson != null && repoJson.isJsonPrimitive() ? repoJson.getAsString() : null; return new McpConfigFunction(version, args, jvmArgs, repo); } diff --git a/src/main/java/dev/architectury/loom/mcpconfig/McpConfigProvider.java b/src/main/java/dev/architectury/loom/mcpconfig/McpConfigProvider.java index 9b60b4a9..074f4c45 100644 --- a/src/main/java/dev/architectury/loom/mcpconfig/McpConfigProvider.java +++ b/src/main/java/dev/architectury/loom/mcpconfig/McpConfigProvider.java @@ -84,7 +84,15 @@ public class McpConfigProvider extends DependencyProvider { configJson = unpacked.resolve("config.json"); } + public boolean hasMappings() { + return data.hasMappings(); + } + public Path getMappings() { + if (!hasMappings()) { + throw new UnsupportedOperationException("MCP config has no mappings (spec 6+ unobfuscated)"); + } + return unpacked.resolve(getMappingsPath()); } diff --git a/src/main/java/dev/architectury/loom/mcpconfig/McpExecutor.java b/src/main/java/dev/architectury/loom/mcpconfig/McpExecutor.java index f2d756a8..edd8afba 100644 --- a/src/main/java/dev/architectury/loom/mcpconfig/McpExecutor.java +++ b/src/main/java/dev/architectury/loom/mcpconfig/McpExecutor.java @@ -51,6 +51,7 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; import org.jspecify.annotations.Nullable; import net.fabricmc.loom.util.download.Download; @@ -90,7 +91,9 @@ public final class McpExecutor extends Service { /** * Mappings extracted from {@code data.mappings} in the MCPConfig JSON. + * Optional for spec 6+ where mappings are absent. */ + @Optional @InputFile RegularFileProperty getMappings(); @@ -217,6 +220,10 @@ public final class McpExecutor extends Service { @Override public Path mappings() { + if (!getOptions().getMappings().isPresent()) { + throw new UnsupportedOperationException("Mappings are not available (spec 6+ unobfuscated)"); + } + return getOptions().getMappings().get().getAsFile().toPath(); } diff --git a/src/main/java/dev/architectury/loom/mcpconfig/McpExecutorBuilder.java b/src/main/java/dev/architectury/loom/mcpconfig/McpExecutorBuilder.java index 28d153a1..490ff08f 100644 --- a/src/main/java/dev/architectury/loom/mcpconfig/McpExecutorBuilder.java +++ b/src/main/java/dev/architectury/loom/mcpconfig/McpExecutorBuilder.java @@ -36,6 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Set; import java.util.SortedSet; @@ -194,7 +195,11 @@ public final class McpExecutorBuilder { } options.getStepsToExecute().set(toExecute); - options.getMappings().set(extension.getMcpConfigProvider().getMappings().toFile()); + + if (extension.getMcpConfigProvider().hasMappings()) { + options.getMappings().set(extension.getMcpConfigProvider().getMappings().toFile()); + } + options.getInitialConfig().set(config); options.getOffline().set(project.getGradle().getStartParameter().isOffline()); options.getManualRefreshDeps().set(extension.manualRefreshDeps()); @@ -228,8 +233,12 @@ public final class McpExecutorBuilder { case "downloadServer" -> ConstantLogic.createOptions(setupContext, () -> minecraftProvider.getMinecraftServerJar().toPath()); case "strip" -> StripLogic.createOptions(setupContext); case "listLibraries" -> ListLibrariesLogic.createOptions(setupContext); - case "downloadClientMappings" -> DownloadManifestFileLogic.createOptions(setupContext, minecraftProvider.getVersionInfo().download("client_mappings")); - case "downloadServerMappings" -> DownloadManifestFileLogic.createOptions(setupContext, minecraftProvider.getVersionInfo().download("server_mappings")); + case "downloadClientMappings" -> DownloadManifestFileLogic.createOptions(setupContext, + Objects.requireNonNull(minecraftProvider.getVersionInfo().download("client_mappings"), + "client_mappings download is not available for this Minecraft version")); + case "downloadServerMappings" -> DownloadManifestFileLogic.createOptions(setupContext, + Objects.requireNonNull(minecraftProvider.getVersionInfo().download("server_mappings"), + "server_mappings download is not available for this Minecraft version")); case "inject" -> InjectLogic.createOptions(setupContext); case "patch" -> PatchLogic.createOptions(setupContext); default -> { diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 2676806d..fd6d6bc3 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -188,6 +188,10 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { return isForgeLike() && !getMcpConfigProvider().isOfficial(); } + default boolean isUnobfuscatedForge() { + return isForgeLike() && getProductionNamespace().get().equals(MappingsNamespace.OFFICIAL.toString()); + } + DependencyProviders getDependencyProviders(); void setDependencyProviders(DependencyProviders dependencyProviders); diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 71bfe2ef..f8c277c2 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -242,9 +242,15 @@ public abstract class CompileConfiguration implements Runnable { throw new UnsupportedOperationException("Using %s with split jars is not supported!".formatted(extension.getPlatform().get().displayName())); } - if (extension.isForgeLike() && extension.disableObfuscation()) { - // TODO: Allow setting up Forge and NeoForge without obfuscation - throw new UnsupportedOperationException("Using %s without obfuscation is not supported!".formatted(extension.getPlatform().get().displayName())); + // TODO: Re-evaluate if isUnobfuscatedForge() should even exist, or if the checks below should be removed + if (extension.isForgeLike() && extension.disableObfuscation() && !extension.isUnobfuscatedForge()) { + throw new UnsupportedOperationException(("Architectury Loom: The dev.architectury.loom-no-remap plugin was applied, but the Minecraft version '%s' is obfuscated. " + + "Forge / NeoForge support for obfuscated Minecraft is through the regular dev.architectury.loom plugin instead.").formatted(metadataProvider.getMinecraftVersion())); + } + + if (extension.isForgeLike() && !extension.disableObfuscation() && extension.isUnobfuscatedForge()) { + throw new UnsupportedOperationException(("Architectury Loom: The Minecraft version '%s' is unobfuscated (no mappings). " + + "Forge / NeoForge support for unobfuscated Minecraft is through the dev.architectury.loom-no-remap plugin instead.").formatted(metadataProvider.getMinecraftVersion())); } extension.setMinecraftProvider(minecraftProvider); @@ -273,9 +279,14 @@ public abstract class CompileConfiguration implements Runnable { mappingConfiguration.setupPost(project); mappingConfiguration.applyToProject(getProject(), mappingsDep); + } else if (extension.isUnobfuscatedForge()) { + // Unobfuscated NeoForge: run the forge patch pipeline without requiring user-provided mappings. + setupDependencyProviders(project, extension); + ForgeLibrariesProvider.provide(null, project); + ((ForgeMinecraftProvider) minecraftProvider).getPatchedProvider().provide(); } - if (extension.isForgeLike() && extension.getForgeProvider().usesMojangAtRuntime()) { + if (extension.isForgeLike() && extension.getForgeProvider().usesMojangAtRuntime() && !extension.isUnobfuscatedForge()) { extension.getRuntimeIntermediaryNamespace().set(MappingsNamespace.MOJANG.toString()); } @@ -315,7 +326,7 @@ public abstract class CompileConfiguration implements Runnable { srgMinecraftProvider.provide(provideContext); } - if (extension.isForgeLike() && extension.getForgeProvider().usesMojangAtRuntime()) { + if (extension.isForgeLike() && extension.getForgeProvider().usesMojangAtRuntime() && !extension.isUnobfuscatedForge()) { final MojangMappedMinecraftProvider mojangMappedMinecraftProvider = jarConfiguration.createMojangMappedMinecraftProvider(project); extension.setMojangMappedMinecraftProvider(mojangMappedMinecraftProvider); mojangMappedMinecraftProvider.provide(provideContext); diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/neoforge/NeoForge261Test.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/neoforge/NeoForge261Test.groovy new file mode 100644 index 00000000..371f126b --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/neoforge/NeoForge261Test.groovy @@ -0,0 +1,58 @@ +/* + * 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.neoforge + +import spock.lang.Specification +import spock.lang.Unroll + +import net.fabricmc.loom.test.util.GradleProjectTestTrait + +import static net.fabricmc.loom.test.LoomTestConstants.DEFAULT_GRADLE +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class NeoForge261Test extends Specification implements GradleProjectTestTrait { + @Unroll + def "build #mcVersion #neoforgeVersion"() { + if (Integer.valueOf(System.getProperty("java.version").split("\\.")[0]) < 21) { + println("This test requires Java 21. Currently you have Java ${System.getProperty("java.version")}.") + return + } + + setup: + def gradle = gradleProject(project: "neoforge/261", version: DEFAULT_GRADLE) + gradle.buildGradle.text = gradle.buildGradle.text.replace('@MCVERSION@', mcVersion) + .replace('@NEOFORGEVERSION@', neoforgeVersion) + + when: + def result = gradle.run(task: "build") + + then: + result.task(":build").outcome == SUCCESS + + where: + mcVersion | neoforgeVersion + '26.1-snapshot-11' | '26.1.0.0-alpha.14+snapshot-11' + } +} diff --git a/src/test/resources/projects/neoforge/261/build.gradle b/src/test/resources/projects/neoforge/261/build.gradle new file mode 100644 index 00000000..2f04977f --- /dev/null +++ b/src/test/resources/projects/neoforge/261/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'dev.architectury.loom-no-remap' + id 'maven-publish' +} + +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +base { + archivesName = project.archives_base_name +} + +version = project.mod_version +group = project.maven_group + +def mcVersion = "@MCVERSION@" +def neoforgeVersion = "@NEOFORGEVERSION@" + +repositories { + maven { url = "https://maven.neoforged.net/releases/" } +} + +dependencies { + minecraft "com.mojang:minecraft:$mcVersion" + neoForge "net.neoforged:neoforge:$neoforgeVersion" +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 21 +} + +java { + withSourcesJar() +} + +jar { + from("LICENSE") { + rename { "${it}_${project.archivesBaseName}"} + } +} + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } +} diff --git a/src/test/resources/projects/neoforge/261/gradle.properties b/src/test/resources/projects/neoforge/261/gradle.properties new file mode 100644 index 00000000..39c0ab3c --- /dev/null +++ b/src/test/resources/projects/neoforge/261/gradle.properties @@ -0,0 +1,10 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G + +# Mod Properties +mod_version = 1.0.0 +maven_group = com.example +archives_base_name = fabric-example-mod + +# Dependencies +loom.platform = neoforge diff --git a/src/test/resources/projects/neoforge/261/settings.gradle b/src/test/resources/projects/neoforge/261/settings.gradle new file mode 100644 index 00000000..edccc03a --- /dev/null +++ b/src/test/resources/projects/neoforge/261/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "fabric-example-mod"