v1.0.16.2 — fix NeoForge/Forge install (bundled JRE for installers, visible progress in JFX UI, skip existing vanilla files), hide zernmc-cli.exe from users
This commit is contained in:
@@ -159,6 +159,7 @@
|
||||
<headerType>gui</headerType>
|
||||
<dontWrapJar>false</dontWrapJar>
|
||||
<mainClass>me.sashegdev.zernmc.launcher.Bootstrap</mainClass>
|
||||
<cmdLine>--jfx</cmdLine>
|
||||
<jre>
|
||||
<path>lib/jre21</path>
|
||||
<minVersion>21</minVersion>
|
||||
@@ -283,20 +284,16 @@
|
||||
ZernMC Launcher
|
||||
|
||||
Files:
|
||||
- zernmc.exe - Main launcher with GUI (no console window)
|
||||
- zernmc-cli.exe - CLI version for servers/advanced users (with console)
|
||||
- zernmc.exe - Main launcher with GUI
|
||||
|
||||
How to use GUI:
|
||||
How to use:
|
||||
Just run zernmc.exe
|
||||
|
||||
How to use CLI:
|
||||
Run from command line: zernmc-cli.exe --cli
|
||||
</echo>
|
||||
|
||||
<!-- Создаём один архив со всем -->
|
||||
<zip destfile="../../server/builds/ZernMC-win-${revision}.${hotfix}.zip"
|
||||
basedir="../../server/builds"
|
||||
includes="zernmc.exe,zernmc-cli.exe,bin/**,assets/**,lib/**,README.txt"
|
||||
includes="zernmc.exe,bin/**,assets/**,lib/**,README.txt"
|
||||
excludes="build.version,*.jar"/>
|
||||
</target>
|
||||
</configuration>
|
||||
|
||||
+18
-17
@@ -1,8 +1,9 @@
|
||||
package me.sashegdev.zernmc.launcher.minecraft.installer;
|
||||
|
||||
import me.sashegdev.zernmc.launcher.minecraft.Instance;
|
||||
import me.sashegdev.zernmc.launcher.utils.JavaResolver;
|
||||
import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
|
||||
import me.sashegdev.zernmc.launcher.utils.ProgressBar;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -19,7 +20,7 @@ public class FabricInstaller {
|
||||
}
|
||||
|
||||
public boolean install(String minecraftVersion, String loaderVersion) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Installing Fabric " + loaderVersion + " for Minecraft " + minecraftVersion));
|
||||
LauncherLogger.info("Installing Fabric " + loaderVersion + " for Minecraft " + minecraftVersion);
|
||||
|
||||
Path instancePath = instance.getPath();
|
||||
cleanOldFabricLoaders();
|
||||
@@ -27,7 +28,7 @@ public class FabricInstaller {
|
||||
VersionInstaller versionInstaller = new VersionInstaller(instancePath);
|
||||
String assetIndex = versionInstaller.install(minecraftVersion);
|
||||
|
||||
System.out.println(ZAnsi.green("Asset index obtained: " + assetIndex));
|
||||
LauncherLogger.info("Asset index obtained: " + assetIndex);
|
||||
|
||||
instance.setAssetIndex(assetIndex);
|
||||
instance.setMinecraftVersion(minecraftVersion);
|
||||
@@ -46,12 +47,12 @@ public class FabricInstaller {
|
||||
|
||||
preDownloadFabricLibraries(minecraftVersion, loaderVersion);
|
||||
|
||||
System.out.println(ZAnsi.cyan("Running Fabric Installer..."));
|
||||
LauncherLogger.info("Running Fabric Installer...");
|
||||
|
||||
String fabricVersionId = "fabric-loader-" + loaderVersion + "-" + minecraftVersion;
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
"java", "-jar", installerJar.toAbsolutePath().toString(),
|
||||
JavaResolver.getJavaExecutable(), "-jar", installerJar.toAbsolutePath().toString(),
|
||||
"client",
|
||||
"-dir", instancePath.toAbsolutePath().toString(),
|
||||
"-mcversion", minecraftVersion,
|
||||
@@ -66,20 +67,20 @@ public class FabricInstaller {
|
||||
boolean finished = process.waitFor(10, TimeUnit.MINUTES);
|
||||
if (!finished) {
|
||||
process.destroyForcibly();
|
||||
System.out.println(ZAnsi.brightRed("Fabric Installer timed out after 10 minutes"));
|
||||
LauncherLogger.error("Fabric Installer timed out after 10 minutes");
|
||||
return false;
|
||||
}
|
||||
int exitCode = process.exitValue();
|
||||
|
||||
if (exitCode != 0) {
|
||||
System.out.println(ZAnsi.brightRed("Fabric Installer failed (code " + exitCode + ")"));
|
||||
LauncherLogger.error("Fabric Installer failed (code " + exitCode + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
Path fabricVersionDir = instancePath.resolve("versions").resolve(fabricVersionId);
|
||||
|
||||
if (Files.exists(fabricVersionDir)) {
|
||||
System.out.println(ZAnsi.brightGreen("Fabric installed successfully!"));
|
||||
LauncherLogger.info("Fabric installed successfully!");
|
||||
|
||||
instance.setLoaderType("fabric");
|
||||
instance.setLoaderVersion(loaderVersion);
|
||||
@@ -91,7 +92,7 @@ public class FabricInstaller {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed("Fabric Installer ran, but version not found."));
|
||||
LauncherLogger.error("Fabric Installer ran, but version not found.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +101,7 @@ public class FabricInstaller {
|
||||
try {
|
||||
ZHttpClient.downloadFile(url, target);
|
||||
} catch (Exception e) {
|
||||
System.out.println(ZAnsi.yellow("Failed to download Fabric Installer: " + e.getMessage()));
|
||||
LauncherLogger.warn("Failed to download Fabric Installer: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +133,7 @@ public class FabricInstaller {
|
||||
|
||||
ZHttpClient.repairLibrariesFromJson(loaderJson, instance.getPath());
|
||||
} catch (Exception e) {
|
||||
System.out.println(ZAnsi.yellow("Pre-download of Fabric libraries incomplete: " + e.getMessage()));
|
||||
LauncherLogger.warn("Pre-download of Fabric libraries incomplete: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ public class FabricInstaller {
|
||||
Path versionJson = fabricVersionDir.resolve(fabricVersionDir.getFileName() + ".json");
|
||||
|
||||
if (!Files.exists(versionJson)) {
|
||||
System.out.println(ZAnsi.yellow("Version JSON file not found: " + versionJson));
|
||||
LauncherLogger.warn("Version JSON file not found: " + versionJson);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ public class FabricInstaller {
|
||||
|
||||
// Check and fix asset index
|
||||
if (!content.contains("\"assets\":\"" + assetIndex + "\"")) {
|
||||
System.out.println(ZAnsi.yellow("Fixing asset index in version JSON file..."));
|
||||
LauncherLogger.warn("Fixing asset index in version JSON file...");
|
||||
|
||||
// Replace assets with correct value
|
||||
content = content.replaceAll("\"assets\":\\s*\"[^\"]*\"", "\"assets\": \"" + assetIndex + "\"");
|
||||
@@ -159,9 +160,9 @@ public class FabricInstaller {
|
||||
}
|
||||
|
||||
Files.writeString(versionJson, content);
|
||||
System.out.println(ZAnsi.green("Asset index fixed to: " + assetIndex));
|
||||
LauncherLogger.info("Asset index fixed to: " + assetIndex);
|
||||
} else {
|
||||
System.out.println(ZAnsi.green("Asset index in version JSON is correct: " + assetIndex));
|
||||
LauncherLogger.info("Asset index in version JSON is correct: " + assetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ public class FabricInstaller {
|
||||
Path librariesDir = instance.getPath().resolve("libraries/net/fabricmc/fabric-loader");
|
||||
if (!Files.exists(librariesDir)) return;
|
||||
|
||||
System.out.println(ZAnsi.yellow("Cleaning old Fabric Loader versions..."));
|
||||
LauncherLogger.warn("Cleaning old Fabric Loader versions...");
|
||||
|
||||
try (var stream = Files.walk(librariesDir)) {
|
||||
stream.filter(Files::isDirectory)
|
||||
@@ -195,7 +196,7 @@ public class FabricInstaller {
|
||||
int end = xml.indexOf("</latest>", start);
|
||||
return xml.substring(start, end).trim();
|
||||
} catch (Exception e) {
|
||||
System.out.println(ZAnsi.yellow("Error getting Fabric Installer version: " + e.getMessage()));
|
||||
LauncherLogger.warn("Error getting Fabric Installer version: " + e.getMessage());
|
||||
throw new Exception("Failed to get Fabric Installer version", e);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-27
@@ -1,8 +1,9 @@
|
||||
package me.sashegdev.zernmc.launcher.minecraft.installer;
|
||||
|
||||
import me.sashegdev.zernmc.launcher.minecraft.Instance;
|
||||
import me.sashegdev.zernmc.launcher.utils.JavaResolver;
|
||||
import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
|
||||
import me.sashegdev.zernmc.launcher.utils.ProgressBar;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
@@ -19,16 +20,16 @@ public class ForgeInstaller {
|
||||
}
|
||||
|
||||
public boolean install(String mcVersion, String forgeVersion) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Installing Forge " + forgeVersion + " for Minecraft " + mcVersion));
|
||||
LauncherLogger.info("Installing Forge " + forgeVersion + " for Minecraft " + mcVersion);
|
||||
|
||||
// Step 1: Install vanilla and get real assetIndex
|
||||
System.out.println(ZAnsi.cyan("Installing base Minecraft version " + mcVersion + "..."));
|
||||
LauncherLogger.info("Installing base Minecraft version " + mcVersion + "...");
|
||||
VersionInstaller vanillaInstaller = new VersionInstaller(instance.getPath());
|
||||
|
||||
String assetIndex = vanillaInstaller.install(mcVersion);
|
||||
|
||||
if (assetIndex == null || assetIndex.isEmpty()) {
|
||||
System.out.println(ZAnsi.brightRed("Failed to install base Minecraft version"));
|
||||
LauncherLogger.error("Failed to install base Minecraft version");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -44,12 +45,12 @@ public class ForgeInstaller {
|
||||
|
||||
Path installerJar = instance.getPath().resolve("forge-installer.jar");
|
||||
|
||||
System.out.println(ZAnsi.cyan("Downloading Forge Installer..."));
|
||||
LauncherLogger.info("Downloading Forge Installer...");
|
||||
downloadFileWithProgress(installerUrl, installerJar);
|
||||
|
||||
// Step 4: Run Forge Installer and show its output
|
||||
System.out.println(ZAnsi.cyan("Running Forge Installer..."));
|
||||
System.out.println(ZAnsi.yellow("This may take a few minutes. Please wait...\n"));
|
||||
LauncherLogger.info("Running Forge Installer...");
|
||||
LauncherLogger.info("This may take a few minutes. Please wait...");
|
||||
|
||||
boolean success = runForgeInstaller(installerJar);
|
||||
|
||||
@@ -59,10 +60,10 @@ public class ForgeInstaller {
|
||||
try {
|
||||
downloadMissingLibraries(mcVersion, forgeVersion);
|
||||
} catch (Exception e) {
|
||||
System.out.println(ZAnsi.yellow("Warning: could not download some libraries: " + e.getMessage()));
|
||||
LauncherLogger.warn("Warning: could not download some libraries: " + e.getMessage());
|
||||
}
|
||||
|
||||
System.out.println(ZAnsi.brightGreen("\nForge " + forgeVersion + " installed successfully!"));
|
||||
LauncherLogger.info("\nForge " + forgeVersion + " installed successfully!");
|
||||
instance.setMinecraftVersion(mcVersion);
|
||||
instance.setLoaderType("forge");
|
||||
instance.setLoaderVersion(forgeVersion);
|
||||
@@ -71,7 +72,7 @@ public class ForgeInstaller {
|
||||
Files.deleteIfExists(installerJar);
|
||||
return true;
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed("\nError installing Forge!"));
|
||||
LauncherLogger.error("\nError installing Forge!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +88,7 @@ public class ForgeInstaller {
|
||||
}
|
||||
""";
|
||||
Files.writeString(profilePath, minimalProfile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
System.out.println(ZAnsi.yellow("Created launcher_profiles.json"));
|
||||
LauncherLogger.info("Created launcher_profiles.json");
|
||||
}
|
||||
|
||||
private void downloadFileWithProgress(String url, Path target) throws Exception {
|
||||
@@ -102,10 +103,10 @@ public class ForgeInstaller {
|
||||
int attempt = 1;
|
||||
|
||||
while (attempt <= maxRetries) {
|
||||
System.out.println(ZAnsi.cyan("Attempt " + attempt + " of " + maxRetries));
|
||||
LauncherLogger.info("Attempt " + attempt + " of " + maxRetries);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
"java",
|
||||
JavaResolver.getJavaExecutable(),
|
||||
"-jar",
|
||||
installerJar.toAbsolutePath().toString(),
|
||||
"--installClient",
|
||||
@@ -131,18 +132,18 @@ public class ForgeInstaller {
|
||||
|
||||
// Format Forge Installer output
|
||||
if (line.contains("Downloading") || line.contains("Extracting")) {
|
||||
System.out.println(ZAnsi.blue(" -> " + line));
|
||||
LauncherLogger.info(" -> " + line);
|
||||
} else if (line.contains("SUCCESS") || line.contains("successfully")) {
|
||||
System.out.println(ZAnsi.brightGreen(" + " + line));
|
||||
LauncherLogger.info(" + " + line);
|
||||
} else if (line.contains("WARNING") || line.contains("warning")) {
|
||||
System.out.println(ZAnsi.yellow(" ! " + line));
|
||||
LauncherLogger.warn(" ! " + line);
|
||||
} else if (line.contains("ERROR") || line.contains("error") || line.contains("failed") || line.contains("timed out")) {
|
||||
System.out.println(ZAnsi.brightRed(" X " + line));
|
||||
LauncherLogger.error(" X " + line);
|
||||
if (line.contains("timed out") || line.contains("failed to download")) {
|
||||
hasErrors = true;
|
||||
}
|
||||
} else if (!line.isBlank()) {
|
||||
System.out.println(" " + line);
|
||||
LauncherLogger.info(" " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +155,7 @@ public class ForgeInstaller {
|
||||
} else {
|
||||
if (!process.waitFor(10, TimeUnit.MINUTES)) {
|
||||
process.destroyForcibly();
|
||||
System.out.println(ZAnsi.brightRed("Forge Installer timed out after 10 minutes"));
|
||||
LauncherLogger.error("Forge Installer timed out after 10 minutes");
|
||||
if (attempt < maxRetries) {
|
||||
attempt++;
|
||||
Thread.sleep(5000);
|
||||
@@ -172,7 +173,7 @@ public class ForgeInstaller {
|
||||
|
||||
// If error and not last attempt
|
||||
if (attempt < maxRetries) {
|
||||
System.out.println(ZAnsi.yellow("Install error. Retrying in 5 seconds..."));
|
||||
LauncherLogger.warn("Install error. Retrying in 5 seconds...");
|
||||
Thread.sleep(5000);
|
||||
|
||||
// Clean temp files before retry
|
||||
@@ -188,15 +189,15 @@ public class ForgeInstaller {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed("Forge Installer exited with error code: " + exitCode));
|
||||
LauncherLogger.error("Forge Installer exited with error code: " + exitCode);
|
||||
|
||||
// Show possible solution
|
||||
if (output.toString().contains("timed out")) {
|
||||
System.out.println(ZAnsi.yellow("\nPossible solutions:"));
|
||||
System.out.println(ZAnsi.yellow("1. Check your internet connection"));
|
||||
System.out.println(ZAnsi.yellow("2. Run the launcher as administrator"));
|
||||
System.out.println(ZAnsi.yellow("3. Temporarily disable antivirus/firewall"));
|
||||
System.out.println(ZAnsi.yellow("4. Try installing a different Forge version"));
|
||||
LauncherLogger.warn("\nPossible solutions:");
|
||||
LauncherLogger.warn("1. Check your internet connection");
|
||||
LauncherLogger.warn("2. Run the launcher as administrator");
|
||||
LauncherLogger.warn("3. Temporarily disable antivirus/firewall");
|
||||
LauncherLogger.warn("4. Try installing a different Forge version");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +208,7 @@ public class ForgeInstaller {
|
||||
}
|
||||
|
||||
private void downloadMissingLibraries(String mcVersion, String forgeVersion) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Checking and downloading missing libraries..."));
|
||||
LauncherLogger.info("Checking and downloading missing libraries...");
|
||||
ZHttpClient.repairMissingLibraries(instance.getPath());
|
||||
}
|
||||
}
|
||||
+28
-27
@@ -1,7 +1,8 @@
|
||||
package me.sashegdev.zernmc.launcher.minecraft.installer;
|
||||
|
||||
import me.sashegdev.zernmc.launcher.minecraft.Instance;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
|
||||
import me.sashegdev.zernmc.launcher.utils.JavaResolver;
|
||||
import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
|
||||
|
||||
import java.io.*;
|
||||
@@ -42,14 +43,14 @@ public class ModLoaderInstaller {
|
||||
}
|
||||
|
||||
public boolean install(String mcVersion, String loaderVersion, LoaderType type) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Installing " + type.loaderName + " " + loaderVersion + " for Minecraft " + mcVersion));
|
||||
LauncherLogger.info("Installing " + type.loaderName + " " + loaderVersion + " for Minecraft " + mcVersion);
|
||||
|
||||
System.out.println(ZAnsi.cyan("Installing base Minecraft version " + mcVersion + "..."));
|
||||
LauncherLogger.info("Installing base Minecraft version " + mcVersion + "...");
|
||||
VersionInstaller vanillaInstaller = new VersionInstaller(instance.getPath());
|
||||
String assetIndex = vanillaInstaller.install(mcVersion);
|
||||
|
||||
if (assetIndex == null || assetIndex.isEmpty()) {
|
||||
System.out.println(ZAnsi.brightRed("Failed to install base Minecraft version"));
|
||||
LauncherLogger.error("Failed to install base Minecraft version");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -60,11 +61,11 @@ public class ModLoaderInstaller {
|
||||
String jarName = type.loaderName + "-installer.jar";
|
||||
Path installerJar = instance.getPath().resolve(jarName);
|
||||
|
||||
System.out.println(ZAnsi.cyan("Downloading " + type.loaderName + " Installer..."));
|
||||
LauncherLogger.info("Downloading " + type.loaderName + " Installer...");
|
||||
ZHttpClient.downloadFileWithSmartProxy(installerUrl, installerJar);
|
||||
|
||||
System.out.println(ZAnsi.cyan("Running " + type.loaderName + " Installer..."));
|
||||
System.out.println(ZAnsi.yellow("This may take a few minutes. Please wait...\n"));
|
||||
LauncherLogger.info("Running " + type.loaderName + " Installer...");
|
||||
LauncherLogger.info("This may take a few minutes. Please wait...");
|
||||
|
||||
boolean success = runInstaller(installerJar, type);
|
||||
|
||||
@@ -72,10 +73,10 @@ public class ModLoaderInstaller {
|
||||
try {
|
||||
downloadMissingLibraries(type);
|
||||
} catch (Exception e) {
|
||||
System.out.println(ZAnsi.yellow("Warning: could not download some libraries: " + e.getMessage()));
|
||||
LauncherLogger.warn("Warning: could not download some libraries: " + e.getMessage());
|
||||
}
|
||||
|
||||
System.out.println(ZAnsi.brightGreen("\n" + type.loaderName + " " + loaderVersion + " installed successfully!"));
|
||||
LauncherLogger.info("\n" + type.loaderName + " " + loaderVersion + " installed successfully!");
|
||||
instance.setMinecraftVersion(mcVersion);
|
||||
instance.setLoaderType(type.loaderName);
|
||||
instance.setLoaderVersion(loaderVersion);
|
||||
@@ -83,7 +84,7 @@ public class ModLoaderInstaller {
|
||||
Files.deleteIfExists(installerJar);
|
||||
return true;
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed("\nError installing " + type.loaderName + "!"));
|
||||
LauncherLogger.error("\nError installing " + type.loaderName + "!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +113,7 @@ public class ModLoaderInstaller {
|
||||
}
|
||||
""";
|
||||
Files.writeString(profilePath, minimalProfile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
System.out.println(ZAnsi.yellow("Created launcher_profiles.json"));
|
||||
LauncherLogger.info("Created launcher_profiles.json");
|
||||
}
|
||||
|
||||
private boolean runInstaller(Path installerJar, LoaderType type) throws IOException, InterruptedException {
|
||||
@@ -120,10 +121,10 @@ public class ModLoaderInstaller {
|
||||
int attempt = 1;
|
||||
|
||||
while (attempt <= maxRetries) {
|
||||
System.out.println(ZAnsi.cyan("Attempt " + attempt + " of " + maxRetries));
|
||||
LauncherLogger.info("Attempt " + attempt + " of " + maxRetries);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
"java",
|
||||
JavaResolver.getJavaExecutable(),
|
||||
"-jar",
|
||||
installerJar.toAbsolutePath().toString(),
|
||||
"--installClient",
|
||||
@@ -145,18 +146,18 @@ public class ModLoaderInstaller {
|
||||
output.append(line).append("\n");
|
||||
|
||||
if (line.contains("Downloading") || line.contains("Extracting")) {
|
||||
System.out.println(ZAnsi.blue(" -> " + line));
|
||||
LauncherLogger.info(" -> " + line);
|
||||
} else if (line.contains("SUCCESS") || line.contains("successfully")) {
|
||||
System.out.println(ZAnsi.brightGreen(" + " + line));
|
||||
LauncherLogger.info(" + " + line);
|
||||
} else if (line.contains("WARNING") || line.contains("warning")) {
|
||||
System.out.println(ZAnsi.yellow(" ! " + line));
|
||||
LauncherLogger.warn(" ! " + line);
|
||||
} else if (line.contains("ERROR") || line.contains("error") || line.contains("failed") || line.contains("timed out")) {
|
||||
System.out.println(ZAnsi.brightRed(" X " + line));
|
||||
LauncherLogger.error(" X " + line);
|
||||
if (line.contains("timed out") || line.contains("failed to download")) {
|
||||
hasErrors = true;
|
||||
}
|
||||
} else if (!line.isBlank()) {
|
||||
System.out.println(" " + line);
|
||||
LauncherLogger.info(" " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,7 +169,7 @@ public class ModLoaderInstaller {
|
||||
} else {
|
||||
if (!process.waitFor(10, TimeUnit.MINUTES)) {
|
||||
process.destroyForcibly();
|
||||
System.out.println(ZAnsi.brightRed(type.loaderName + " Installer timed out after 10 minutes"));
|
||||
LauncherLogger.error(type.loaderName + " Installer timed out after 10 minutes");
|
||||
if (attempt < maxRetries) {
|
||||
attempt++;
|
||||
Thread.sleep(5000);
|
||||
@@ -184,7 +185,7 @@ public class ModLoaderInstaller {
|
||||
}
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
System.out.println(ZAnsi.yellow("Install error. Retrying in 5 seconds..."));
|
||||
LauncherLogger.warn("Install error. Retrying in 5 seconds...");
|
||||
Thread.sleep(5000);
|
||||
|
||||
Path librariesDir = instance.getPath().resolve("libraries");
|
||||
@@ -198,14 +199,14 @@ public class ModLoaderInstaller {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed(type.loaderName + " Installer exited with error code: " + exitCode));
|
||||
LauncherLogger.error(type.loaderName + " Installer exited with error code: " + exitCode);
|
||||
|
||||
if (output.toString().contains("timed out")) {
|
||||
System.out.println(ZAnsi.yellow("\nPossible solutions:"));
|
||||
System.out.println(ZAnsi.yellow("1. Check your internet connection"));
|
||||
System.out.println(ZAnsi.yellow("2. Run the launcher as administrator"));
|
||||
System.out.println(ZAnsi.yellow("3. Temporarily disable antivirus/firewall"));
|
||||
System.out.println(ZAnsi.yellow("4. Try installing a different version"));
|
||||
LauncherLogger.warn("\nPossible solutions:");
|
||||
LauncherLogger.warn("1. Check your internet connection");
|
||||
LauncherLogger.warn("2. Run the launcher as administrator");
|
||||
LauncherLogger.warn("3. Temporarily disable antivirus/firewall");
|
||||
LauncherLogger.warn("4. Try installing a different version");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +217,7 @@ public class ModLoaderInstaller {
|
||||
}
|
||||
|
||||
private void downloadMissingLibraries(LoaderType type) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Checking and downloading missing libraries..."));
|
||||
LauncherLogger.info("Checking and downloading missing libraries...");
|
||||
ZHttpClient.repairMissingLibraries(instance.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
+28
-27
@@ -1,8 +1,9 @@
|
||||
package me.sashegdev.zernmc.launcher.minecraft.installer;
|
||||
|
||||
import me.sashegdev.zernmc.launcher.minecraft.Instance;
|
||||
import me.sashegdev.zernmc.launcher.utils.JavaResolver;
|
||||
import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
|
||||
import me.sashegdev.zernmc.launcher.utils.ProgressBar;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
|
||||
|
||||
import java.io.*;
|
||||
@@ -20,14 +21,14 @@ public class NeoForgeInstaller {
|
||||
}
|
||||
|
||||
public boolean install(String mcVersion, String neoForgeVersion) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Installing NeoForge " + neoForgeVersion + " for Minecraft " + mcVersion));
|
||||
LauncherLogger.info("Installing NeoForge " + neoForgeVersion + " for Minecraft " + mcVersion);
|
||||
|
||||
System.out.println(ZAnsi.cyan("Installing base Minecraft version " + mcVersion + "..."));
|
||||
LauncherLogger.info("Installing base Minecraft version " + mcVersion + "...");
|
||||
VersionInstaller vanillaInstaller = new VersionInstaller(instance.getPath());
|
||||
String assetIndex = vanillaInstaller.install(mcVersion);
|
||||
|
||||
if (assetIndex == null || assetIndex.isEmpty()) {
|
||||
System.out.println(ZAnsi.brightRed("Failed to install base Minecraft version"));
|
||||
LauncherLogger.error("Failed to install base Minecraft version");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -45,11 +46,11 @@ public class NeoForgeInstaller {
|
||||
|
||||
Path installerJar = instance.getPath().resolve("neoforge-installer.jar");
|
||||
|
||||
System.out.println(ZAnsi.cyan("Downloading NeoForge Installer..."));
|
||||
LauncherLogger.info("Downloading NeoForge Installer...");
|
||||
downloadFileWithProgress(installerUrl, installerJar);
|
||||
|
||||
System.out.println(ZAnsi.cyan("Running NeoForge Installer..."));
|
||||
System.out.println(ZAnsi.yellow("This may take a few minutes. Please wait...\n"));
|
||||
LauncherLogger.info("Running NeoForge Installer...");
|
||||
LauncherLogger.info("This may take a few minutes. Please wait...");
|
||||
|
||||
boolean success = runNeoForgeInstaller(installerJar);
|
||||
|
||||
@@ -57,10 +58,10 @@ public class NeoForgeInstaller {
|
||||
try {
|
||||
downloadMissingLibraries(mcVersion, neoForgeVersion, mavenGroup, mavenArtifact);
|
||||
} catch (Exception e) {
|
||||
System.out.println(ZAnsi.yellow("Warning: could not download some libraries: " + e.getMessage()));
|
||||
LauncherLogger.warn("Warning: could not download some libraries: " + e.getMessage());
|
||||
}
|
||||
|
||||
System.out.println(ZAnsi.brightGreen("\nNeoForge " + neoForgeVersion + " installed successfully!"));
|
||||
LauncherLogger.info("\nNeoForge " + neoForgeVersion + " installed successfully!");
|
||||
instance.setMinecraftVersion(mcVersion);
|
||||
instance.setLoaderType("neoforge");
|
||||
instance.setLoaderVersion(neoForgeVersion);
|
||||
@@ -68,7 +69,7 @@ public class NeoForgeInstaller {
|
||||
Files.deleteIfExists(installerJar);
|
||||
return true;
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed("\nError installing NeoForge!"));
|
||||
LauncherLogger.error("\nError installing NeoForge!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +99,7 @@ public class NeoForgeInstaller {
|
||||
}
|
||||
""";
|
||||
Files.writeString(profilePath, minimalProfile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
System.out.println(ZAnsi.yellow("Created launcher_profiles.json"));
|
||||
LauncherLogger.info("Created launcher_profiles.json");
|
||||
}
|
||||
|
||||
private void downloadFileWithProgress(String url, Path target) throws Exception {
|
||||
@@ -112,10 +113,10 @@ public class NeoForgeInstaller {
|
||||
int attempt = 1;
|
||||
|
||||
while (attempt <= maxRetries) {
|
||||
System.out.println(ZAnsi.cyan("Attempt " + attempt + " of " + maxRetries));
|
||||
LauncherLogger.info("Attempt " + attempt + " of " + maxRetries);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
"java",
|
||||
JavaResolver.getJavaExecutable(),
|
||||
"-jar",
|
||||
installerJar.toAbsolutePath().toString(),
|
||||
"--installClient",
|
||||
@@ -137,25 +138,25 @@ public class NeoForgeInstaller {
|
||||
output.append(line).append("\n");
|
||||
|
||||
if (line.contains("Downloading") || line.contains("Extracting")) {
|
||||
System.out.println(ZAnsi.blue(" -> " + line));
|
||||
LauncherLogger.info(" -> " + line);
|
||||
} else if (line.contains("SUCCESS") || line.contains("successfully")) {
|
||||
System.out.println(ZAnsi.brightGreen(" + " + line));
|
||||
LauncherLogger.info(" + " + line);
|
||||
} else if (line.contains("WARNING") || line.contains("warning")) {
|
||||
System.out.println(ZAnsi.yellow(" ! " + line));
|
||||
LauncherLogger.warn(" ! " + line);
|
||||
} else if (line.contains("ERROR") || line.contains("error") || line.contains("failed") || line.contains("timed out")) {
|
||||
System.out.println(ZAnsi.brightRed(" X " + line));
|
||||
LauncherLogger.error(" X " + line);
|
||||
if (line.contains("timed out") || line.contains("failed to download")) {
|
||||
hasErrors = true;
|
||||
}
|
||||
} else if (!line.isBlank()) {
|
||||
System.out.println(" " + line);
|
||||
LauncherLogger.info(" " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!process.waitFor(10, TimeUnit.MINUTES)) {
|
||||
process.destroyForcibly();
|
||||
System.out.println(ZAnsi.brightRed("NeoForge Installer timed out after 10 minutes"));
|
||||
LauncherLogger.error("NeoForge Installer timed out after 10 minutes");
|
||||
return false;
|
||||
}
|
||||
int exitCode = process.exitValue();
|
||||
@@ -165,7 +166,7 @@ public class NeoForgeInstaller {
|
||||
}
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
System.out.println(ZAnsi.yellow("Install error. Retrying in 5 seconds..."));
|
||||
LauncherLogger.warn("Install error. Retrying in 5 seconds...");
|
||||
Thread.sleep(5000);
|
||||
|
||||
Path librariesDir = instance.getPath().resolve("libraries");
|
||||
@@ -179,14 +180,14 @@ public class NeoForgeInstaller {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println(ZAnsi.brightRed("NeoForge Installer exited with error code: " + exitCode));
|
||||
LauncherLogger.error("NeoForge Installer exited with error code: " + exitCode);
|
||||
|
||||
if (output.toString().contains("timed out")) {
|
||||
System.out.println(ZAnsi.yellow("\nPossible solutions:"));
|
||||
System.out.println(ZAnsi.yellow("1. Check your internet connection"));
|
||||
System.out.println(ZAnsi.yellow("2. Run the launcher as administrator"));
|
||||
System.out.println(ZAnsi.yellow("3. Temporarily disable antivirus/firewall"));
|
||||
System.out.println(ZAnsi.yellow("4. Try installing a different NeoForge version"));
|
||||
LauncherLogger.warn("\nPossible solutions:");
|
||||
LauncherLogger.warn("1. Check your internet connection");
|
||||
LauncherLogger.warn("2. Run the launcher as administrator");
|
||||
LauncherLogger.warn("3. Temporarily disable antivirus/firewall");
|
||||
LauncherLogger.warn("4. Try installing a different NeoForge version");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +198,7 @@ public class NeoForgeInstaller {
|
||||
}
|
||||
|
||||
private void downloadMissingLibraries(String mcVersion, String neoForgeVersion, String mavenGroup, String mavenArtifact) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Checking and downloading missing libraries..."));
|
||||
LauncherLogger.info("Checking and downloading missing libraries...");
|
||||
ZHttpClient.repairMissingLibraries(instance.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
+54
-19
@@ -1,6 +1,7 @@
|
||||
package me.sashegdev.zernmc.launcher.minecraft.installer;
|
||||
|
||||
import me.sashegdev.zernmc.launcher.minecraft.model.MinecraftVersion;
|
||||
import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
|
||||
import me.sashegdev.zernmc.launcher.utils.ProgressBar;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
|
||||
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
|
||||
@@ -8,6 +9,7 @@ import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
@@ -56,11 +58,22 @@ public class VersionInstaller {
|
||||
}
|
||||
|
||||
public String install(String versionId) throws Exception {
|
||||
System.out.println(ZAnsi.cyan("Full install of Minecraft " + versionId + "..."));
|
||||
LauncherLogger.info("Full install of Minecraft " + versionId + "...");
|
||||
ProgressBar.setStage("Version", 0, 5);
|
||||
Path versionDir = minecraftDir.resolve("versions").resolve(versionId);
|
||||
Files.createDirectories(versionDir);
|
||||
|
||||
boolean alreadyInstalled = Files.exists(versionDir.resolve(versionId + ".json"))
|
||||
&& Files.exists(versionDir.resolve(versionId + ".jar"));
|
||||
if (alreadyInstalled) {
|
||||
LauncherLogger.info("Minecraft " + versionId + " already installed, skipping");
|
||||
String existing = Files.readString(versionDir.resolve(versionId + ".json"));
|
||||
JSONObject existingData = new JSONObject(existing);
|
||||
return existingData.has("assetIndex")
|
||||
? existingData.getJSONObject("assetIndex").getString("id")
|
||||
: existingData.getString("assets");
|
||||
}
|
||||
|
||||
ProgressBar.show("Fetching version info", 0, 1, "files");
|
||||
String versionJson;
|
||||
try {
|
||||
@@ -82,24 +95,27 @@ public class VersionInstaller {
|
||||
|
||||
// client.jar
|
||||
ProgressBar.show("Downloading client.jar", 0, 1, "files");
|
||||
try {
|
||||
ZHttpClient.downloadFileWithSmartProxy(
|
||||
versionData.getJSONObject("downloads").getJSONObject("client").getString("url"),
|
||||
versionDir.resolve(versionId + ".jar"));
|
||||
} catch (Exception e) {
|
||||
System.err.println(ZAnsi.red("[VERSION] Failed to download client.jar: " + e.getMessage()));
|
||||
throw e;
|
||||
Path clientJar = versionDir.resolve(versionId + ".jar");
|
||||
if (!Files.exists(clientJar)) {
|
||||
try {
|
||||
ZHttpClient.downloadFileWithSmartProxy(
|
||||
versionData.getJSONObject("downloads").getJSONObject("client").getString("url"),
|
||||
clientJar);
|
||||
} catch (Exception e) {
|
||||
System.err.println(ZAnsi.red("[VERSION] Failed to download client.jar: " + e.getMessage()));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
ProgressBar.show("Client.jar", 1, 1, "files");
|
||||
|
||||
// Libraries
|
||||
ProgressBar.setStage("Libraries", 1, 5);
|
||||
System.out.println(ZAnsi.cyan("Downloading libraries..."));
|
||||
LauncherLogger.info("Downloading libraries...");
|
||||
downloadLibraries(versionData.getJSONArray("libraries"));
|
||||
|
||||
// Natives
|
||||
ProgressBar.setStage("Natives", 2, 5);
|
||||
System.out.println(ZAnsi.cyan("Extracting natives..."));
|
||||
LauncherLogger.info("Extracting natives...");
|
||||
extractNatives(versionData.getJSONArray("libraries"));
|
||||
|
||||
String assetIndex;
|
||||
@@ -109,15 +125,15 @@ public class VersionInstaller {
|
||||
assetIndex = versionData.getString("assets");
|
||||
}
|
||||
|
||||
System.out.println(ZAnsi.cyan("Asset index: " + assetIndex));
|
||||
LauncherLogger.info("Asset index: " + assetIndex);
|
||||
|
||||
// Download assets using correct index
|
||||
ProgressBar.setStage("Assets", 3, 5);
|
||||
System.out.println(ZAnsi.cyan("Downloading assets..."));
|
||||
LauncherLogger.info("Downloading assets...");
|
||||
downloadAssets(versionData, assetIndex);
|
||||
|
||||
ProgressBar.setStage("Done", 4, 5);
|
||||
System.out.println(ZAnsi.brightGreen("\nMinecraft " + versionId + " fully installed!"));
|
||||
LauncherLogger.info("\nMinecraft " + versionId + " fully installed!");
|
||||
return assetIndex;
|
||||
}
|
||||
|
||||
@@ -190,7 +206,7 @@ public class VersionInstaller {
|
||||
if (extracted > 0) {
|
||||
ProgressBar.finish("Natives extracted (" + extracted + " ok, " + failed + " failed)");
|
||||
} else {
|
||||
System.out.println(ZAnsi.yellow("No natives to extract for " + classifier));
|
||||
LauncherLogger.warn("No natives to extract for " + classifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +224,12 @@ public class VersionInstaller {
|
||||
Path target = minecraftDir.resolve("libraries").resolve(path);
|
||||
Files.createDirectories(target.getParent());
|
||||
|
||||
if (Files.exists(target)) {
|
||||
count++;
|
||||
ProgressBar.show("Libraries", count, total, "files");
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
ZHttpClient.downloadFileWithSmartProxy(url, target);
|
||||
} catch (Exception e) {
|
||||
@@ -229,14 +251,18 @@ public class VersionInstaller {
|
||||
Files.createDirectories(indexesDir);
|
||||
Path indexPath = indexesDir.resolve(assetIndex + ".json");
|
||||
|
||||
System.out.println(ZAnsi.cyan("Downloading asset index (" + assetIndex + ")..."));
|
||||
ZHttpClient.downloadFileWithSmartProxy(indexUrl, indexPath);
|
||||
if (!Files.exists(indexPath)) {
|
||||
LauncherLogger.info("Downloading asset index (" + assetIndex + ")...");
|
||||
ZHttpClient.downloadFileWithSmartProxy(indexUrl, indexPath);
|
||||
} else {
|
||||
LauncherLogger.info("Asset index already present (" + assetIndex + ")");
|
||||
}
|
||||
|
||||
String jsonContent = Files.readString(indexPath);
|
||||
JSONObject root = new JSONObject(jsonContent);
|
||||
JSONObject objects = root.getJSONObject("objects");
|
||||
|
||||
System.out.println(ZAnsi.cyan("Downloading " + objects.length() + " asset objects (index: " + assetIndex + ")..."));
|
||||
LauncherLogger.info("Downloading " + objects.length() + " asset objects (index: " + assetIndex + ")...");
|
||||
|
||||
int total = objects.length();
|
||||
int[] success = {0};
|
||||
@@ -256,6 +282,15 @@ public class VersionInstaller {
|
||||
Files.createDirectories(target.getParent());
|
||||
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (Files.exists(target) && Files.size(target) > 0) {
|
||||
synchronized (this) {
|
||||
success[0]++;
|
||||
ProgressBar.show("Assets", success[0], total, "files");
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
boolean downloaded = false;
|
||||
for (int attempt = 1; attempt <= 3; attempt++) {
|
||||
try {
|
||||
@@ -297,8 +332,8 @@ public class VersionInstaller {
|
||||
ProgressBar.finish("Assets downloaded (" + success[0] + " ok, " + failed[0] + " skipped)");
|
||||
|
||||
if (failed[0] > 0) {
|
||||
System.out.println(ZAnsi.yellow("Warning: " + failed[0] + " asset files could not be downloaded."));
|
||||
System.out.println(ZAnsi.yellow("The game will launch, but some textures/sounds may be missing."));
|
||||
LauncherLogger.warn("Warning: " + failed[0] + " asset files could not be downloaded.");
|
||||
LauncherLogger.warn("The game will launch, but some textures/sounds may be missing.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ public final class JFXBridge {
|
||||
private static final String JFX_CLASS = "me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher";
|
||||
|
||||
private static volatile java.lang.reflect.Method appendGameLogMethod;
|
||||
private static volatile java.lang.reflect.Method appendLauncherLogFromLoggerMethod;
|
||||
private static volatile java.lang.reflect.Method setInstallProgressMethod;
|
||||
private static volatile java.lang.reflect.Method setInstallStageMethod;
|
||||
|
||||
@@ -49,6 +50,25 @@ public final class JFXBridge {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward a launcher log line to the JFX UI without re-logging it through
|
||||
* LauncherLogger. Called from LauncherLogger.write so all logged lines
|
||||
* (including installer output) become visible in the UI. Safe no-op in CLI mode.
|
||||
*/
|
||||
public static void appendLauncherLogFromLogger(String msg) {
|
||||
if (appendLauncherLogFromLoggerMethod == null) {
|
||||
appendLauncherLogFromLoggerMethod = method("appendLauncherLogFromLogger", String.class);
|
||||
}
|
||||
if (appendLauncherLogFromLoggerMethod == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
appendLauncherLogFromLoggerMethod.invoke(null, msg);
|
||||
} catch (Throwable t) {
|
||||
appendLauncherLogFromLoggerMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Forward install progress to the JFX UI. Safe no-op in CLI mode. */
|
||||
public static void setInstallProgress(String label, int current, int total) {
|
||||
if (setInstallProgressMethod == null) {
|
||||
|
||||
@@ -134,6 +134,19 @@ public class JFXLauncher extends Application {
|
||||
try { consumer.onLog(msg); } catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a line to the UI log buffer without re-logging it through
|
||||
* LauncherLogger (avoids recursion when called from LauncherLogger.write).
|
||||
*/
|
||||
public static void appendLauncherLogFromLogger(String msg) {
|
||||
synchronized (launcherLogBuffer) {
|
||||
launcherLogBuffer.append(msg).append("\n");
|
||||
}
|
||||
for (LogConsumer consumer : logConsumers) {
|
||||
try { consumer.onLog(msg); } catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static void appendGameLog(String msg) {
|
||||
synchronized (gameLogBuffer) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package me.sashegdev.zernmc.launcher.utils;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Resolves the java executable used to run the launcher itself, so child
|
||||
* processes (Forge/NeoForge/Fabric installers) run on the bundled JRE
|
||||
* instead of relying on a system java that may not exist or be too old.
|
||||
*
|
||||
* Order of preference:
|
||||
* 1. The JVM currently running the launcher (bundled jre21 in lib/jre21).
|
||||
* 2. A jre21 next to the working directory (dev layout).
|
||||
* 3. System PATH lookup (last resort).
|
||||
*/
|
||||
public final class JavaResolver {
|
||||
|
||||
private JavaResolver() {}
|
||||
|
||||
public static String getJavaExecutable() {
|
||||
String os = System.getProperty("os.name", "").toLowerCase();
|
||||
String javaExe = os.contains("win") ? "java.exe" : "java";
|
||||
|
||||
Path fromHome = Paths.get(System.getProperty("java.home"), "bin", javaExe);
|
||||
if (Files.exists(fromHome)) {
|
||||
return fromHome.toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
Path bundled = Paths.get("").toAbsolutePath().resolve("lib").resolve("jre21").resolve("bin").resolve(javaExe);
|
||||
if (Files.exists(bundled)) {
|
||||
return bundled.toString();
|
||||
}
|
||||
|
||||
Path devJre = Paths.get("").toAbsolutePath().resolve("jre21").resolve("bin").resolve(javaExe);
|
||||
if (Files.exists(devJre)) {
|
||||
return devJre.toString();
|
||||
}
|
||||
|
||||
return javaExe;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.sashegdev.zernmc.launcher.utils;
|
||||
|
||||
import me.sashegdev.zernmc.launcher.ui.jfx.JFXBridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
@@ -94,6 +96,11 @@ public class LauncherLogger {
|
||||
// full/hung stdout pipe (e.g. javaw piped to the parent exe) can never
|
||||
// block application threads.
|
||||
offerStdout(line);
|
||||
|
||||
// Forward to the JFX UI log so installer/progress output is visible
|
||||
// in the GUI. The bridge is a safe no-op when JavaFX is unavailable.
|
||||
JFXBridge.appendLauncherLogFromLogger(line);
|
||||
|
||||
if (t != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
|
||||
<properties>
|
||||
<revision>1.0.16</revision>
|
||||
<hotfix>0</hotfix>
|
||||
<hotfix>2</hotfix>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
@@ -1347,6 +1347,9 @@ def generate_launcher_builds_meta():
|
||||
# Skip root-level JARs — only bin/*.jar is needed at runtime
|
||||
if rel_path in ("zernmclauncher.jar", "zernmc-bootstrap.jar"):
|
||||
continue
|
||||
# CLI exe is not shipped to users
|
||||
if rel_path == "zernmc-cli.exe":
|
||||
continue
|
||||
stat = file_path.stat()
|
||||
|
||||
# Calculate hash
|
||||
|
||||
Reference in New Issue
Block a user