From 6a9c970a8bcb9d85492365390b3f10d7ab72e0da Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 14 Jun 2024 00:33:05 +0200 Subject: [PATCH 1/7] Improve source set support Allow the modding depedencies to be added to source sets that do not extend from the main source set. Also allow setting of the primary source set for runs, which also translates into that source set being set as the IntelliJ classpath module for that run. --- README.md | 32 +++++ .../moddevgradle/dsl/NeoForgeExtension.java | 23 ++++ .../neoforged/moddevgradle/dsl/RunModel.java | 12 ++ .../moddevgradle/internal/ModDevPlugin.java | 117 ++++++++++++------ .../moddevgradle/internal/RunUtils.java | 11 +- .../internal/utils/ExtensionUtils.java | 6 + .../internal/utils/IdeDetection.java | 49 ++++++++ testproject/build.gradle | 11 ++ testproject/src/api/java/apitest/ApiTest.java | 10 ++ .../main/java/testproject/TestProject.java | 3 + .../resources/META-INF/neoforge.mods.toml | 6 +- 11 files changed, 234 insertions(+), 46 deletions(-) create mode 100644 testproject/src/api/java/apitest/ApiTest.java diff --git a/README.md b/README.md index 7fb62a5b..34758c61 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,10 @@ neoForge { // You can change the name used for this run in your IDE ideName = "Run Game Tests" + + // Changes the source set whose runtime classpath is used for this run. This defaults to "main" + // Eclipse does not support having multiple runtime classpaths per project (except for unit tests). + sourceSet = sourceSets.main } } } @@ -167,6 +171,34 @@ neoForge { } ``` +### Isolated Source Sets + +If you work with source sets that do not extend from `main`, and would like the modding dependencies to be available +in those source sets, you can use the following api: + +``` +sourceSets { + anotherSourceSet // example +} + +neoForge { + // ... + addModdingDependenciesTo(sourceSets.anotherSourceSet) + + mods { + mymod { + sourceSet sourceSets.main + // Do not forget to add additional soruce-sets here! + sourceSet sourceSets.anotherSourceSet + } + } +} + +dependencies { + implementation sourceSets.anotherSourceSet.output +} +``` + ### Better Minecraft Parameter Names / Javadoc (Parchment) You can use community-sourced parameter-names and Javadoc for Minecraft source code diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java b/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java index 8310e177..996bd7e4 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java @@ -1,10 +1,14 @@ package net.neoforged.moddevgradle.dsl; +import net.neoforged.moddevgradle.internal.ModDevPlugin; import org.gradle.api.Action; +import org.gradle.api.GradleException; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Project; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; import javax.inject.Inject; import java.util.List; @@ -15,6 +19,7 @@ public abstract class NeoForgeExtension { public static final String NAME = "neoForge"; + private final Project project; private final NamedDomainObjectContainer mods; private final NamedDomainObjectContainer runs; private final Parchment parchment; @@ -23,6 +28,7 @@ public abstract class NeoForgeExtension { @Inject public NeoForgeExtension(Project project) { + this.project = project; mods = project.container(ModModel.class); runs = project.container(RunModel.class); parchment = project.getObjects().newInstance(Parchment.class); @@ -40,6 +46,23 @@ public NeoForgeExtension(Project project) { })); } + /** + * Adds the necessary dependencies to develop a Minecraft mod to the given source set. + * The plugin automatically adds these dependencies to the main source set. + */ + public void addModdingDependenciesTo(SourceSet sourceSet) { + var configurations = project.getConfigurations(); + var sourceSets = project.getExtensions().getByType(SourceSetContainer.class); + if (!sourceSets.contains(sourceSet)) { + throw new GradleException("Cannot add to the source set in another project."); + } + + configurations.getByName(sourceSet.getRuntimeClasspathConfigurationName()) + .extendsFrom(configurations.getByName(ModDevPlugin.CONFIGURATION_RUNTIME_DEPENDENCIES)); + configurations.getByName(sourceSet.getCompileClasspathConfigurationName()) + .extendsFrom(configurations.getByName(ModDevPlugin.CONFIGURATION_COMPILE_DEPENDENCIES)); + } + /** * NeoForge version number. You have to set either this or {@link #getNeoFormVersion()}. */ diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/RunModel.java b/src/main/java/net/neoforged/moddevgradle/dsl/RunModel.java index 46a7ed28..b300a36c 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/RunModel.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/RunModel.java @@ -1,5 +1,6 @@ package net.neoforged.moddevgradle.dsl; +import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; import net.neoforged.moddevgradle.internal.utils.StringUtils; import org.gradle.api.Named; import org.gradle.api.Project; @@ -11,6 +12,7 @@ import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.SetProperty; +import org.gradle.api.tasks.SourceSet; import org.slf4j.event.Level; import javax.inject.Inject; @@ -49,6 +51,8 @@ public RunModel(String name, Project project) { ideName = project.getName() + " - " + ideName; } getIdeName().convention(ideName); + + getSourceSet().convention(ExtensionUtils.getSourceSets(project).getByName(SourceSet.MAIN_SOURCE_SET_NAME)); } @Override @@ -113,6 +117,14 @@ public Configuration getAdditionalRuntimeClasspathConfiguration() { public abstract Property getLogLevel(); + /** + * Sets the source set to be used as the main classpath of this run. + * Defaults to the {@code main} source set. + * Eclipse does not support having multiple different classpaths per project beyond a separate unit-testing + * classpath. + */ + public abstract Property getSourceSet(); + @Override public String toString() { return "Run[" + getName() + "]"; diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 0b211a1d..e314788b 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -7,6 +7,7 @@ import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; import net.neoforged.moddevgradle.internal.utils.IdeDetection; import net.neoforged.moddevgradle.tasks.JarJar; +import org.gradle.api.GradleException; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; @@ -28,6 +29,7 @@ import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.bundling.AbstractArchiveTask; @@ -74,10 +76,16 @@ public class ModDevPlugin implements Plugin { private static final String INTERNAL_TASK_GROUP = "mod development/internal"; /** - * Name of the configuration in which we place our generated artifacts for use in the runtime classpath, - * without having them leak to dependents. + * Name of the configuration in which we place the required dependencies to develop mods for use in the runtime-classpath. + * We cannot use "runtimeOnly", since the contents of that are published. */ - private static final String CONFIGURATION_GENERATED_ARTIFACTS = "neoForgeGeneratedArtifacts"; + public static final String CONFIGURATION_RUNTIME_DEPENDENCIES = "neoForgeRuntimeDependencies"; + + /** + * Name of the configuration in which we place the required dependencies to develop mods for use in the compile-classpath. + * While compile only is not published, we also use a configuration here to be consistent. + */ + public static final String CONFIGURATION_COMPILE_DEPENDENCIES = "neoForgeCompileDependencies"; private Runnable configureTesting = null; @@ -227,8 +235,8 @@ public void apply(Project project) { minecraftClassesArtifact = createArtifacts.map(task -> project.files(task.getCompiledArtifact())); } - var localRuntime = configurations.create(CONFIGURATION_GENERATED_ARTIFACTS, config -> { - config.setDescription("Minecraft artifacts that were generated locally by NFRT"); + var runtimeDependenciesConfig = configurations.create(CONFIGURATION_RUNTIME_DEPENDENCIES, config -> { + config.setDescription("The runtime dependencies to develop a mod for NeoForge, including Minecraft classes."); config.setCanBeResolved(false); config.setCanBeConsumed(false); config.withDependencies(dependencies -> { @@ -248,14 +256,26 @@ public void apply(Project project) { }); }); + configurations.create(CONFIGURATION_COMPILE_DEPENDENCIES, config -> { + config.setDescription("The compile-time dependencies to develop a mod for NeoForge, including Minecraft classes."); + config.setCanBeResolved(false); + config.setCanBeConsumed(false); + config.withDependencies(dependencies -> { + dependencies.addLater(minecraftClassesArtifact.map(dependencyFactory::create)); + dependencies.addLater(neoForgeModDevLibrariesDependency); + }); + }); + + var sourceSets = ExtensionUtils.getSourceSets(project); + var mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); + extension.addModdingDependenciesTo(mainSourceSet); + configurations.named(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME).configure(configuration -> { configuration.withDependencies(dependencies -> { dependencies.addLater(minecraftClassesArtifact.map(dependencyFactory::create)); dependencies.addLater(neoForgeModDevLibrariesDependency); }); }); - var runtimeClasspath = configurations.named(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); - runtimeClasspath.configure(files -> files.extendsFrom(localRuntime)); // Try to give people at least a fighting chance to run on the correct java version project.afterEvaluate(ignored -> { @@ -282,38 +302,39 @@ public void apply(Project project) { }))); }); - var neoForgeModDevModules = project.getConfigurations().create("neoForgeModuleOnly", spec -> { - spec.setDescription("Libraries that should be placed on the JVMs boot module path."); - spec.setCanBeResolved(true); - spec.setCanBeConsumed(false); - spec.shouldResolveConsistentlyWith(runtimeClasspath.get()); - // NOTE: When running in vanilla mode, this configuration is simply empty - spec.withDependencies(set -> { - set.addLater(extension.getVersion().map(version -> { - return dependencyFactory.create("net.neoforged:neoforge:" + version) - .capabilities(caps -> { - caps.requireCapability("net.neoforged:neoforge-moddev-module-path"); - }) - // TODO: this is ugly; maybe make the configuration transitive in neoforge, or fix the SJH dep. - .exclude(Map.of("group", "org.jetbrains", "module", "annotations")); - })); - set.add(dependencyFactory.create(RunUtils.DEV_LAUNCH_GAV)); - }); - }); - var ideSyncTask = tasks.register("neoForgeIdeSync"); Map> prepareRunTasks = new IdentityHashMap<>(); extension.getRuns().configureEach(run -> { var type = RunUtils.getRequiredType(project, run); - var sourceSet = ExtensionUtils.getExtension(project, "sourceSets", SourceSetContainer.class).getByName("main"); + var runtimeClasspathConfig = run.getSourceSet().map(sourceSet -> sourceSet.getRuntimeClasspathConfigurationName()) + .map(name -> configurations.getByName(name)); + + var neoForgeModDevModules = project.getConfigurations().create(InternalModelHelper.nameOfRun(run, "", "modulesOnly"), spec -> { + spec.setDescription("Libraries that should be placed on the JVMs boot module path for run " + run.getName() + "."); + spec.setCanBeResolved(true); + spec.setCanBeConsumed(false); + spec.shouldResolveConsistentlyWith(runtimeClasspathConfig.get()); + // NOTE: When running in vanilla mode, this configuration is simply empty + spec.withDependencies(set -> { + set.addLater(extension.getVersion().map(version -> { + return dependencyFactory.create("net.neoforged:neoforge:" + version) + .capabilities(caps -> { + caps.requireCapability("net.neoforged:neoforge-moddev-module-path"); + }) + // TODO: this is ugly; maybe make the configuration transitive in neoforge, or fix the SJH dep. + .exclude(Map.of("group", "org.jetbrains", "module", "annotations")); + })); + set.add(dependencyFactory.create(RunUtils.DEV_LAUNCH_GAV)); + }); + }); var legacyClasspathConfiguration = configurations.create(InternalModelHelper.nameOfRun(run, "", "legacyClasspath"), spec -> { spec.setDescription("Contains all dependencies of the " + run.getName() + " run that should not be considered boot classpath modules."); spec.setCanBeResolved(true); spec.setCanBeConsumed(false); - spec.shouldResolveConsistentlyWith(runtimeClasspath.get()); + spec.shouldResolveConsistentlyWith(runtimeClasspathConfig.get()); spec.attributes(attributes -> { attributes.attributeProvider(ATTRIBUTE_DISTRIBUTION, type.map(t -> t.equals("client") ? "client" : "server")); attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME)); @@ -367,7 +388,7 @@ public void apply(Project project) { task.getJavaLauncher().set(toolchainService.launcherFor(spec -> spec.getLanguageVersion().set(javaExtension.getToolchain().getLanguageVersion()))); // Note: this contains both the runtimeClasspath configuration and the sourceset's outputs. // This records a dependency on compiling and processing the resources of the source set. - task.getClasspathProvider().from(sourceSet.getRuntimeClasspath()); + task.getClasspathProvider().from(mainSourceSet.getRuntimeClasspath()); task.getGameDirectory().set(run.getGameDirectory()); task.getEnvironmentProperty().set(run.getEnvironment()); @@ -381,14 +402,12 @@ public void apply(Project project) { }); }); - setupJarJar(project); configureTesting = () -> setupTesting( project, modDevBuildDir, userDevConfigOnly, - neoForgeModDevModules, downloadAssets, ideSyncTask, createArtifacts, @@ -515,7 +534,6 @@ public void setupTesting() { private void setupTesting(Project project, Provider modDevDir, Configuration userDevConfigOnly, - Configuration neoForgeModDevModules, TaskProvider downloadAssets, TaskProvider ideSyncTask, TaskProvider createArtifacts, @@ -550,15 +568,35 @@ private void setupTesting(Project project, }); }); - configurations.named(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, files -> { - files.extendsFrom(configurations.getByName(CONFIGURATION_GENERATED_ARTIFACTS)); + var testRuntimeClasspathConfig = configurations.named(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, files -> { + files.extendsFrom(configurations.getByName(CONFIGURATION_RUNTIME_DEPENDENCIES)); files.extendsFrom(testFixtures); }); + var neoForgeModDevModules = project.getConfigurations().create("neoForgeTestModules", spec -> { + spec.setDescription("Libraries that should be placed on the JVMs boot module path for unit tests."); + spec.setCanBeResolved(true); + spec.setCanBeConsumed(false); + spec.shouldResolveConsistentlyWith(testRuntimeClasspathConfig.get()); + // NOTE: When running in vanilla mode, this configuration is simply empty + spec.withDependencies(set -> { + set.addLater(extension.getVersion().map(version -> { + return dependencyFactory.create("net.neoforged:neoforge:" + version) + .capabilities(caps -> { + caps.requireCapability("net.neoforged:neoforge-moddev-module-path"); + }) + // TODO: this is ugly; maybe make the configuration transitive in neoforge, or fix the SJH dep. + .exclude(Map.of("group", "org.jetbrains", "module", "annotations")); + })); + set.add(dependencyFactory.create(RunUtils.DEV_LAUNCH_GAV)); + }); + }); + var legacyClasspathConfiguration = configurations.create("neoForgeTestLibraries", spec -> { - spec.setDescription("Contains the legacy classpath of the test run"); + spec.setDescription("Contains the legacy classpath of unit tests."); spec.setCanBeResolved(true); spec.setCanBeConsumed(false); + spec.shouldResolveConsistentlyWith(testRuntimeClasspathConfig.get()); spec.attributes(attributes -> { attributes.attribute(ATTRIBUTE_DISTRIBUTION, "client"); attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME)); @@ -681,8 +719,13 @@ private static void addIntelliJRunConfiguration(Project project, RunModel run, PrepareRun prepareTask) { var appRun = new Application(run.getIdeName().get(), project); - var sourceSets = ExtensionUtils.getExtension(project, "sourceSets", SourceSetContainer.class); - appRun.setModuleRef(new ModuleRef(project, sourceSets.getByName("main"))); + var sourceSets = ExtensionUtils.getSourceSets(project); + var sourceSet = run.getSourceSet().get(); + // Validate that the source set is part of this project + if (!sourceSets.contains(sourceSet)) { + throw new GradleException("Cannot use source set from another project for run " + run.getName()); + } + appRun.setModuleRef(new ModuleRef(project, sourceSet)); appRun.setWorkingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()); appRun.setEnvs(run.getEnvironment().get()); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index 78451fb5..4b608ba6 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -5,6 +5,7 @@ import net.neoforged.moddevgradle.dsl.NeoForgeExtension; import net.neoforged.moddevgradle.dsl.RunModel; import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; +import net.neoforged.moddevgradle.internal.utils.IdeDetection; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; @@ -246,14 +247,12 @@ private static Provider> getModFoldersForGradle(Project p /** * Returns the configured output directory, only if "Build and run using" is set to "IDEA". - * In other cases, returns {@null}. + * In other cases, returns {@code null}. */ @Nullable static File getIntellijOutputDirectory(Project project) { - // TODO: this doesn't work in our little testproject because the .idea folder is one level above the root... - var projectDir = project.getRootDir(); - var ideaDir = new File(projectDir, ".idea"); - if (!ideaDir.exists()) { + var ideaDir = IdeDetection.getIntellijProjectDir(project); + if (ideaDir == null) { return null; } @@ -272,7 +271,7 @@ static File getIntellijOutputDirectory(Project project) { outputDirUrl = "file://$PROJECT_DIR$/out"; } - outputDirUrl = outputDirUrl.replace("$PROJECT_DIR$", projectDir.getAbsolutePath()); + outputDirUrl = outputDirUrl.replace("$PROJECT_DIR$", ideaDir.getParentFile().getAbsolutePath()); outputDirUrl = outputDirUrl.replaceAll("^file:", ""); // The output dir can start with something like "//C:\"; File can handle it. diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/ExtensionUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/ExtensionUtils.java index 38b8f684..097fbb9b 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/utils/ExtensionUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/ExtensionUtils.java @@ -1,7 +1,9 @@ package net.neoforged.moddevgradle.internal.utils; +import org.gradle.api.Project; import org.gradle.api.plugins.ExtensionAware; import org.gradle.api.plugins.ExtensionContainer; +import org.gradle.api.tasks.SourceSetContainer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -41,4 +43,8 @@ public static T findExtension(ExtensionContainer container, String name, Cla } return expectedType.cast(extension); } + + public static SourceSetContainer getSourceSets(Project project) { + return getExtension(project, "sourceSets", SourceSetContainer.class); + } } diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java index ca3857c4..30531a61 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java @@ -1,5 +1,11 @@ package net.neoforged.moddevgradle.internal.utils; +import org.gradle.api.Project; +import org.gradle.api.initialization.IncludedBuild; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + /** * Utilities for trying to detect in which IDE Gradle is running. */ @@ -27,4 +33,47 @@ public static boolean isIntelliJSync() { public static boolean isEclipse() { return System.getProperty("eclipse.application") != null; } + + /** + * Try to find the IntelliJ project directory that belongs to this Gradle project. + * There are scenarios where this is impossible, since IntelliJ allows adding + * Gradle builds to IntelliJ projects in a completely different directory. + */ + @Nullable + public static File getIntellijProjectDir(Project project) { + // Always try the root directory first, since it has the highest chance + var intellijProjectDir = getIntellijProjectDir(project.getRootDir()); + if (intellijProjectDir != null) { + return intellijProjectDir; + } + + // Try every included build + for (var includedBuild : project.getGradle().getIncludedBuilds()) { + if (!includedBuild.getProjectDir().equals(project.getRootDir())) { + intellijProjectDir = getIntellijProjectDir(includedBuild.getProjectDir()); + if (intellijProjectDir != null) { + return intellijProjectDir; + } + } + } + + return null; + } + + private static File getIntellijProjectDir(File gradleProjectDir) { + // Search the .idea folder belonging to this Gradle project + // In includeBuild scenarios, it might be above the project. It's also possible + // that it is completely separate. + var ideaDir = new File(gradleProjectDir, ".idea"); + while (!ideaDir.exists()) { + gradleProjectDir = gradleProjectDir.getParentFile(); + if (gradleProjectDir == null) { + return null; + } + ideaDir = new File(gradleProjectDir, ".idea"); + } + + return ideaDir; + } + } diff --git a/testproject/build.gradle b/testproject/build.gradle index c3ea0695..33331523 100644 --- a/testproject/build.gradle +++ b/testproject/build.gradle @@ -7,12 +7,17 @@ repositories { mavenLocal() } +sourceSets { + api +} + dependencies { testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation "net.neoforged:testframework:${project.neoforge_version}" implementation project(":subproject") + implementation sourceSets.api.output } test { @@ -21,6 +26,7 @@ test { neoForge { version = project.neoforge_version + addModdingDependenciesTo(sourceSets.api) runs { configureEach { @@ -35,11 +41,16 @@ neoForge { server { server() } + apitest { + client() + sourceSet = sourceSets.api + } } mods { testproject { sourceSet sourceSets.main + sourceSet sourceSets.api dependency project(":subproject") } } diff --git a/testproject/src/api/java/apitest/ApiTest.java b/testproject/src/api/java/apitest/ApiTest.java new file mode 100644 index 00000000..f9ab3f7b --- /dev/null +++ b/testproject/src/api/java/apitest/ApiTest.java @@ -0,0 +1,10 @@ +package apitest; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class ApiTest { + public ApiTest() { + new ItemStack(Items.AIR); + } +} diff --git a/testproject/src/main/java/testproject/TestProject.java b/testproject/src/main/java/testproject/TestProject.java index c60aaf12..0298696b 100644 --- a/testproject/src/main/java/testproject/TestProject.java +++ b/testproject/src/main/java/testproject/TestProject.java @@ -1,5 +1,6 @@ package testproject; +import apitest.ApiTest; import net.minecraft.DetectedVersion; import net.neoforged.fml.common.Mod; import subproject.SubProject; @@ -9,5 +10,7 @@ public class TestProject { public TestProject() { System.out.println(DetectedVersion.tryDetectVersion().getName()); System.out.println(SubProject.class.getName()); + + new ApiTest(); // access something from the api source set } } diff --git a/testproject/src/main/resources/META-INF/neoforge.mods.toml b/testproject/src/main/resources/META-INF/neoforge.mods.toml index 7e137733..d624a48c 100644 --- a/testproject/src/main/resources/META-INF/neoforge.mods.toml +++ b/testproject/src/main/resources/META-INF/neoforge.mods.toml @@ -7,7 +7,7 @@ modLoader="javafml" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the the FML version. This is currently 47. -loaderVersion="[3,)" #mandatory +loaderVersion="[4,)" #mandatory # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. @@ -76,7 +76,7 @@ type="required" #mandatory # Optional field describing why the dependency is required or why it is incompatible # reason="..." # The version range of the dependency -versionRange="[20.6,)" #mandatory +versionRange="[21.0.0-beta,)" #mandatory # An ordering relationship for the dependency. # BEFORE - This mod is loaded BEFORE the dependency # AFTER - This mod is loaded AFTER the dependency @@ -89,7 +89,7 @@ side="BOTH" modId="minecraft" type="required" # This version range declares a minimum of the current minecraft version up to but not including the next major version -versionRange="[1.20.6]" +versionRange="[1.21]" ordering="NONE" side="BOTH" From 30ace80da06076ab7d5782deaa004a0412025709 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 14 Jun 2024 00:35:51 +0200 Subject: [PATCH 2/7] Improve source set support Allow the modding depedencies to be added to source sets that do not extend from the main source set. Also allow setting of the primary source set for runs, which also translates into that source set being set as the IntelliJ classpath module for that run. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 34758c61..bd98d7d8 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ neoForge { mods { mymod { sourceSet sourceSets.main - // Do not forget to add additional soruce-sets here! + // Do not forget to add additional source-sets here! sourceSet sourceSets.anotherSourceSet } } From b10d325171acc3d96d0f0a83845fdd0e89f200f8 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 14 Jun 2024 12:55:19 +0200 Subject: [PATCH 3/7] In multi-projects it still uses the Gradle dir for storing the output --- src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index 4b608ba6..f4a37ef1 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -271,7 +271,7 @@ static File getIntellijOutputDirectory(Project project) { outputDirUrl = "file://$PROJECT_DIR$/out"; } - outputDirUrl = outputDirUrl.replace("$PROJECT_DIR$", ideaDir.getParentFile().getAbsolutePath()); + outputDirUrl = outputDirUrl.replace("$PROJECT_DIR$", project.getProjectDir().getAbsolutePath()); outputDirUrl = outputDirUrl.replaceAll("^file:", ""); // The output dir can start with something like "//C:\"; File can handle it. From 394053ee13973493b8c1b89cfc8abf528f071ba8 Mon Sep 17 00:00:00 2001 From: Technici4n <13494793+Technici4n@users.noreply.github.com> Date: Fri, 14 Jun 2024 19:54:18 +0200 Subject: [PATCH 4/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd98d7d8..5b9da0e1 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ sourceSets { neoForge { // ... - addModdingDependenciesTo(sourceSets.anotherSourceSet) + addModdingDependenciesTo sourceSets.anotherSourceSet mods { mymod { From ef7a80a3f6f6c45e0543cfd85fe845e5a3cc8bd6 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 14 Jun 2024 20:43:06 +0200 Subject: [PATCH 5/7] Improve the .idea folder detection. --- .../moddevgradle/internal/utils/IdeDetection.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java index 30531a61..b3b9b986 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java @@ -47,14 +47,14 @@ public static File getIntellijProjectDir(Project project) { return intellijProjectDir; } - // Try every included build - for (var includedBuild : project.getGradle().getIncludedBuilds()) { - if (!includedBuild.getProjectDir().equals(project.getRootDir())) { - intellijProjectDir = getIntellijProjectDir(includedBuild.getProjectDir()); - if (intellijProjectDir != null) { - return intellijProjectDir; - } + // Navigate to the root of the composite build tree + var root = project.getGradle().getParent(); + if (root != null) { + while (root.getParent() != null) { + root = root.getParent(); } + + return getIntellijProjectDir(root.getRootProject().getProjectDir()); } return null; From f7cd01b30dd4c5091b242898d30fe074b004f005 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 14 Jun 2024 20:47:53 +0200 Subject: [PATCH 6/7] Improve idea folder detection --- .../moddevgradle/internal/utils/IdeDetection.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java index b3b9b986..399f332d 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java @@ -1,7 +1,6 @@ package net.neoforged.moddevgradle.internal.utils; import org.gradle.api.Project; -import org.gradle.api.initialization.IncludedBuild; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -41,13 +40,7 @@ public static boolean isEclipse() { */ @Nullable public static File getIntellijProjectDir(Project project) { - // Always try the root directory first, since it has the highest chance - var intellijProjectDir = getIntellijProjectDir(project.getRootDir()); - if (intellijProjectDir != null) { - return intellijProjectDir; - } - - // Navigate to the root of the composite build tree + // Always try the root of a composite build first, since it has the highest chance var root = project.getGradle().getParent(); if (root != null) { while (root.getParent() != null) { @@ -57,7 +50,8 @@ public static File getIntellijProjectDir(Project project) { return getIntellijProjectDir(root.getRootProject().getProjectDir()); } - return null; + // As a fallback or in case of not using composite builds, try the root project folder + return getIntellijProjectDir(project.getRootDir()); } private static File getIntellijProjectDir(File gradleProjectDir) { From 8583e166b1d303d71c812ca13daa5631c68db922 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 14 Jun 2024 21:08:58 +0200 Subject: [PATCH 7/7] Do not search upwards through the project tree yet. --- .../moddevgradle/internal/utils/IdeDetection.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java index 399f332d..afd62a7b 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/IdeDetection.java @@ -55,19 +55,8 @@ public static File getIntellijProjectDir(Project project) { } private static File getIntellijProjectDir(File gradleProjectDir) { - // Search the .idea folder belonging to this Gradle project - // In includeBuild scenarios, it might be above the project. It's also possible - // that it is completely separate. var ideaDir = new File(gradleProjectDir, ".idea"); - while (!ideaDir.exists()) { - gradleProjectDir = gradleProjectDir.getParentFile(); - if (gradleProjectDir == null) { - return null; - } - ideaDir = new File(gradleProjectDir, ".idea"); - } - - return ideaDir; + return ideaDir.exists() ? ideaDir : null; } }