fix: include net.minecraft libs in classpath for Forge module path resolution

Forge version.json uses -p ${classpath} to set the module path to the same
argfile as the classpath. Previously we filtered net.minecraft:* libs from the
classpath string, which meant they were absent from the module path too, causing
ClassNotFoundException for PreparableReloadListener and other MC classes.

Now net.minecraft:* libs are included in the Forge classpath argfile so
securejarhandler can load them as modules.
This commit is contained in:
SashegDev
2026-07-13 13:43:29 +00:00
parent 1d069811e3
commit 5c8e93fd95
@@ -501,14 +501,11 @@ public class LaunchCommandBuilder {
boolean isForgeLike = "forge".equals(loaderType) || "neoforge".equals(loaderType);
for (VersionManifest.Library lib : manifest.getAllLibraries()) {
// For Forge/NeoForge: skip Minecraft client libraries — they're loaded
// through Forge's own module system (securejarhandler + module path).
// Having them on the classpath creates automatic modules that conflict
// with Forge's own module layer (split-package ResolutionException).
if (isForgeLike && lib.name.startsWith("net.minecraft:")) {
System.out.println(ZAnsi.cyan(" Skipping Minecraft lib (loaded via module system): " + lib.name));
continue;
}
// For Forge/NeoForge: include ALL libraries including net.minecraft:*
// in the classpath string. Forge version.json uses "-p ${classpath}" to
// set BOTH classpath and module path to the same string. The Minecraft
// client JAR must be on the module path so securejarhandler can load it
// as a proper module. Skipping it causes ClassNotFoundException.
Path libPath = lib.artifactPath != null ? librariesDir.resolve(lib.artifactPath) : null;
if (libPath != null && Files.exists(libPath)) {
if (isValidJar(libPath)) {