diff --git a/README.md b/README.md index a840a462..b5ede245 100644 --- a/README.md +++ b/README.md @@ -21,20 +21,20 @@ In `settings.gradle`: ```groovy pluginManagement { - repositories { - // Add the usual NeoForged maven repository. - maven { url = 'https://maven.neoforged.net/releases' } - // Add the maven repository for the ModDevGradle plugin. - maven { - name 'Maven for PR #1' // https://github.com/neoforged/ModDevGradle/pull/1 - url 'https://prmaven.neoforged.net/ModDevGradle/pr1' - content { - includeModule('net.neoforged.moddev', 'net.neoforged.moddev.gradle.plugin') - includeModule('net.neoforged.moddev.junit', 'net.neoforged.moddev.junit.gradle.plugin') - includeModule('net.neoforged', 'moddev-gradle') - } + repositories { + // Add the usual NeoForged maven repository. + maven { url = 'https://maven.neoforged.net/releases' } + // Add the maven repository for the ModDevGradle plugin. + maven { + name 'Maven for PR #1' // https://github.com/neoforged/ModDevGradle/pull/1 + url 'https://prmaven.neoforged.net/ModDevGradle/pr1' + content { + includeModule('net.neoforged.moddev', 'net.neoforged.moddev.gradle.plugin') + includeModule('net.neoforged.moddev.junit', 'net.neoforged.moddev.junit.gradle.plugin') + includeModule('net.neoforged', 'moddev-gradle') + } + } } - } } plugins { @@ -78,15 +78,18 @@ neoForge { See the example code in [the test project](./testproject/build.gradle). ## More Configuration + ### Runs + Any number of runs can be added in the `neoForge { runs { ... } }` block. Every run must have a type. Currently, the supported types are `client`, `data`, `gameTestServer`, `server`. The run type can be set as follows: + ```groovy neoForge { runs { - { + < run name > { // This is the standard syntax: type = "gameTestServer" // Client, data and server runs can use a shorthand instead: @@ -98,18 +101,47 @@ neoForge { } ``` -Please have a look at [RunModel.java](src/java17/java/net/neoforged/moddevgradle/dsl/RunModel.java) for the list of supported properties. +Please have a look at [RunModel.java](src/java17/java/net/neoforged/moddevgradle/dsl/RunModel.java) for the list of +supported properties. Here is an example that sets a system property to change the log level to debug: + ```groovy neoForge { runs { configureEach { - systemProperty 'forge.logging.console.level', 'debug' + systemProperty 'forge.logging.console.level', 'debug' } } } ``` +### Better Minecraft Parameter Names / Javadoc (Parchment) + +You can use community-sourced parameter-names and Javadoc for Minecraft source code +from [ParchmentMC](https://parchmentmc.org/docs/getting-started). + +The easiest way is setting the Parchment version in your gradle.properties: + +```properties +neoForge.parchment.minecraftVersion=1.20.6 +neoForge.parchment.mappingsVersion=2024.05.01 +``` + +Alternatively, you can set it in your build.gradle: + +```groovy +neoForge { + // [...] + + parchment { + // Get versions from https://parchmentmc.org/docs/getting-started + // Omit the "v"-prefix in mappingsVersion + minecraftVersion = "1.20.6" + mappingsVersion = "2024.05.01" + } +} +``` + ## Advanced Tips & Tricks ### Overriding Platform Libraries diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java b/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java index 1632ab11..db39b184 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java @@ -15,11 +15,13 @@ public abstract class NeoForgeExtension { private final NamedDomainObjectContainer mods; private final NamedDomainObjectContainer runs; + private final Parchment parchment; @Inject public NeoForgeExtension(Project project) { mods = project.container(ModModel.class); runs = project.container(RunModel.class); + parchment = project.getObjects().newInstance(Parchment.class); getEnableCache().convention(project.getProviders().gradleProperty("neoforge.cache").map(Boolean::valueOf).orElse(true)); getVerbose().convention(project.getProviders().gradleProperty("neoforge.verbose").map(Boolean::valueOf).orElse(false)); @@ -66,4 +68,12 @@ public NamedDomainObjectContainer getRuns() { public void runs(Action> action) { action.execute(runs); } + + public Parchment getParchment() { + return parchment; + } + + public void parchment(Action action) { + action.execute(parchment); + } } diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/Parchment.java b/src/main/java/net/neoforged/moddevgradle/dsl/Parchment.java new file mode 100644 index 00000000..ee7f88bb --- /dev/null +++ b/src/main/java/net/neoforged/moddevgradle/dsl/Parchment.java @@ -0,0 +1,85 @@ +package net.neoforged.moddevgradle.dsl; + +import net.neoforged.moddevgradle.internal.utils.PropertyUtils; +import org.gradle.api.Project; +import org.gradle.api.artifacts.repositories.MavenArtifactRepository; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Optional; +import org.jetbrains.annotations.ApiStatus; + +import javax.inject.Inject; +import java.net.URI; + +/** + * Allows configuration of Parchment mappings for userdev. + */ +@ApiStatus.NonExtendable +public abstract class Parchment { + @Inject + public Parchment(Project project) { + getParchmentArtifact().convention( + project.getProviders().gradleProperty("neoForge.parchment.parchmentArtifact").orElse( + getMinecraftVersion() + .zip(getMappingsVersion(), (minecraftVersion, mappingVersion) -> { + return "org.parchmentmc.data" + + ":" + "parchment-" + minecraftVersion + + ":" + mappingVersion + // We need the checked variant for now since it resolves + // parameters conflicting with local variables by prefixing everything with "p" + + ":checked" + + "@zip"; + }) + ) + ); + getMinecraftVersion().convention( + project.getProviders().gradleProperty("neoForge.parchment.minecraftVersion") + ); + getMappingsVersion().convention( + project.getProviders().gradleProperty("neoForge.parchment.mappingsVersion") + ); + getAddRepository().convention( + PropertyUtils.getBooleanProperty(project, "neoForge.parchment.addRepository").orElse(true) + ); + getEnabled().convention(getParchmentArtifact() + .map(s -> !s.isEmpty()).orElse(PropertyUtils.getBooleanProperty(project, "neoForge.parchment.enabled").orElse(false))); + } + + /** + * Artifact coordinates for parchment mappings. + */ + @Input + @Optional + public abstract Property getParchmentArtifact(); + + /** + * Minecraft version of parchment to use. This property is + * ignored if {@link #getParchmentArtifact()} is set explicitly. + */ + @Input + @Optional + public abstract Property getMinecraftVersion(); + + /** + * Mapping version of default parchment to use. This property is + * ignored if {@link #getParchmentArtifact()} is set explicitly. + */ + @Input + @Optional + public abstract Property getMappingsVersion(); + + /** + * If enabled (the default), the parchment repository will automatically be added to the project, + * if {@link #getEnabled()} is true. + */ + @Internal + public abstract Property getAddRepository(); + + /** + * Enables or disables the system. It is enabled by default if a {@link #getParchmentArtifact()} is specified. + */ + @Input + public abstract Property getEnabled(); + +} diff --git a/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java b/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java index 15c56371..2a57e982 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/CreateMinecraftArtifactsTask.java @@ -1,5 +1,6 @@ package net.neoforged.moddevgradle.internal; +import org.gradle.api.GradleException; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Property; @@ -46,6 +47,9 @@ public CreateMinecraftArtifactsTask() { @InputFiles abstract ConfigurableFileCollection getAccessTransformers(); + @InputFiles + abstract ConfigurableFileCollection getParchmentData(); + @OutputFile abstract RegularFileProperty getCompiledWithSourcesArtifact(); @@ -104,6 +108,14 @@ public void createArtifacts() throws IOException { args.add(accessTransformer.getAbsolutePath()); } + var parchmentData = getParchmentData().getFiles(); + if (parchmentData.size() == 1) { + args.add("--parchment-data"); + args.add(parchmentData.iterator().next().getAbsolutePath()); + } else if (parchmentData.size() > 1) { + throw new GradleException("More than one parchment data file were specified: " + parchmentData); + } + Collections.addAll( args, "--neoforge", artifactId + ":userdev", diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 093b74cb..706f6714 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -2,6 +2,7 @@ import net.neoforged.moddevgradle.dsl.InternalModelHelper; import net.neoforged.moddevgradle.dsl.NeoForgeExtension; +import net.neoforged.moddevgradle.dsl.Parchment; import net.neoforged.moddevgradle.dsl.RunModel; import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; import net.neoforged.moddevgradle.internal.utils.StringUtils; @@ -12,6 +13,7 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ModuleDependency; import org.gradle.api.artifacts.dsl.RepositoryHandler; +import org.gradle.api.artifacts.repositories.MavenArtifactRepository; import org.gradle.api.artifacts.result.ResolvedArtifactResult; import org.gradle.api.attributes.Attribute; import org.gradle.api.attributes.Bundling; @@ -131,7 +133,7 @@ public void apply(Project project) { files.setCanBeConsumed(false); files.setCanBeResolved(true); files.defaultDependencies(spec -> { - spec.add(dependencyFactory.create("net.neoforged:neoform-runtime:0.1.17").attributes(attributes -> { + spec.add(dependencyFactory.create("net.neoforged:neoform-runtime:0.1.19").attributes(attributes -> { attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, project.getObjects().named(Bundling.class, Bundling.SHADOWED)); })); }); @@ -199,6 +201,18 @@ public void apply(Project project) { task.getManifestFile().set(layout.getBuildDirectory().file("neoform_artifact_manifest.properties")); }); + // Add a filtered parchment repository automatically if enabled + var parchment = extension.getParchment(); + configureParchmentRepository(project, parchment); + var parchmentData = configurations.create("parchmentData", spec -> { + spec.setCanBeResolved(true); + spec.setCanBeConsumed(false); + spec.setTransitive(false); // Expect a single result + spec.withDependencies(dependencies -> { + dependencies.addLater(parchment.getParchmentArtifact().map(project.getDependencyFactory()::create)); + }); + }); + // it has to contain client-extra to be loaded by FML, and it must be added to the legacy CP var createArtifacts = tasks.register("createMinecraftArtifacts", CreateMinecraftArtifactsTask.class, task -> { task.getVerbose().set(extension.getVerbose()); @@ -206,6 +220,7 @@ public void apply(Project project) { task.getArtifactManifestFile().set(createManifest.get().getManifestFile()); task.getNeoForgeArtifact().set(extension.getVersion().map(version -> "net.neoforged:neoforge:" + version)); task.getAccessTransformers().from(accessTransformers); + task.getParchmentData().from(parchmentData); task.getNeoFormRuntime().from(neoFormRuntimeConfig); task.getCompileClasspath().from(minecraftCompileClasspath); task.getCompiledArtifact().set(layout.getBuildDirectory().file("repo/minecraft/neoforge-minecraft-joined/local/neoforge-minecraft-joined-local.jar")); @@ -376,6 +391,22 @@ public void apply(Project project) { configureEclipseModel(project, idePostSyncTask, createArtifacts); } + private static void configureParchmentRepository(Project project, Parchment parchment) { + project.afterEvaluate(p -> { + if (!parchment.getEnabled().get() || !parchment.getAddRepository().get()) { + return; + } + MavenArtifactRepository repo = p.getRepositories().maven(m -> { + m.setName("Parchment Data"); + m.setUrl(URI.create("https://maven.parchmentmc.org/")); + m.mavenContent(mavenContent -> mavenContent.includeGroup("org.parchmentmc.data")); + }); + // Make sure it comes first due to its filtered group, that should speed up resolution + p.getRepositories().remove(repo); + p.getRepositories().addFirst(repo); + }); + } + private static boolean shouldUseCombinedSourcesAndClassesArtifact() { return true; // return Boolean.getBoolean("idea.active"); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/PropertyUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/PropertyUtils.java new file mode 100644 index 00000000..eb0e4145 --- /dev/null +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/PropertyUtils.java @@ -0,0 +1,26 @@ +package net.neoforged.moddevgradle.internal.utils; + +import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.provider.Provider; + +public final class PropertyUtils { + private PropertyUtils() { + } + + public static Provider getStringProperty(Project project, String propertyName) { + return project.getProviders().gradleProperty(propertyName); + } + + public static Provider getBooleanProperty(Project project, String propertyName) { + return project.getProviders().gradleProperty(propertyName) + .map(value -> { + try { + return Boolean.valueOf(value); + } catch (Exception e) { + throw new GradleException("Gradle Property " + propertyName + " is not set to a boolean value: '" + value + "'"); + } + }); + } + +} diff --git a/testproject/build.gradle b/testproject/build.gradle index f94530bc..c3b0f7d1 100644 --- a/testproject/build.gradle +++ b/testproject/build.gradle @@ -28,4 +28,9 @@ neoForge { sourceSet sourceSets.main } } + + parchment { + minecraftVersion = "1.20.6" + mappingsVersion = "2024.05.01" + } }