fix: use patched Forge client jar instead of vanilla version jar
Vanilla 1.20.1.jar on -cp creates automatic module _1._20._1 which conflicts with Forge minecraft module. Use forge-*-client.jar from libraries/ instead (contains all MC classes). Falls back to vanilla.
This commit is contained in:
+52
-6
@@ -63,14 +63,16 @@ public class LaunchCommandBuilder {
|
||||
// always use ModLauncher as main class (version.json might have
|
||||
// BootstrapLauncher which breaks with Java module system)
|
||||
if ("forge".equals(loaderType) || "neoforge".equals(loaderType)) {
|
||||
// Forge manifest's -p is a HARDCODED list of 8 bootstrap JARs
|
||||
// (bootstraplauncher, securejarhandler, asm-*, JarJarFileSystems)
|
||||
// using ${library_directory}. Version jar is NOT on -p.
|
||||
// Put version jar on -cp only → PreparableReloadListener loadable,
|
||||
// no _1._20._1 vs minecraft split-package conflict.
|
||||
// Forge: vanilla version jar on -cp creates automatic module _1._20._1
|
||||
// which conflicts with Forge's "minecraft" module → split-package error.
|
||||
// Fix: use patched Forge client jar instead of vanilla version jar.
|
||||
// The patched jar (forge-1.20.1-47.4.20-client.jar) is created by the
|
||||
// Forge installer in libraries/ and contains all MC classes including
|
||||
// PreparableReloadListener. It is NOT listed in version.json manifest,
|
||||
// so we find and add it separately.
|
||||
String classpath;
|
||||
if (manifest != null) {
|
||||
classpath = buildClasspathFromManifest(manifest, true);
|
||||
classpath = buildClasspathFromManifest(manifest, false);
|
||||
} else {
|
||||
classpath = "";
|
||||
}
|
||||
@@ -78,6 +80,21 @@ public class LaunchCommandBuilder {
|
||||
classpath = buildVanillaClasspath();
|
||||
}
|
||||
|
||||
// Find and add the patched Forge client jar
|
||||
Path patchedJar = findPatchedForgeJar();
|
||||
if (patchedJar != null) {
|
||||
String sep = System.getProperty("os.name").toLowerCase().contains("win") ? ";" : ":";
|
||||
classpath = patchedJar.toAbsolutePath().toString() + sep + classpath;
|
||||
System.out.println(ZAnsi.green(" Added patched Forge jar: " + patchedJar.getFileName()));
|
||||
} else {
|
||||
System.out.println(ZAnsi.yellow(" No patched Forge client jar found, falling back to vanilla version jar"));
|
||||
Path versionJar = findVersionJar();
|
||||
if (versionJar != null && isValidJar(versionJar)) {
|
||||
String sep = System.getProperty("os.name").toLowerCase().contains("win") ? ";" : ":";
|
||||
classpath = versionJar.toAbsolutePath().toString() + sep + classpath;
|
||||
}
|
||||
}
|
||||
|
||||
command.add("-cp");
|
||||
String cpFile = writeClasspathFile(classpath);
|
||||
command.add(cpFile);
|
||||
@@ -640,6 +657,35 @@ public class LaunchCommandBuilder {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the patched Forge client jar in libraries/.
|
||||
* The Forge installer creates it via binarypatcher processor:
|
||||
* libraries/net/minecraftforge/forge/<version>/forge-<version>-client.jar
|
||||
* This jar contains all vanilla MC classes + Forge patches.
|
||||
* Using it instead of vanilla 1.20.1.jar avoids the _1._20._1 vs minecraft
|
||||
* split-package conflict, because the filename produces a different automatic
|
||||
* module name.
|
||||
*/
|
||||
private Path findPatchedForgeJar() {
|
||||
Path librariesDir = instance.getPath().resolve("libraries");
|
||||
String mcVersion = instance.getMinecraftVersion();
|
||||
String loaderVer = instance.getLoaderVersion();
|
||||
|
||||
String[] candidates = {
|
||||
"net/minecraftforge/forge/" + mcVersion + "-" + loaderVer + "/forge-" + mcVersion + "-" + loaderVer + "-client.jar",
|
||||
"net/neoforged/neoforge/" + mcVersion + "-" + loaderVer + "/neoforge-" + mcVersion + "-" + loaderVer + "-client.jar"
|
||||
};
|
||||
|
||||
for (String candidate : candidates) {
|
||||
Path jarPath = librariesDir.resolve(candidate);
|
||||
if (Files.exists(jarPath) && isValidJar(jarPath)) {
|
||||
return jarPath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String mavenToPath(String mavenName) {
|
||||
String[] parts = mavenName.split(":");
|
||||
if (parts.length < 3) return mavenName;
|
||||
|
||||
Reference in New Issue
Block a user