Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,10 @@ neoForge {
type = "gameTestServer"
// Client, data and server runs can use a shorthand instead:
// client()
// vanillaClient()
// data()
// server()
// vanillaServer()

// Changes the working directory used for this run.
// The default is the 'run' subdirectory of your project
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/net/neoforged/moddevgradle/dsl/RunModel.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.neoforged.moddevgradle.dsl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -57,6 +58,7 @@ public RunModel(String name, Project project, Iterable<ModModel> defaultMods) {

getLogLevel().convention(Level.INFO);
getDevLogin().convention(false);
getUseVanillaRunTemplates().convention(false);

// Build a nicer name for the IDE run configuration
boolean isSubProject = project.getRootProject() != project;
Expand Down Expand Up @@ -164,6 +166,15 @@ public void client() {
getType().set("client");
}

/**
* Equivalent to setting {@code type = "client"} and using the vanilla client run template.
*/
public void vanillaClient() {
getType().set("client");
getUseVanillaRunTemplates().set(true);
getLoadedMods().set(Collections.emptySet());
}

/**
* Equivalent to setting {@code type = "clientData"}.
*
Expand Down Expand Up @@ -191,6 +202,15 @@ public void server() {
getType().set("server");
}

/**
* Equivalent to setting {@code type = "server"} and using the vanilla server run template.
*/
public void vanillaServer() {
getType().set("server");
getUseVanillaRunTemplates().set(true);
getLoadedMods().set(Collections.emptySet());
}

/**
* Equivalent to setting {@code type = "serverData"}.
*
Expand Down Expand Up @@ -273,6 +293,11 @@ public Configuration getAdditionalRuntimeClasspathConfiguration() {
*/
public abstract Property<Boolean> getDevLogin();

/**
* Use ModDevGradle's built-in vanilla run templates instead of the configured loader's run templates.
*/
public abstract Property<Boolean> getUseVanillaRunTemplates();

@Override
public String toString() {
return "Run[" + getName() + "]";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.gradle.api.file.Directory;
import org.gradle.api.file.RegularFile;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.plugins.ide.eclipse.EclipsePlugin;
import org.gradle.plugins.ide.eclipse.model.Classpath;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
Expand Down Expand Up @@ -70,13 +69,18 @@ public void attachSources(Map<Provider<RegularFile>, Provider<RegularFile>> jarT
}

@Override
public void configureRuns(Map<RunModel, TaskProvider<PrepareRun>> prepareRunTasks,
public void configureRuns(Map<RunModel, IdeRunConfiguration> ideRunConfigurations,
Iterable<RunModel> runs) {
// Set up runs if running under buildship and in VS Code
project.afterEvaluate(ignored -> {
for (var run : runs) {
var prepareTask = prepareRunTasks.get(run).get();
addEclipseLaunchConfiguration(project, run, prepareTask);
var ideRunConfiguration = ideRunConfigurations.get(run);
var prepareTask = ideRunConfiguration.prepareRunTask().get();
if (ideRunConfiguration.usesDedicatedVanillaRuntime().get()) {
addEclipseGradleLaunchConfiguration(project, run, prepareTask, ideRunConfiguration.runTask().get());
} else {
addEclipseLaunchConfiguration(project, run, prepareTask);
}
}
});
}
Expand Down Expand Up @@ -166,6 +170,27 @@ private void addEclipseLaunchConfiguration(Project project,
writeEclipseLaunchConfig(project, launchConfigName, config);
}

private void addEclipseGradleLaunchConfiguration(Project project,
RunModel run,
PrepareRun prepareTask,
RunGameTask runTask) {
if (!prepareTask.getEnabled()) {
LOG.info("Not creating Eclipse run {} since its prepare task {} is disabled", run, prepareTask);
return;
}
if (!shouldGenerateConfigFor(run)) {
LOG.info("Not creating Eclipse run {} since it's explicitly disabled", run);
return;
}

var runIdeName = run.getIdeName().get();
var eclipseProjectName = Objects.requireNonNullElse(eclipseModel.getProject().getName(), project.getName());
var config = GradleLaunchConfig.builder(eclipseProjectName)
.tasks(runTask.getPath())
.build();
writeEclipseLaunchConfig(project, runIdeName, config);
}

protected static ModFoldersProvider getModFoldersProvider(Project project,
Provider<Set<ModModel>> modsProvider,
@Nullable Provider<ModModel> testedMod) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public final void runTaskOnProjectSync(Object task) {
ideSyncTask.configure(ideSyncTask -> ideSyncTask.dependsOn(task));
}

void configureRuns(Map<RunModel, TaskProvider<PrepareRun>> prepareRunTasks, Iterable<RunModel> runs) {}
void configureRuns(Map<RunModel, IdeRunConfiguration> ideRunConfigurations, Iterable<RunModel> runs) {}

void configureTesting(Provider<Set<ModModel>> loadedMods,
Provider<ModModel> testedMod,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.internal.DefaultTaskExecutionRequest;
import org.gradle.plugins.ide.idea.IdeaPlugin;
import org.gradle.plugins.ide.idea.model.IdeaModel;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.gradle.ext.Application;
import org.jetbrains.gradle.ext.BeforeRunTask;
import org.jetbrains.gradle.ext.Gradle;
import org.jetbrains.gradle.ext.IdeaExtPlugin;
import org.jetbrains.gradle.ext.JUnit;
import org.jetbrains.gradle.ext.ModuleRef;
Expand Down Expand Up @@ -81,7 +81,7 @@ public void attachSources(Map<Provider<RegularFile>, Provider<RegularFile>> jarT
}

@Override
public void configureRuns(Map<RunModel, TaskProvider<PrepareRun>> prepareRunTasks, Iterable<RunModel> runs) {
public void configureRuns(Map<RunModel, IdeRunConfiguration> ideRunConfigurations, Iterable<RunModel> runs) {
// IDEA Sync has no real notion of tasks or providers or similar
project.afterEvaluate(ignored -> {

Expand All @@ -93,7 +93,8 @@ public void configureRuns(Map<RunModel, TaskProvider<PrepareRun>> prepareRunTask
var outputDirectory = IntelliJOutputDirectoryValueSource.getIntellijOutputDirectory(project);

for (var run : runs) {
var prepareTask = prepareRunTasks.get(run).get();
var ideRunConfiguration = ideRunConfigurations.get(run);
var prepareTask = ideRunConfiguration.prepareRunTask().get();
if (!prepareTask.getEnabled()) {
LOG.info("Not creating IntelliJ run {} since its prepare task {} is disabled", run, prepareTask);
continue;
Expand All @@ -102,7 +103,11 @@ public void configureRuns(Map<RunModel, TaskProvider<PrepareRun>> prepareRunTask
LOG.info("Not creating IntelliJ run {} since it's explicitly disabled", run);
continue;
}
addIntelliJRunConfiguration(project, runConfigurations, outputDirectory, run, prepareTask);
if (ideRunConfiguration.usesDedicatedVanillaRuntime().get()) {
addIntelliJGradleRunConfiguration(project, runConfigurations, run, ideRunConfiguration.runTask().get());
} else {
addIntelliJRunConfiguration(project, runConfigurations, outputDirectory, run, prepareTask);
}
}
}
});
Expand Down Expand Up @@ -220,6 +225,16 @@ class GradleTasks extends BeforeRunTask {
runConfigurations.add(appRun);
}

private static void addIntelliJGradleRunConfiguration(Project project,
RunConfigurationContainer runConfigurations,
RunModel run,
RunGameTask runTask) {
var gradleRun = new ExtendedGradle(run.getIdeName().get(), getExtraIntelijRunProperties(run));
gradleRun.setProjectPath(project.getProjectDir().getAbsolutePath());
gradleRun.setTaskNames(List.of(runTask.getPath()));
runConfigurations.add(gradleRun);
}

private static String buildRelativePath(Provider<RegularFile> file, File workingDirectory) {
return workingDirectory.toPath().relativize(file.get().getAsFile().toPath()).toString().replace("\\", "/");
}
Expand Down Expand Up @@ -295,4 +310,21 @@ public ExtendedApplication(String name, Project project, Map<String, Object> ext
return m;
}
}

private static class ExtendedGradle extends Gradle {
private final Map<String, Object> extraProperties;

public ExtendedGradle(String name, Map<String, Object> extraProperties) {
super(name);
this.extraProperties = extraProperties;
}

@Override
public Map<String, ?> toMap() {
@SuppressWarnings("unchecked")
var m = (Map<String, Object>) super.toMap();
m.putAll(extraProperties);
return m;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,16 @@ public record ModDevArtifactsWorkflow(
VersionCapabilitiesInternal versionCapabilities,
TaskProvider<CreateMinecraftArtifacts> createArtifacts,
Provider<? extends Dependency> minecraftClassesDependency,
Provider<RegularFile> vanillaMinecraftClassesArtifact,
TaskProvider<DownloadAssets> downloadAssets,
Configuration runtimeDependencies,
Configuration compileDependencies,
Configuration vanillaRuntimeDependencies,
Provider<Directory> modDevBuildDir,
Provider<Directory> artifactsBuildDir) {

private static final String EXTENSION_NAME = "__internal_modDevArtifactsWorkflow";
private static final String VANILLA_CLASSES_RESULT_ID = "vanillaDeobfuscated";
public static ModDevArtifactsWorkflow get(Project project) {
var result = ExtensionUtils.findExtension(project, EXTENSION_NAME, ModDevArtifactsWorkflow.class);
if (result == null) {
Expand Down Expand Up @@ -193,6 +196,7 @@ public static ModDevArtifactsWorkflow create(Project project,
} else {
minecraftClassesDependency = createArtifacts.map(task -> project.files(task.getGameJarArtifact())).map(dependencyFactory::create);
}
var vanillaMinecraftClassesArtifact = artifactsBuildDir.map(dir -> dir.file("vanilla-runtime-" + versionCapabilities.minecraftVersion() + ".jar"));

// 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.
Expand Down Expand Up @@ -225,6 +229,18 @@ public static ModDevArtifactsWorkflow create(Project project,
}
});

var vanillaRuntimeDependencies = configurations.create("modDevVanillaRuntimeDependencies", config -> {
config.setDescription("The runtime dependencies to run vanilla Minecraft.");
config.setCanBeResolved(false);
config.setCanBeConsumed(false);
if (moddingDependencies.neoFormDependency() != null) {
config.getDependencies().add(moddingDependencies.neoFormDependency().copy()
.capabilities(c -> c.requireCapability("net.neoforged:neoform-dependencies")));
} else {
config.getDependencies().add(dependencyFactory.create("net.neoforged:minecraft-dependencies:" + versionCapabilities.minecraftVersion()));
}
});

// For IDEs that support it, link the source/binary artifacts if we use separated ones
if (!disableRecompilation && !ideIntegration.shouldUseCombinedSourcesAndClassesArtifact()) {
ideIntegration.attachSources(
Expand All @@ -239,9 +255,11 @@ public static ModDevArtifactsWorkflow create(Project project,
versionCapabilities,
createArtifacts,
minecraftClassesDependency,
vanillaMinecraftClassesArtifact,
downloadAssets,
runtimeDependencies,
compileDependencies,
vanillaRuntimeDependencies,
modDevBuildDir,
artifactsBuildDir);

Expand Down Expand Up @@ -371,6 +389,11 @@ public Provider<RegularFile> requestAdditionalMinecraftArtifact(String id, Provi
createArtifacts.flatMap(task -> task.getAdditionalResults().getting(id)));
}

public Provider<? extends Dependency> requestVanillaMinecraftClassesDependency() {
createArtifacts.configure(task -> task.getAdditionalResults().put(VANILLA_CLASSES_RESULT_ID, vanillaMinecraftClassesArtifact.map(RegularFile::getAsFile)));
return vanillaMinecraftClassesArtifact.map(path -> project.getDependencyFactory().create(project.files(path).builtBy(createArtifacts)));
}

private static <T extends Named> void setNamedAttribute(Project project, AttributeContainer attributes, Attribute<T> attribute, String value) {
attributes.attribute(attribute, project.getObjects().named(attribute.getType(), value));
}
Expand Down
Loading
Loading