diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/NeoFormRuntime.java b/src/main/java/net/neoforged/moddevgradle/dsl/NeoFormRuntime.java index 0dac39e8..a3d140c9 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/NeoFormRuntime.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/NeoFormRuntime.java @@ -11,7 +11,7 @@ * the Minecraft artifacts for compiling and mods. */ public abstract class NeoFormRuntime { - private static final String DEFAULT_NFRT_VERSION = "0.1.70"; + private static final String DEFAULT_NFRT_VERSION = "1.0.0"; @Inject public NeoFormRuntime(Project project) { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java b/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java index 1ec4623b..171cd5ae 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java @@ -6,6 +6,7 @@ import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; @@ -20,9 +21,14 @@ * using the NFRT CLI. */ @DisableCachingByDefault(because = "Implements its own caching") -abstract class CreateMinecraftArtifactsTask extends NeoFormRuntimeEngineTask { +abstract class CreateMinecraftArtifactsTask extends NeoFormRuntimeTask { @Inject public CreateMinecraftArtifactsTask() { + // When cache is disabled, the task is NEVER up-to-date to aid with debugging problems + getOutputs().upToDateWhen(task -> ((CreateMinecraftArtifactsTask) task).getEnableCache().get()); + getEnableCache().convention(false); + getUseEclipseCompiler().convention(false); + getAnalyzeCacheMisses().convention(false); } @InputFiles @@ -59,6 +65,34 @@ public CreateMinecraftArtifactsTask() { @OutputFile abstract RegularFileProperty getResourcesArtifact(); + /** + * Gradle dependency notation for the NeoForge userdev artifact. + * Either this or {@link #getNeoFormArtifact()} must be specified. + */ + @Input + @Optional + abstract Property getNeoForgeArtifact(); + + /** + * Gradle dependency notation for the NeoForm data artifact. + * Either this or {@link #getNeoForgeArtifact()} must be specified. + */ + @Input + @Optional + abstract Property getNeoFormArtifact(); + + /** + * Enables use of the cache. + */ + @Internal + abstract Property getEnableCache(); + + @Internal + abstract Property getAnalyzeCacheMisses(); + + @Input + abstract Property getUseEclipseCompiler(); + @TaskAction public void createArtifacts() { var args = new ArrayList(); @@ -94,6 +128,29 @@ public void createArtifacts() { } } + if (!getEnableCache().get()) { + args.add("--disable-cache"); + } + + if (getAnalyzeCacheMisses().get()) { + args.add("--analyze-cache-misses"); + } + + if (getUseEclipseCompiler().get()) { + args.add("--use-eclipse-compiler"); + } + + // Note that it is possible to specify both + if (getNeoForgeArtifact().isPresent()) { + Collections.addAll(args, "--neoforge", getNeoForgeArtifact().get()); + } + if (getNeoFormArtifact().isPresent()) { + Collections.addAll(args, "--neoform", getNeoFormArtifact().get()); + } + if (!getNeoFormArtifact().isPresent() && !getNeoForgeArtifact().isPresent()) { + throw new GradleException("You need to specify at least 'version' or 'neoFormVersion' in the 'neoForge' block of your build script."); + } + Collections.addAll( args, "--dist", "joined", diff --git a/src/main/java/net/neoforged/moddevgradle/internal/DownloadAssetsTask.java b/src/main/java/net/neoforged/moddevgradle/internal/DownloadAssetsTask.java index e02d7519..051f21b6 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/DownloadAssetsTask.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/DownloadAssetsTask.java @@ -1,29 +1,95 @@ package net.neoforged.moddevgradle.internal; +import org.gradle.api.GradleException; import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import javax.inject.Inject; -import java.util.List; +import java.util.ArrayList; +import java.util.Collections; /** * Use the NFRT CLI to download the asset index and assets for the Minecraft version used by the * underlying NeoForge/NeoForm configuration. */ -abstract class DownloadAssetsTask extends NeoFormRuntimeEngineTask { +abstract class DownloadAssetsTask extends NeoFormRuntimeTask { @Inject public DownloadAssetsTask() { } + /** + * Gradle dependency notation for the NeoForm data artifact, from which a Minecraft version will be derived. + *

+ * To determine the minecraft version, the following properties will be checked in-order and the first one will be used: + *

    + *
  1. {@link #getMinecraftVersion()}
  2. + *
  3. {@link #getNeoFormArtifact()}
  4. + *
  5. this property
  6. + *
+ */ + @Input + @Optional + abstract Property getNeoForgeArtifact(); + + /** + * Gradle dependency notation for the NeoForm data artifact, from which a Minecraft version will be derived. + *

+ * To determine the minecraft version, the following properties will be checked in-order and the first one will be used: + *

    + *
  1. {@link #getMinecraftVersion()}
  2. + *
  3. this property
  4. + *
  5. {@link #getNeoForgeArtifact()}
  6. + *
+ */ + @Input + @Optional + abstract Property getNeoFormArtifact(); + + /** + * The Minecraft version to download the assets for. + *

+ * To determine the minecraft version, the following properties will be checked in-order and the first one will be used: + *

    + *
  1. this property
  2. + *
  3. {@link #getNeoFormArtifact()}
  4. + *
  5. {@link #getNeoForgeArtifact()}
  6. + *
+ */ + @Input + @Optional + abstract Property getMinecraftVersion(); + + /** + * A properties file will be written to this location which can be read by the runtime tasks + * to determine where the asset index and asset root are located. + */ @OutputFile abstract RegularFileProperty getAssetPropertiesFile(); @TaskAction public void createArtifacts() { - run(List.of( + + var args = new ArrayList(); + Collections.addAll(args, "download-assets", - "--output-properties-to", getAssetPropertiesFile().get().getAsFile().getAbsolutePath() - )); + "--write-properties", getAssetPropertiesFile().get().getAsFile().getAbsolutePath() + ); + + // Only one should be specified, we try to use the best one. + if (getMinecraftVersion().isPresent()) { + Collections.addAll(args, "--minecraft-version", getMinecraftVersion().get()); + } else if (getNeoFormArtifact().isPresent()) { + Collections.addAll(args, "--neoform", getNeoFormArtifact().get()); + } else if (getNeoForgeArtifact().isPresent()) { + Collections.addAll(args, "--neoforge", getNeoForgeArtifact().get()); + } else { + throw new GradleException("One of minecraftVersion, neoFormArtifact or neoForgeArtifact must be specified to download assets."); + } + + run(args); } } diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index c7fe822e..f6bd145a 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -199,15 +199,10 @@ public void apply(Project project) { }); // Configure common properties of NeoFormRuntimeEngineTask - Consumer configureEngineTask = task -> { + Consumer configureNfrtTask = task -> { var nfrtSettings = extension.getNeoFormRuntime(); task.getVerbose().set(nfrtSettings.getVerbose()); - task.getEnableCache().set(nfrtSettings.getEnableCache()); - task.getAnalyzeCacheMisses().set(nfrtSettings.getAnalyzeCacheMisses()); - task.getUseEclipseCompiler().set(nfrtSettings.getUseEclipseCompiler()); task.getArtifactManifestFile().set(createManifest.get().getManifestFile()); - task.getNeoForgeArtifact().set(extension.getVersion().map(version -> "net.neoforged:neoforge:" + version)); - task.getNeoFormArtifact().set(extension.getNeoFormVersion().map(version -> "net.neoforged:neoform:" + version + "@zip")); task.getNeoFormRuntime().from(neoFormRuntimeConfig); }; @@ -235,7 +230,14 @@ public void apply(Project project) { task.getSourcesArtifact().set(jarPathFactory.apply("-sources")); task.getResourcesArtifact().set(jarPathFactory.apply("-resources-aka-client-extra")); - configureEngineTask.accept(task); + var nfrtSettings = extension.getNeoFormRuntime(); + task.getEnableCache().set(nfrtSettings.getEnableCache()); + task.getAnalyzeCacheMisses().set(nfrtSettings.getAnalyzeCacheMisses()); + task.getUseEclipseCompiler().set(nfrtSettings.getUseEclipseCompiler()); + task.getNeoForgeArtifact().set(getNeoForgeUserDevDependencyNotation(extension)); + task.getNeoFormArtifact().set(getNeoFormDataDependencyNotation(extension)); + + configureNfrtTask.accept(task); }); var downloadAssets = tasks.register("downloadAssets", DownloadAssetsTask.class, task -> { @@ -243,7 +245,9 @@ public void apply(Project project) { task.setGroup(TASK_GROUP); task.setDescription("Downloads the Minecraft assets and asset index needed to run a Minecraft client or generate client-side resources."); task.getAssetPropertiesFile().set(modDevBuildDir.map(dir -> dir.file("minecraft_assets.properties"))); - configureEngineTask.accept(task); + task.getNeoForgeArtifact().set(getNeoForgeUserDevDependencyNotation(extension)); + task.getNeoFormArtifact().set(getNeoFormDataDependencyNotation(extension)); + configureNfrtTask.accept(task); }); // For IntelliJ, we attach a combined sources+classes artifact which enables an "Attach Sources..." link for IJ users @@ -443,6 +447,14 @@ public void apply(Project project) { configureEclipseModel(project, ideSyncTask, createArtifacts, extension, prepareRunTasks); } + private static Provider getNeoFormDataDependencyNotation(NeoForgeExtension extension) { + return extension.getNeoFormVersion().map(version -> "net.neoforged:neoform:" + version + "@zip"); + } + + private static Provider getNeoForgeUserDevDependencyNotation(NeoForgeExtension extension) { + return extension.getVersion().map(version -> "net.neoforged:neoforge:" + version + ":userdev"); + } + /** * Collects all dependencies needed by the NeoFormRuntime */ diff --git a/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeEngineTask.java b/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeEngineTask.java deleted file mode 100644 index f52deca8..00000000 --- a/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeEngineTask.java +++ /dev/null @@ -1,106 +0,0 @@ -package net.neoforged.moddevgradle.internal; - -import org.gradle.api.GradleException; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.Optional; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Extends the basic taks for running NFRT with the properties that apply to all subcommands - * working with NeoForge or NeoForm data. - */ -abstract public class NeoFormRuntimeEngineTask extends NeoFormRuntimeTask { - public NeoFormRuntimeEngineTask() { - // When cache is disabled, the task is NEVER up-to-date to aid with debugging problems - getOutputs().upToDateWhen(task -> ((NeoFormRuntimeEngineTask) task).getEnableCache().get()); - getEnableCache().convention(false); - getUseEclipseCompiler().convention(false); - getAnalyzeCacheMisses().convention(false); - getVerbose().convention(false); - } - - /** - * Points to the NeoForge Userdev artifact. - * Either this or {@link #getNeoFormArtifact()} must be specified. - */ - @Input - @Optional - abstract Property getNeoForgeArtifact(); - - /** - * Points to the NeoForm Config artifact. - * Either this or {@link #getNeoForgeArtifact()} must be specified. - */ - @Input - @Optional - abstract Property getNeoFormArtifact(); - - /** - * Enable verbose output for the NFRT engine. - */ - @Internal - abstract Property getVerbose(); - - @InputFile - @Optional - abstract RegularFileProperty getArtifactManifestFile(); - - /** - * Enables use of the cache. - */ - @Internal - abstract Property getEnableCache(); - - @Internal - abstract Property getAnalyzeCacheMisses(); - - @Input - abstract Property getUseEclipseCompiler(); - - @Override - protected void run(List args) { - args = new ArrayList<>(args); - - if (getVerbose().get()) { - args.add("--verbose"); - } - - if (getArtifactManifestFile().isPresent()) { - args.add("--artifact-manifest"); - args.add(getArtifactManifestFile().get().getAsFile().getAbsolutePath()); - args.add("--warn-on-artifact-manifest-miss"); - } - - if (!getEnableCache().get()) { - args.add("--disable-cache"); - } - - if (getAnalyzeCacheMisses().get()) { - args.add("--analyze-cache-misses"); - } - - if (getUseEclipseCompiler().get()) { - args.add("--use-eclipse-compiler"); - } - - // Note that it is possible to specify both - if (getNeoForgeArtifact().isPresent()) { - Collections.addAll(args, "--neoforge", getNeoForgeArtifact().get() + ":userdev"); - } - if (getNeoFormArtifact().isPresent()) { - Collections.addAll(args, "--neoform", getNeoFormArtifact().get()); - } - if (!getNeoFormArtifact().isPresent() && !getNeoForgeArtifact().isPresent()) { - throw new GradleException("You need to specify at least 'version' or 'neoFormVersion' in the 'neoForge' block of your build script."); - } - - super.run(args); - } -} diff --git a/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeTask.java b/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeTask.java index 03447b9e..546f1c26 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeTask.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/NeoFormRuntimeTask.java @@ -5,10 +5,13 @@ import org.gradle.api.DefaultTask; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Optional; import org.gradle.jvm.toolchain.JavaLanguageVersion; import org.gradle.jvm.toolchain.JavaLauncher; import org.gradle.jvm.toolchain.JavaToolchainService; @@ -24,10 +27,25 @@ */ abstract public class NeoFormRuntimeTask extends DefaultTask { + /** + * Enable verbose output for the NFRT engine. + */ + @Internal + abstract Property getVerbose(); + @Classpath @InputFiles abstract ConfigurableFileCollection getNeoFormRuntime(); + /** + * To help NFRT avoid unnecessary downloads of artifacts that Gradle has already cached, and to allow + * overriding dependencies, this property can specify a properties file mapping G:A:V to the on-disk path + * of those artifacts, which NFRT will use to avoid downloads if those artifacts are requested. + */ + @InputFile + @Optional + abstract RegularFileProperty getArtifactManifestFile(); + /** * Launcher for the java version used by NFRT itself. */ @@ -55,6 +73,8 @@ abstract public class NeoFormRuntimeTask extends DefaultTask { public NeoFormRuntimeTask() { var project = getProject(); + getVerbose().convention(false); + // When running NeoForm as part of a Gradle build, we store our caches under Gradles // home directory for user convenience (they will be picked up by Gradle cache actions in CI, etc.) var gradleHome = project.getGradle().getGradleUserHomeDir(); @@ -76,6 +96,21 @@ protected void run(List args) { realArgs.add(2, "--work-dir"); realArgs.add(3, getWorkDirectory().get().getAsFile().getAbsolutePath()); + if (getVerbose().get()) { + realArgs.add("--verbose"); + } + + if (getArtifactManifestFile().isPresent()) { + realArgs.add("--artifact-manifest"); + realArgs.add(getArtifactManifestFile().get().getAsFile().getAbsolutePath()); + realArgs.add("--warn-on-artifact-manifest-miss"); + } + + // When running through IJ or Eclipse, always enable emojis + if (IdeDetection.isIntelliJ() || IdeDetection.isEclipse()) { + realArgs.add("--emojis"); + } + getExecOperations().javaexec(execSpec -> { // Pass through network properties execSpec.systemProperties(NetworkSettingPassthrough.getNetworkSystemProperties()); @@ -83,11 +118,6 @@ protected void run(List args) { // See https://github.com/gradle/gradle/issues/28959 execSpec.jvmArgs("-Dstdout.encoding=UTF-8", "-Dstderr.encoding=UTF-8"); - // When running through IJ or Eclipse, always enable emojis - if (IdeDetection.isIntelliJ() || IdeDetection.isEclipse()) { - execSpec.args("--emojis"); - } - execSpec.executable(getNeoFormRuntimeLauncher().get().getExecutablePath().getAsFile()); execSpec.classpath(getNeoFormRuntime()); execSpec.args(realArgs);