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:
@@ -16,12 +16,19 @@ public class Bootstrap {
|
|||||||
private static final String JAR_NAME = "zernmclauncher.jar";
|
private static final String JAR_NAME = "zernmclauncher.jar";
|
||||||
private static final String BASE_URL = "http://87.120.187.36:1582";
|
private static final String BASE_URL = "http://87.120.187.36:1582";
|
||||||
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())) {
|
||||||
@@ -77,13 +84,13 @@ public class Bootstrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
// Fallback: из build.version
|
// Fallback: из build.version
|
||||||
Path f = baseDir.resolve(VERSION_FILE);
|
Path f = baseDir.resolve(VERSION_FILE);
|
||||||
try {
|
try {
|
||||||
if (Files.exists(f)) return Files.readString(f).trim();
|
if (Files.exists(f)) return Files.readString(f).trim();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
return "0.0.0";
|
return "0.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,11 +476,11 @@ public class Bootstrap {
|
|||||||
URL url = new URL(BASE_URL + "/launcher/download/jar");
|
URL url = new URL(BASE_URL + "/launcher/download/jar");
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
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();
|
||||||
OutputStream out = new FileOutputStream(tmp.toFile())) {
|
OutputStream out = new FileOutputStream(tmp.toFile())) {
|
||||||
byte[] buf = new byte[BUFFER_SIZE];
|
byte[] buf = new byte[BUFFER_SIZE];
|
||||||
@@ -486,12 +493,12 @@ public class Bootstrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
log("JAR скачан");
|
log("JAR скачан");
|
||||||
|
|
||||||
Path backup = jarFile.resolveSibling(JAR_NAME + ".old");
|
Path backup = jarFile.resolveSibling(JAR_NAME + ".old");
|
||||||
if (Files.exists(jarFile)) Files.move(jarFile, backup, StandardCopyOption.REPLACE_EXISTING);
|
if (Files.exists(jarFile)) Files.move(jarFile, backup, StandardCopyOption.REPLACE_EXISTING);
|
||||||
Files.move(tmp, jarFile, StandardCopyOption.REPLACE_EXISTING);
|
Files.move(tmp, jarFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
if (Files.exists(backup)) Files.delete(backup);
|
if (Files.exists(backup)) Files.delete(backup);
|
||||||
|
|
||||||
Files.writeString(baseDir.resolve(VERSION_FILE), newVersion);
|
Files.writeString(baseDir.resolve(VERSION_FILE), newVersion);
|
||||||
log("Обновлено до v" + newVersion + " (JAR метод)");
|
log("Обновлено до v" + newVersion + " (JAR метод)");
|
||||||
} else {
|
} else {
|
||||||
@@ -501,8 +508,8 @@ 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);
|
||||||
log("JAR: " + jarPath);
|
log("JAR: " + jarPath);
|
||||||
@@ -544,8 +551,8 @@ 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);
|
||||||
log("JAR: " + jarPath);
|
log("JAR: " + jarPath);
|
||||||
|
|||||||
+40
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user