Skip to content

Commit

Permalink
New FML Startup Experiments
Browse files Browse the repository at this point in the history
  • Loading branch information
shartte committed Jan 1, 2025
1 parent f369028 commit da8510b
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ immaculate {
config = rootProject.file('codeformat/formatter-config.xml')
}


// courtesy of diffplug/spotless#240
// https://github.com/diffplug/spotless/issues/240#issuecomment-385206606
custom 'noWildcardImports', { String fileContents ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public CreateUserDevConfig() {}
@Input
abstract ListProperty<String> getModules();

@Input
abstract ListProperty<String> getJavaAgents();

@Input
abstract ListProperty<String> getTestLibraries();

Expand All @@ -62,7 +65,7 @@ public CreateUserDevConfig() {}
@TaskAction
public void writeUserDevConfig() throws IOException {
var config = new UserDevConfig(
2,
3,
"net.neoforged:neoform:%s-%s@zip".formatted(getMinecraftVersion().get(), getRawNeoFormVersion().get()),
"ats/",
"joined.lzma",
Expand All @@ -75,31 +78,28 @@ public void writeUserDevConfig() throws IOException {
getLibraries().get(),
getTestLibraries().get(),
new LinkedHashMap<>(),
getModules().get());
getModules().get(),
getJavaAgents().get()
);

for (var runType : RunType.values()) {
var launchTarget = switch (runType) {
case CLIENT -> "neoforgeclientdev";
case CLIENT_DATA -> "neoforgeclientdatadev";
case SERVER_DATA -> "neoforgeserverdatadev";
case GAME_TEST_SERVER, SERVER -> "neoforgeserverdev";
case JUNIT -> "neoforgejunitdev";
var mainClass = switch (runType) {
case CLIENT -> "net.neoforged.fml.startup.Client";
case CLIENT_DATA -> "net.neoforged.fml.startup.DataClient";
case SERVER_DATA -> "net.neoforged.fml.startup.DataServer";
case GAME_TEST_SERVER, SERVER -> "net.neoforged.fml.startup.Server";
case JUNIT -> null;
};

List<String> args = new ArrayList<>();
Collections.addAll(args,
"--launchTarget", launchTarget);

if (runType == RunType.CLIENT || runType == RunType.JUNIT) {
if (runType == RunType.CLIENT) {
// TODO: this is copied from NG but shouldn't it be the MC version?
Collections.addAll(args,
"--version", getNeoForgeVersion().get());
Collections.addAll(args, "--version", getNeoForgeVersion().get());
}

if (runType == RunType.CLIENT || runType == RunType.CLIENT_DATA || runType == RunType.JUNIT) {
Collections.addAll(args,
"--assetIndex", "{asset_index}",
"--assetsDir", "{assets_root}");
if (runType == RunType.CLIENT || runType == RunType.CLIENT_DATA) {
Collections.addAll(args, "--assetIndex", "{asset_index}", "--assetsDir", "{assets_root}");
}

Collections.addAll(args,
Expand All @@ -111,8 +111,6 @@ public void writeUserDevConfig() throws IOException {

Map<String, String> systemProperties = new LinkedHashMap<>();
systemProperties.put("java.net.preferIPv6Addresses", "system");
systemProperties.put("ignoreList", String.join(",", getIgnoreList().get()));
systemProperties.put("legacyClassPath.file", "{minecraft_classpath_file}");

if (runType == RunType.CLIENT || runType == RunType.GAME_TEST_SERVER) {
systemProperties.put("neoforge.enableGameTest", "true");
Expand All @@ -124,22 +122,19 @@ public void writeUserDevConfig() throws IOException {

config.runs().put(runType.jsonName, new UserDevRunType(
runType != RunType.JUNIT,
"cpw.mods.bootstraplauncher.BootstrapLauncher",
mainClass,
args,
List.of(
"-p", "{modules}",
"--add-modules", "ALL-MODULE-PATH",
"--add-opens", "java.base/java.util.jar=cpw.mods.securejarhandler",
"--add-opens", "java.base/java.lang.invoke=cpw.mods.securejarhandler",
"--add-exports", "java.base/sun.security.util=cpw.mods.securejarhandler",
"--add-opens", "java.base/java.util.jar=ALL-UNNAMED",
"--add-opens", "java.base/java.lang.invoke=ALL-UNNAMED",
"--add-exports", "java.base/sun.security.util=ALL-UNNAMED",
"--add-exports", "jdk.naming.dns/com.sun.jndi.dns=java.naming"),
runType == RunType.CLIENT || runType == RunType.JUNIT || runType == RunType.CLIENT_DATA,
runType == RunType.GAME_TEST_SERVER || runType == RunType.SERVER || runType == RunType.SERVER_DATA,
runType == RunType.CLIENT_DATA || runType == RunType.SERVER_DATA,
runType == RunType.CLIENT || runType == RunType.GAME_TEST_SERVER,
runType == RunType.JUNIT,
Map.of(
"MOD_CLASSES", "{source_roots}"),
Map.of("MOD_CLASSES", "{source_roots}"),
systemProperties
));
}
Expand Down Expand Up @@ -179,7 +174,10 @@ record UserDevConfig(
List<String> libraries,
List<String> testLibraries,
Map<String, UserDevRunType> runs,
List<String> modules) {}
List<String> modules,
List<String> javaAgents
) {
}

record BinpatcherConfig(
String version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ static NeoDevConfigurations createAndSetup(Project project) {
* (i.e. BootstrapLauncher and its dependencies).
*/
final Configuration moduleLibraries;
/**
* The Java Agents to attach to the running JVM when running the game.
*/
final Configuration javaAgents;
/**
* Libraries that should be accessible in mod development environments at compilation time only.
* Currently, this is only used for MixinExtras, which is already available at runtime via JiJ in the NeoForge universal jar.
Expand Down Expand Up @@ -73,6 +77,10 @@ static NeoDevConfigurations createAndSetup(Project project) {
* Resolvable {@link #moduleLibraries}.
*/
final Configuration modulePath;
/**
* Resolvable {@link #javaAgents}.
*/
final Configuration javaAgentsClasspath;
/**
* Userdev dependencies (written to a json file in the userdev jar).
* This should contain all of NeoForge's additional dependencies for userdev,
Expand Down Expand Up @@ -125,12 +133,14 @@ private NeoDevConfigurations(Project project) {
neoFormDependencies = dependencyScope(configurations, "neoFormDependencies");
libraries = dependencyScope(configurations, "libraries");
moduleLibraries = dependencyScope(configurations, "moduleLibraries");
javaAgents = dependencyScope(configurations, "javaAgents");
userdevCompileOnly = dependencyScope(configurations, "userdevCompileOnly");
userdevTestFixtures = dependencyScope(configurations, "userdevTestFixtures");

neoFormDataOnly = resolvable(configurations, "neoFormDataOnly");
neoFormClasspath = resolvable(configurations, "neoFormClasspath");
modulePath = resolvable(configurations, "modulePath");
javaAgentsClasspath = resolvable(configurations, "javaAgentsClasspath");
userdevClasspath = resolvable(configurations, "userdevClasspath");
userdevCompileOnlyClasspath = resolvable(configurations, "userdevCompileOnlyClasspath");
userdevTestClasspath = resolvable(configurations, "userdevTestClasspath");
Expand All @@ -152,6 +162,9 @@ private NeoDevConfigurations(Project project) {
modulePath.extendsFrom(moduleLibraries);
modulePath.shouldResolveConsistentlyWith(runtimeClasspath);

javaAgentsClasspath.extendsFrom(javaAgents);
javaAgentsClasspath.shouldResolveConsistentlyWith(runtimeClasspath);

userdevClasspath.extendsFrom(libraries, moduleLibraries, userdevCompileOnly);
userdevClasspath.shouldResolveConsistentlyWith(runtimeClasspath);

Expand Down
7 changes: 5 additions & 2 deletions buildSrc/src/main/java/net/neoforged/neodev/NeoDevPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ public void apply(Project project) {
task.getRawNeoFormVersion().set(rawNeoFormVersion);
task.getLibraries().addAll(DependencyUtils.configurationToGavList(configurations.userdevClasspath));
task.getModules().addAll(DependencyUtils.configurationToGavList(configurations.modulePath));
task.getJavaAgents().addAll(DependencyUtils.configurationToGavList(configurations.javaAgentsClasspath));
task.getTestLibraries().addAll(DependencyUtils.configurationToGavList(configurations.userdevTestClasspath));
task.getTestLibraries().add(neoForgeVersion.map(v -> "net.neoforged:testframework:" + v));
task.getIgnoreList().addAll(configurations.userdevCompileOnlyClasspath.getIncoming().getArtifacts().getResolvedArtifacts().map(results -> {
Expand Down Expand Up @@ -285,6 +286,7 @@ public void apply(Project project) {
// ${version_name}.jar will be filled out by the launcher. It corresponds to the raw SRG Minecraft client jar.
task.getIgnoreList().addAll("client-extra", "${version_name}.jar");
task.setModules(configurations.modulePath);
task.setJavaAgents(configurations.javaAgentsClasspath);
task.getLauncherProfile().set(neoDevBuildDir.map(dir -> dir.file("launcher-profile.json")));
});

Expand Down Expand Up @@ -316,11 +318,11 @@ public void apply(Project project) {
});

var createWindowsServerArgsFile = tasks.register("createWindowsServerArgsFile", CreateArgsFile.class, task -> {
task.setLibraries(";", configurations.launcherProfileClasspath, configurations.modulePath);
task.getPathSeparator().set(";");
task.getArgsFile().set(neoDevBuildDir.map(dir -> dir.file("windows-server-args.txt")));
});
var createUnixServerArgsFile = tasks.register("createUnixServerArgsFile", CreateArgsFile.class, task -> {
task.setLibraries(":", configurations.launcherProfileClasspath, configurations.modulePath);
task.getPathSeparator().set(":");
task.getArgsFile().set(neoDevBuildDir.map(dir -> dir.file("unix-server-args.txt")));
});

Expand All @@ -339,6 +341,7 @@ public void apply(Project project) {
return results.stream().map(r -> r.getFile().getName()).toList();
}));
task.getRawServerJar().set(createCleanArtifacts.flatMap(CreateCleanArtifacts::getRawServerJar));
task.setLibraries(configurations.launcherProfileClasspath, configurations.modulePath, configurations.javaAgentsClasspath);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -44,21 +45,24 @@ public CreateArgsFile() {}
public abstract Property<String> getRawNeoFormVersion();

@Input
protected abstract Property<String> getPathSeparator();
public abstract Property<String> getPathSeparator();

@Input
protected abstract Property<String> getModules();
protected abstract ListProperty<String> getModules();

@Input
protected abstract ListProperty<String> getJavaAgents();

@Input
public abstract ListProperty<String> getIgnoreList();

@Input
protected abstract Property<String> getClasspath();
protected abstract ListProperty<String> getClasspath();

public void setLibraries(String separator, Configuration classpath, Configuration modulePath) {
getPathSeparator().set(separator);
getClasspath().set(DependencyUtils.configurationToClasspath(classpath, "libraries/", separator));
getModules().set(DependencyUtils.configurationToClasspath(modulePath, "libraries/", separator));
public void setLibraries(Configuration classpath, Configuration modulePath, Configuration javaAgents) {
getClasspath().set(DependencyUtils.configurationToClasspathItems(classpath, "libraries/"));
getModules().set(DependencyUtils.configurationToClasspathItems(modulePath, "libraries/"));
getJavaAgents().set(DependencyUtils.configurationToClasspathItems(javaAgents, "libraries/"));
}

@InputFile
Expand All @@ -71,13 +75,17 @@ public void setLibraries(String separator, Configuration classpath, Configuratio
protected abstract ArchiveOperations getArchiveOperations();

private String resolveClasspath() throws IOException {
var ourClasspath = getClasspath().get() + getPathSeparator().get()
+ "libraries/net/minecraft/server/%s/server-%s-extra.jar".formatted(
getRawNeoFormVersion().get(), getRawNeoFormVersion().get());
String pathSeparator = getPathSeparator().get();
var classpathItems = new ArrayList<>(getClasspath().get());
classpathItems.add("libraries/net/minecraft/server/%s/server-%s-extra.jar".formatted(
getRawNeoFormVersion().get(), getRawNeoFormVersion().get()));

// Remove any java agents, since they automatically are on the classpath
classpathItems.removeAll(getJavaAgents().get());

// The raw server jar also contains its own classpath.
// We want to make sure that our versions of the libraries are used when there is a conflict.
var ourClasspathEntries = Stream.of(ourClasspath.split(getPathSeparator().get()))
var ourClasspathEntries = classpathItems.stream()
.map(CreateArgsFile::stripVersionSuffix)
.collect(Collectors.toSet());

Expand All @@ -89,9 +97,10 @@ private String resolveClasspath() throws IOException {
.filter(path -> !ourClasspathEntries.contains(stripVersionSuffix(path)))
// Exclude the actual MC server jar, which is under versions/
.filter(path -> path.startsWith("libraries/"))
.collect(Collectors.joining(getPathSeparator().get()));
.collect(Collectors.joining(pathSeparator));

return ourClasspath + getPathSeparator().get() + filteredServerClasspath;
classpathItems.add(filteredServerClasspath);
return String.join(pathSeparator, classpathItems);
}

// Example:
Expand All @@ -104,14 +113,18 @@ private static String stripVersionSuffix(String classpathEntry) {

@TaskAction
public void createArgsFile() throws IOException {
var pathSeparator = getPathSeparator().get();

var jvmOptions = new ArrayList<String>();
for (var javaAgent : getJavaAgents().get()) {
jvmOptions.add("-javaagent:" + javaAgent);
}

jvmOptions.add("-cp");
jvmOptions.add(resolveClasspath());

var replacements = new HashMap<String, String>();
replacements.put("@MODULE_PATH@", getModules().get());
replacements.put("@MODULES@", "ALL-MODULE-PATH");
replacements.put("@IGNORE_LIST@", String.join(",", getIgnoreList().get()));
replacements.put("@PLUGIN_LAYER_LIBRARIES@", "");
replacements.put("@GAME_LAYER_LIBRARIES@", "");
replacements.put("@CLASS_PATH@", resolveClasspath());
replacements.put("@TASK@", "neoforgeserver");
replacements.put("@JVM_OPTIONS@", String.join("\n", jvmOptions));
replacements.put("@FORGE_VERSION@", getNeoForgeVersion().get());
replacements.put("@FML_VERSION@", getFmlVersion().get());
replacements.put("@MC_VERSION@", getMinecraftVersion().get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,17 @@ public void setLibraries(Configuration libraries) {
public abstract ListProperty<String> getIgnoreList();

@Input
protected abstract Property<String> getModulePath();
protected abstract ListProperty<String> getModulePath();

@Input
protected abstract ListProperty<String> getJavaAgentsClasspath();

public void setModules(Configuration modules) {
getModulePath().set(DependencyUtils.configurationToClasspath(modules, "${library_directory}/", "${classpath_separator}"));
getModulePath().set(DependencyUtils.configurationToClasspathItems(modules, "${library_directory}/"));
}

public void setJavaAgents(Configuration javaAgents) {
getJavaAgentsClasspath().set(DependencyUtils.configurationToClasspathItems(javaAgents, "${library_directory}/"));
}

@OutputFile
Expand All @@ -82,17 +89,26 @@ public void createLauncherProfile() throws IOException {

var jvmArguments = new ArrayList<>(List.of(
"-Djava.net.preferIPv6Addresses=system",
"-DignoreList=" + String.join(",", getIgnoreList().get()),
"-DlibraryDirectory=${library_directory}"));
if (!getIgnoreList().get().isEmpty()) {
jvmArguments.add("-DignoreList=" + String.join(",", getIgnoreList().get()));
}

var modulePath = getModulePath().get();
if (!modulePath.isEmpty()) {
jvmArguments.add("-p");
jvmArguments.add(String.join("${classpath_separator}", modulePath));
}

jvmArguments.add("-p");
jvmArguments.add(getModulePath().get());
var javaAgents = getJavaAgentsClasspath().get();
for (var javaAgent : javaAgents) {
jvmArguments.add("-javaagent:" + javaAgent);
}

jvmArguments.addAll(List.of(
"--add-modules", "ALL-MODULE-PATH",
"--add-opens", "java.base/java.util.jar=cpw.mods.securejarhandler",
"--add-opens", "java.base/java.lang.invoke=cpw.mods.securejarhandler",
"--add-exports", "java.base/sun.security.util=cpw.mods.securejarhandler",
"--add-opens", "java.base/java.util.jar=ALL-UNNAMED",
"--add-opens", "java.base/java.lang.invoke=ALL-UNNAMED",
"--add-exports", "java.base/sun.security.util=ALL-UNNAMED",
"--add-exports", "jdk.naming.dns/com.sun.jndi.dns=java.naming"));

var arguments = new LinkedHashMap<String, List<String>>();
Expand All @@ -104,7 +120,7 @@ public void createLauncherProfile() throws IOException {
time,
time,
"release",
"cpw.mods.bootstraplauncher.BootstrapLauncher",
"net.neoforged.fml.startup.Client",
getMinecraftVersion().get(),
arguments,
libraries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@ public static Provider<List<String>> configurationToGavList(Configuration config
}

/**
* Turns a configuration into a classpath string,
* Turns a configuration into a list of classpath items,
* assuming that the contents of the configuration are installed following the Maven directory layout.
*
* @param prefix string to add in front of each classpath entry
* @param separator separator to add between each classpath entry
*/
public static Provider<String> configurationToClasspath(Configuration configuration, String prefix, String separator) {
public static Provider<List<String>> configurationToClasspathItems(Configuration configuration, String prefix) {
return configuration.getIncoming().getArtifacts().getResolvedArtifacts().map(
results -> results.stream()
.map(artifact -> prefix + guessMavenIdentifier(artifact).repositoryPath())
.collect(Collectors.joining(separator))
.distinct()
.toList()
);
}
}
Loading

0 comments on commit da8510b

Please sign in to comment.