Fix: Fabric loader launch and Bootstrap paths

- Add Fabric support in LaunchCommandBuilder.findVersionJson()
- Fix Bootstrap to properly use bin/ directory for launcher JAR
- Fix server.py to accept both ZernMC-win-*.zip and ZernMCLauncher-*.zip
- Add debug output for version.json resolution
This commit is contained in:
SashegDev
2026-05-08 11:04:45 +00:00
parent e5948b5337
commit ec551ab2e3
3 changed files with 62 additions and 14 deletions
@@ -18,10 +18,17 @@ public class Bootstrap {
private static final int BUFFER_SIZE = 8192; private static final int BUFFER_SIZE = 8192;
private static Path baseDir; private static Path baseDir;
private static Path binDir;
private static Path logDir; private static Path logDir;
private static Path getLauncherJar() {
return binDir.resolve(JAR_NAME);
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
baseDir = Paths.get("").toAbsolutePath(); baseDir = Paths.get("").toAbsolutePath();
binDir = baseDir.resolve("bin");
Files.createDirectories(binDir);
logDir = baseDir.resolve("logs"); logDir = baseDir.resolve("logs");
Files.createDirectories(logDir); Files.createDirectories(logDir);
@@ -65,7 +72,7 @@ public class Bootstrap {
private static String readCurrentVersion() { private static String readCurrentVersion() {
// Читаем версию из манифеста zernmclauncher.jar в папке bin/ // Читаем версию из манифеста zernmclauncher.jar в папке bin/
Path launcherJar = baseDir.resolve("bin").resolve("zernmclauncher.jar"); Path launcherJar = getLauncherJar();
try { try {
if (Files.exists(launcherJar)) { if (Files.exists(launcherJar)) {
try (FileInputStream fis = new FileInputStream(launcherJar.toFile())) { try (FileInputStream fis = new FileInputStream(launcherJar.toFile())) {
@@ -471,7 +478,7 @@ public class Bootstrap {
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) { if (conn.getResponseCode() == 200) {
Path jarFile = baseDir.resolve(JAR_NAME); Path jarFile = getLauncherJar();
Path tmp = jarFile.resolveSibling("zernmc-launcher-new.jar"); Path tmp = jarFile.resolveSibling("zernmc-launcher-new.jar");
try (InputStream in = conn.getInputStream(); try (InputStream in = conn.getInputStream();
@@ -501,7 +508,7 @@ public class Bootstrap {
private static void launchJFX() throws Exception { private static void launchJFX() throws Exception {
Path javaBin = findJava(); Path javaBin = findJava();
Path jarPath = baseDir.resolve(JAR_NAME); Path jarPath = getLauncherJar();
log("Запуск JFX режима..."); log("Запуск JFX режима...");
log("Java: " + javaBin); log("Java: " + javaBin);
@@ -544,7 +551,7 @@ public class Bootstrap {
private static void launchCLI() throws Exception { private static void launchCLI() throws Exception {
Path javaBin = findJava(); Path javaBin = findJava();
Path jarPath = baseDir.resolve(JAR_NAME); Path jarPath = getLauncherJar();
log("Запуск CLI режима..."); log("Запуск CLI режима...");
log("Java: " + javaBin); log("Java: " + javaBin);
@@ -63,6 +63,10 @@ public class LaunchCommandBuilder {
JSONObject json = new JSONObject(content); JSONObject json = new JSONObject(content);
System.out.println(ZAnsi.green("Найден version.json: " + versionJson.getFileName())); System.out.println(ZAnsi.green("Найден version.json: " + versionJson.getFileName()));
return new VersionManifest(json); return new VersionManifest(json);
} else {
System.out.println(ZAnsi.yellow("version.json не найден для " + instance.getName()));
System.out.println(ZAnsi.yellow(" loaderType=" + instance.getLoaderType() + " mcVersion=" + instance.getMinecraftVersion() + " loaderVersion=" + instance.getLoaderVersion()));
System.out.println(ZAnsi.yellow(" path=" + instance.getPath()));
} }
} catch (Exception e) { } catch (Exception e) {
System.out.println(ZAnsi.yellow("Не удалось загрузить version.json: " + e.getMessage())); System.out.println(ZAnsi.yellow("Не удалось загрузить version.json: " + e.getMessage()));
@@ -76,6 +80,38 @@ public class LaunchCommandBuilder {
String mcVersion = instance.getMinecraftVersion(); String mcVersion = instance.getMinecraftVersion();
String loaderVersion = instance.getLoaderVersion(); String loaderVersion = instance.getLoaderVersion();
if ("fabric".equals(loaderType)) {
String versionId = getVersionId();
// Try fabric version ID first
Path jsonPath = versionsDir.resolve(versionId).resolve(versionId + ".json");
if (Files.exists(jsonPath)) {
return jsonPath;
}
// Try instance's fabricVersionId if available
String fabricId = instance.getFabricVersionId();
if (fabricId != null && !fabricId.isEmpty()) {
Path fabricPath = versionsDir.resolve(fabricId).resolve(fabricId + ".json");
if (Files.exists(fabricPath)) {
return fabricPath;
}
}
// Try generic fabric pattern
try {
if (Files.exists(versionsDir)) {
try (var stream = Files.list(versionsDir)) {
return stream
.filter(Files::isDirectory)
.filter(dir -> dir.getFileName().toString().contains("fabric"))
.filter(dir -> dir.getFileName().toString().contains(mcVersion))
.findFirst()
.map(dir -> dir.resolve(dir.getFileName().toString() + ".json"))
.filter(Files::exists)
.orElse(null);
}
}
} catch (Exception ignored) {}
}
if ("forge".equals(loaderType) || "neoforge".equals(loaderType)) { if ("forge".equals(loaderType) || "neoforge".equals(loaderType)) {
String[] candidates = { String[] candidates = {
getVersionId(), getVersionId(),
@@ -152,6 +188,10 @@ public class LaunchCommandBuilder {
String loaderType = instance.getLoaderType().toLowerCase(); String loaderType = instance.getLoaderType().toLowerCase();
if ("fabric".equals(loaderType)) { if ("fabric".equals(loaderType)) {
return "net.fabricmc.loader.impl.launch.knot.KnotClient"; return "net.fabricmc.loader.impl.launch.knot.KnotClient";
} else if ("forge".equals(loaderType)) {
return "net.minecraftforge.client.main.ForgeClient";
} else if ("neoforge".equals(loaderType)) {
return "cpw.mods.bootstraplauncher.BootstrapLauncher";
} }
return "net.minecraft.client.main.Main"; return "net.minecraft.client.main.Main";
} }
+2 -1
View File
@@ -1080,7 +1080,8 @@ async def download_launcher_exe():
@app.get("/launcher/download/zip/{filename}") @app.get("/launcher/download/zip/{filename}")
async def download_launcher_zip(filename: str): async def download_launcher_zip(filename: str):
"""Download specific launcher ZIP archive""" """Download specific launcher ZIP archive"""
if ".." in filename or not filename.startswith("ZernMCLauncher-") or not filename.endswith(".zip"): valid_patterns = ["ZernMCLauncher-", "ZernMC-win-"]
if ".." in filename or not any(filename.startswith(p) for p in valid_patterns) or not filename.endswith(".zip"):
raise HTTPException(400, "Invalid filename") raise HTTPException(400, "Invalid filename")
file_path = BUILDS_DIR / filename file_path = BUILDS_DIR / filename