From 0a388c90fd5e62aa8cca9d3c2e6f726e7a43bbc3 Mon Sep 17 00:00:00 2001 From: SashegDev Date: Mon, 13 Jul 2026 16:27:29 +0000 Subject: [PATCH] Fix 11: Remove forge- from ignoreList, let forge client jar create minecraft module Instead of copying the vanilla jar to versions// and adding it to -cp (Fix 9/10), we now simply remove forge- from the -DignoreList pattern. This allows securejarhandler to process forge-1.20.1-47.4.20-client.jar on the classpath, which has Automatic-Module-Name: minecraft in its MANIFEST, and create the minecraft module from it. The forge client jar contains all patched MC classes, so PreparableReloadListener and all other vanilla classes are accessible in the minecraft module. No duplicate module creation, no split-package errors. --- .../launch/LaunchCommandBuilder.java | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/launcher/launcher/src/main/java/sashegdev/zernmc/launcher/minecraft/launch/LaunchCommandBuilder.java b/launcher/launcher/src/main/java/sashegdev/zernmc/launcher/minecraft/launch/LaunchCommandBuilder.java index c58add8..974eea6 100644 --- a/launcher/launcher/src/main/java/sashegdev/zernmc/launcher/minecraft/launch/LaunchCommandBuilder.java +++ b/launcher/launcher/src/main/java/sashegdev/zernmc/launcher/minecraft/launch/LaunchCommandBuilder.java @@ -63,18 +63,12 @@ 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)) { - // Ensure securejarhandler can create the "minecraft" module. - // The Forge installer only creates versions//.json, - // NOT the jar. We copy the vanilla version jar there so - // securejarhandler finds it and creates the "minecraft" module. - ensureVersionJarForForge(); - - // Build classpath from manifest libraries + the copied version jar. - // The copied jar (e.g. 1.20.1-forge-47.4.20.jar) does NOT match the - // "-DignoreList" pattern "forge-" (it starts with "1", not "forge-"), - // so securejarhandler will include it in the module layer. - // It also won't create automatic module "_1._20._1" because the - // filename is "1.20.1-forge-47.4.20.jar", not "1.20.1.jar". + // Build classpath from manifest libraries only. + // The forge client jar (forge-*-client.jar) on the classpath + // contains the patched Minecraft classes and has + // Automatic-Module-Name: minecraft in its MANIFEST. + // We modify the ignoreList below to NOT exclude it, + // so securejarhandler creates the "minecraft" module from it. String classpath; if (manifest != null) { classpath = buildClasspathFromManifest(manifest, false); @@ -85,31 +79,38 @@ public class LaunchCommandBuilder { classpath = buildVanillaClasspath(); } - // Add the copied version jar to classpath (if it exists). - // securejarhandler scans classpath JARs and creates modules. - // The jar name "1.20.1-forge-47.4.20.jar" is NOT in ignoreList, - // so it becomes a proper module with Automatic-Module-Name: minecraft. - Path copiedVersionJar = instance.getPath().resolve("versions") - .resolve(getVersionId()).resolve(getVersionId() + ".jar"); - if (Files.exists(copiedVersionJar) && isValidJar(copiedVersionJar)) { - String sep = System.getProperty("os.name").toLowerCase().contains("win") ? ";" : ":"; - classpath = copiedVersionJar.toAbsolutePath().toString() + sep + classpath; - System.out.println(ZAnsi.green(" Added version jar for minecraft module: " + copiedVersionJar.getFileName())); - } - command.add("-cp"); String cpFile = writeClasspathFile(classpath); command.add(cpFile); - // Add JVM arguments from version.json manifest as-is. - // Forge's -p is a HARDCODED list of 8 bootstrap JARs (bootstraplauncher, - // securejarhandler, asm-*, JarJarFileSystems) — NOT ${classpath}. - // Do NOT intercept it. + // Add JVM arguments from version.json manifest. + // Forge's -p is a HARDCODED list of 8 bootstrap JARs + // (bootstraplauncher, securejarhandler, asm-*, JarJarFileSystems). + // Intercept -DignoreList to remove "forge-" pattern, which + // blocks the forge client jar (forge-*-client.jar) from being + // processed by securejarhandler into the "minecraft" module. if (manifest != null) { Map vars = buildVariableMap(options); vars.put("classpath", cpFile); for (String arg : manifest.getJvmArguments()) { - command.add(resolveVariable(arg, vars)); + String resolved = resolveVariable(arg, vars); + if (resolved.startsWith("-DignoreList=")) { + String value = resolved.substring("-DignoreList=".length()); + // Remove forge- from the comma-separated list: + // - ,forge-, in the middle → just the comma + // - ,forge- at the end → remove + // - forge-, at the start → remove + String modified = value + .replace(",forge-,", ",") + .replace(",forge-", "") + .replace("forge-,", ""); + if (modified.equals("forge-")) modified = ""; + if (!modified.equals(value)) { + System.out.println(ZAnsi.green(" Removed 'forge-' from ignoreList")); + } + resolved = "-DignoreList=" + modified; + } + command.add(resolved); } }