v1.0.16.0 — fix Zern-OBT asset index (1.20.1->5), JavaFX 23->23.0.1 (WebKit WebSocket fix), drop embedded JavaFX from jar (scope=provided), deliver JavaFX 23.0.1 via incremental update, JFXBridge for safe CLI fallback

This commit is contained in:
SashegDev
2026-08-14 07:29:23 +00:00
parent 77fd97ad24
commit 21cd30c1c3
11 changed files with 242 additions and 52 deletions
@@ -394,9 +394,49 @@ public class Bootstrap {
String summary = "Updated files: " + downloaded + ", skipped: " + skipped + ", failed: " + failed; String summary = "Updated files: " + downloaded + ", skipped: " + skipped + ", failed: " + failed;
if (staged > 0) summary += ", staged self-update: " + staged; if (staged > 0) summary += ", staged self-update: " + staged;
log(summary); log(summary);
cleanStaleJavaFxJars(serverFiles);
log("Updated to v" + newVersion); log("Updated to v" + newVersion);
} }
/**
* Removes old lib/javafx/*-win.jar files that are no longer part of the
* server meta (e.g. the previous JavaFX 23 jars after an upgrade to
* 23.0.1). Keeping both would put two JARs exporting the same module on
* the --module-path, which breaks module resolution.
*/
private static void cleanStaleJavaFxJars(Map<String, FileMeta> serverFiles) {
Path javafxDir = baseDir.resolve("lib").resolve("javafx");
if (!Files.isDirectory(javafxDir)) return;
java.util.Set<String> keep = new java.util.HashSet<>();
for (String filePath : serverFiles.keySet()) {
String normalized = filePath.toLowerCase().replace("\\", "/");
if (normalized.startsWith("lib/javafx/") && normalized.endsWith("-win.jar")) {
keep.add(new File(filePath).getName().toLowerCase());
}
}
try (java.util.stream.Stream<Path> stream = Files.list(javafxDir)) {
stream.filter(Files::isRegularFile)
.filter(p -> {
String name = p.getFileName().toString().toLowerCase();
return name.endsWith("-win.jar") && !keep.contains(name);
})
.forEach(p -> {
try {
Files.delete(p);
log("Removed stale JavaFX jar: " + p.getFileName());
} catch (Exception e) {
log("Warning: could not remove stale JavaFX jar " + p.getFileName() + " - " + e.getMessage());
}
});
} catch (Exception e) {
log("Warning: failed to scan JavaFX dir: " + e.getMessage());
}
}
private static boolean isSelfExe(String filePath) { private static boolean isSelfExe(String filePath) {
String lower = filePath.toLowerCase().replace("\\", "/"); String lower = filePath.toLowerCase().replace("\\", "/");
return lower.equals("zernmc.exe") || lower.equals("zernmc-cli.exe") return lower.equals("zernmc.exe") || lower.equals("zernmc-cli.exe")
+15 -10
View File
@@ -61,32 +61,37 @@
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId> <artifactId>javafx-controls</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId> <artifactId>javafx-web</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId> <artifactId>javafx-graphics</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId> <artifactId>javafx-base</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId> <artifactId>javafx-media</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
<scope>provided</scope>
</dependency> </dependency>
<!-- Test --> <!-- Test -->
@@ -235,27 +240,27 @@
<!-- Копируем JavaFX модули в lib/javafx --> <!-- Копируем JavaFX модули в lib/javafx -->
<mkdir dir="../../server/builds/lib/javafx"/> <mkdir dir="../../server/builds/lib/javafx"/>
<copy todir="../../server/builds/lib/javafx" overwrite="true"> <copy todir="../../server/builds/lib/javafx" overwrite="true">
<fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-controls/23"> <fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-controls/23.0.1">
<include name="*win.jar"/> <include name="*win.jar"/>
</fileset> </fileset>
</copy> </copy>
<copy todir="../../server/builds/lib/javafx" overwrite="true"> <copy todir="../../server/builds/lib/javafx" overwrite="true">
<fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-graphics/23"> <fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-graphics/23.0.1">
<include name="*win.jar"/> <include name="*win.jar"/>
</fileset> </fileset>
</copy> </copy>
<copy todir="../../server/builds/lib/javafx" overwrite="true"> <copy todir="../../server/builds/lib/javafx" overwrite="true">
<fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-base/23"> <fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-base/23.0.1">
<include name="*win.jar"/> <include name="*win.jar"/>
</fileset> </fileset>
</copy> </copy>
<copy todir="../../server/builds/lib/javafx" overwrite="true"> <copy todir="../../server/builds/lib/javafx" overwrite="true">
<fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-web/23"> <fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-web/23.0.1">
<include name="*win.jar"/> <include name="*win.jar"/>
</fileset> </fileset>
</copy> </copy>
<copy todir="../../server/builds/lib/javafx" overwrite="true"> <copy todir="../../server/builds/lib/javafx" overwrite="true">
<fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-media/23"> <fileset dir="${user.home}/.m2/repository/org/openjfx/javafx-media/23.0.1">
<include name="*win.jar"/> <include name="*win.jar"/>
</fileset> </fileset>
</copy> </copy>
@@ -50,7 +50,7 @@ public class Main {
private static void launchJFX() { private static void launchJFX() {
try { try {
System.setProperty("javafx.runtime.version", "21"); System.setProperty("javafx.runtime.version", "23.0.1");
JFXLauncher.main(new String[]{}); JFXLauncher.main(new String[]{});
} catch (Exception e) { } catch (Exception e) {
@@ -6,7 +6,7 @@ import me.sashegdev.zernmc.launcher.minecraft.Instance;
import me.sashegdev.zernmc.launcher.minecraft.InstanceManager; import me.sashegdev.zernmc.launcher.minecraft.InstanceManager;
import me.sashegdev.zernmc.launcher.minecraft.launch.LaunchCommandBuilder; import me.sashegdev.zernmc.launcher.minecraft.launch.LaunchCommandBuilder;
import me.sashegdev.zernmc.launcher.minecraft.model.LaunchOptions; import me.sashegdev.zernmc.launcher.minecraft.model.LaunchOptions;
import me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher; import me.sashegdev.zernmc.launcher.ui.jfx.JFXBridge;
import me.sashegdev.zernmc.launcher.utils.Config; import me.sashegdev.zernmc.launcher.utils.Config;
import me.sashegdev.zernmc.launcher.utils.LauncherLogger; import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
@@ -102,14 +102,14 @@ public class LaunchService {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
String timestamped = "[" + java.time.LocalTime.now().format(java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss")) + "] " + line; String timestamped = "[" + java.time.LocalTime.now().format(java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss")) + "] " + line;
JFXLauncher.appendGameLog(line); JFXBridge.appendGameLog(line);
try { try {
logFileOut.write((timestamped + "\n").getBytes(java.nio.charset.StandardCharsets.UTF_8)); logFileOut.write((timestamped + "\n").getBytes(java.nio.charset.StandardCharsets.UTF_8));
logFileOut.flush(); logFileOut.flush();
} catch (Exception ignored) {} } catch (Exception ignored) {}
} }
} catch (Exception e) { } catch (Exception e) {
JFXLauncher.appendGameLog("[Error reading logs: " + e.getMessage() + "]"); JFXBridge.appendGameLog("[Error reading logs: " + e.getMessage() + "]");
} finally { } finally {
try { logFileOut.close(); } catch (Exception ignored) {} try { logFileOut.close(); } catch (Exception ignored) {}
} }
@@ -127,11 +127,11 @@ public class LaunchService {
try { try {
int exitCode = process.waitFor(); int exitCode = process.waitFor();
runningProcesses.remove(pid); runningProcesses.remove(pid);
JFXLauncher.appendGameLog("[Minecraft exited with code: " + exitCode + "]"); JFXBridge.appendGameLog("[Minecraft exited with code: " + exitCode + "]");
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (Exception e) { } catch (Exception e) {
JFXLauncher.appendGameLog("[Error watching process: " + e.getMessage() + "]"); JFXBridge.appendGameLog("[Error watching process: " + e.getMessage() + "]");
} }
}, "ProcessWatcher-" + instanceName); }, "ProcessWatcher-" + instanceName);
processWatcher.setDaemon(true); processWatcher.setDaemon(true);
@@ -5,7 +5,7 @@ import me.sashegdev.zernmc.launcher.minecraft.installer.ModLoaderInstaller;
import me.sashegdev.zernmc.launcher.minecraft.installer.VersionInstaller; import me.sashegdev.zernmc.launcher.minecraft.installer.VersionInstaller;
import me.sashegdev.zernmc.launcher.minecraft.launch.LaunchCommandBuilder; import me.sashegdev.zernmc.launcher.minecraft.launch.LaunchCommandBuilder;
import me.sashegdev.zernmc.launcher.minecraft.model.LaunchOptions; import me.sashegdev.zernmc.launcher.minecraft.model.LaunchOptions;
import me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher; import me.sashegdev.zernmc.launcher.ui.jfx.JFXBridge;
import me.sashegdev.zernmc.launcher.utils.ConsoleUtils; import me.sashegdev.zernmc.launcher.utils.ConsoleUtils;
import me.sashegdev.zernmc.launcher.utils.LauncherLogger; import me.sashegdev.zernmc.launcher.utils.LauncherLogger;
import me.sashegdev.zernmc.launcher.utils.ZAnsi; import me.sashegdev.zernmc.launcher.utils.ZAnsi;
@@ -141,10 +141,10 @@ public class MinecraftLib {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
JFXLauncher.appendGameLog(line); JFXBridge.appendGameLog(line);
} }
} catch (Exception e) { } catch (Exception e) {
JFXLauncher.appendGameLog("[Error reading output: " + e.getMessage() + "]"); JFXBridge.appendGameLog("[Error reading output: " + e.getMessage() + "]");
} }
}); });
outThread.setDaemon(true); outThread.setDaemon(true);
@@ -155,10 +155,10 @@ public class MinecraftLib {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
JFXLauncher.appendGameLog("[ERR] " + line); JFXBridge.appendGameLog("[ERR] " + line);
} }
} catch (Exception e) { } catch (Exception e) {
JFXLauncher.appendGameLog("[Error reading stderr: " + e.getMessage() + "]"); JFXBridge.appendGameLog("[Error reading stderr: " + e.getMessage() + "]");
} }
}); });
errThread.setDaemon(true); errThread.setDaemon(true);
@@ -250,7 +250,7 @@ public class PackDownloader {
instance.setMinecraftVersion(manifest.getMinecraftVersion()); instance.setMinecraftVersion(manifest.getMinecraftVersion());
instance.setLoaderType(manifest.getLoaderType()); instance.setLoaderType(manifest.getLoaderType());
instance.setLoaderVersion(manifest.getLoaderVersion()); instance.setLoaderVersion(manifest.getLoaderVersion());
instance.setAssetIndex(manifest.getAssetIndex()); instance.setAssetIndex(resolveAssetIndex(manifest));
reportProgress("Pack installed successfully!", 100, "Installing pack files", 4, 5); reportProgress("Pack installed successfully!", 100, "Installing pack files", 4, 5);
System.out.println(ZAnsi.brightGreen("Pack installed successfully!")); System.out.println(ZAnsi.brightGreen("Pack installed successfully!"));
@@ -300,7 +300,7 @@ public class PackDownloader {
instance.setMinecraftVersion(manifest.getMinecraftVersion()); instance.setMinecraftVersion(manifest.getMinecraftVersion());
instance.setLoaderType(manifest.getLoaderType()); instance.setLoaderType(manifest.getLoaderType());
instance.setLoaderVersion(manifest.getLoaderVersion()); instance.setLoaderVersion(manifest.getLoaderVersion());
instance.setAssetIndex(manifest.getAssetIndex()); instance.setAssetIndex(resolveAssetIndex(manifest));
System.out.println(ZAnsi.brightGreen("Pack installed successfully!")); System.out.println(ZAnsi.brightGreen("Pack installed successfully!"));
LauncherLogger.info("installOrUpdatePack: SUCCESS"); LauncherLogger.info("installOrUpdatePack: SUCCESS");
@@ -771,6 +771,56 @@ public class PackDownloader {
public boolean isEmpty() { return files == null || files.isEmpty(); } public boolean isEmpty() { return files == null || files.isEmpty(); }
} }
/**
* Resolve the correct asset index for the installed Minecraft version.
* The manifest/instance.json asset_index value may be wrong (e.g. Zern-OBT
* shipped "1.20.1" while the real index for MC 1.20.1 is "5"). The source of
* truth is the local Mojang version JSON downloaded during install
* (versions/&lt;mc&gt;/&lt;mc&gt;.json -> assetIndex.id). We only trust it when the
* corresponding index file actually exists on disk; otherwise fall back to
* the manifest value.
*/
private String resolveAssetIndex(PackManifest manifest) {
String manifestIndex = manifest.getAssetIndex();
if (manifest == null || manifest.getMinecraftVersion() == null) {
return manifestIndex;
}
try {
Path versionJson = instance.getPath().resolve("versions")
.resolve(manifest.getMinecraftVersion())
.resolve(manifest.getMinecraftVersion() + ".json");
if (Files.exists(versionJson)) {
JsonObject versionData = JsonParser.parseString(Files.readString(versionJson)).getAsJsonObject();
String realIndex = null;
if (versionData.has("assetIndex") && versionData.get("assetIndex").isJsonObject()
&& versionData.getAsJsonObject("assetIndex").has("id")) {
realIndex = versionData.getAsJsonObject("assetIndex").get("id").getAsString();
} else if (versionData.has("assets") && !versionData.get("assets").isJsonNull()) {
realIndex = versionData.get("assets").getAsString();
}
if (realIndex != null && !realIndex.isEmpty()) {
Path indexPath = instance.getPath().resolve("assets").resolve("indexes")
.resolve(realIndex + ".json");
if (Files.exists(indexPath)) {
if (!realIndex.equals(manifestIndex)) {
LauncherLogger.warn("resolveAssetIndex: manifest asset_index=" + manifestIndex
+ " but real index=" + realIndex + " exists on disk, using real index");
}
return realIndex;
} else {
LauncherLogger.warn("resolveAssetIndex: real index=" + realIndex
+ " from version JSON, but " + indexPath + " does not exist; falling back to manifest=" + manifestIndex);
}
}
} else {
LauncherLogger.warn("resolveAssetIndex: local version JSON not found: " + versionJson);
}
} catch (Exception e) {
LauncherLogger.warn("resolveAssetIndex: failed to resolve: " + e.getClass().getSimpleName() + " - " + e.getMessage());
}
return manifestIndex;
}
public static class DiffResponse { public static class DiffResponse {
private int version; private int version;
private List<FileInfo> to_download; private List<FileInfo> to_download;
@@ -498,6 +498,29 @@ public class LaunchCommandBuilder {
assetIndex = instance.getMinecraftVersion(); assetIndex = instance.getMinecraftVersion();
System.out.println(ZAnsi.yellow("Asset index not found, using version: " + assetIndex)); System.out.println(ZAnsi.yellow("Asset index not found, using version: " + assetIndex));
} else { } else {
// Validate that the index file exists. A wrong/stale asset index
// (e.g. the Zern-OBT "1.20.1" bug, real index is "5") makes the game
// fail to load the base resource pack (grey panorama, no sounds).
Path indexPath = instance.getPath().resolve("assets").resolve("indexes").resolve(assetIndex + ".json");
if (!Files.exists(indexPath)) {
System.out.println(ZAnsi.yellow("Asset index file missing: " + assetIndex + ".json, searching for existing index..."));
try (java.util.stream.Stream<Path> stream = Files.list(instance.getPath().resolve("assets").resolve("indexes"))) {
java.util.List<Path> existing = stream
.filter(p -> p.getFileName().toString().endsWith(".json"))
.sorted()
.collect(java.util.stream.Collectors.toList());
if (!existing.isEmpty()) {
String found = existing.get(existing.size() - 1).getFileName().toString()
.replace(".json", "");
System.out.println(ZAnsi.green("Using existing asset index: " + found + " (was " + assetIndex + ")"));
assetIndex = found;
} else {
System.out.println(ZAnsi.yellow("No asset index files found in assets/indexes/"));
}
} catch (Exception e) {
System.out.println(ZAnsi.yellow("Failed to search asset indexes: " + e.getMessage()));
}
}
System.out.println(ZAnsi.green("Using asset index: " + assetIndex)); System.out.println(ZAnsi.green("Using asset index: " + assetIndex));
} }
args.add(assetIndex); args.add(assetIndex);
@@ -0,0 +1,81 @@
package me.sashegdev.zernmc.launcher.ui.jfx;
/**
* Safe reflection bridge to JFXLauncher for use from non-JFX code (CLI, menus,
* installers).
*
* IMPORTANT: JFXLauncher extends javafx.application.Application. In CLI mode
* JavaFX is NOT on the module path, so loading JFXLauncher (or any class that
* references JavaFX) throws NoClassDefFoundError (an Error, not an Exception).
* Therefore the bridge must catch Throwable and never let JFX-launcher errors
* leak into CLI/game-launch code paths.
*
* Rule: any call into JFX UI state from non-JFX context MUST go through this
* bridge. Direct JFXLauncher.x() calls are only allowed inside JFXLauncher.java.
*/
public final class JFXBridge {
private 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 setInstallProgressMethod;
private static volatile java.lang.reflect.Method setInstallStageMethod;
private static java.lang.reflect.Method method(String name, Class<?>... params) {
java.lang.reflect.Method m = null;
try {
Class<?> clazz = Class.forName(JFX_CLASS);
m = clazz.getMethod(name, params);
} catch (Throwable t) {
// JavaFX not available (CLI mode) or JFXLauncher not initialized.
}
return m;
}
/** Forward a game log line to the JFX UI. Safe no-op in CLI mode. */
public static void appendGameLog(String msg) {
if (appendGameLogMethod == null) {
appendGameLogMethod = method("appendGameLog", String.class);
}
if (appendGameLogMethod == null) {
return;
}
try {
appendGameLogMethod.invoke(null, msg);
} catch (Throwable t) {
appendGameLogMethod = 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) {
setInstallProgressMethod = method("setInstallProgress", String.class, int.class, int.class);
}
if (setInstallProgressMethod == null) {
return;
}
try {
setInstallProgressMethod.invoke(null, label, current, total);
} catch (Throwable t) {
setInstallProgressMethod = null;
}
}
/** Forward install stage to the JFX UI. Safe no-op in CLI mode. */
public static void setInstallStage(String stageName, int stageIndex, int stageCount) {
if (setInstallStageMethod == null) {
setInstallStageMethod = method("setInstallStage", String.class, int.class, int.class);
}
if (setInstallStageMethod == null) {
return;
}
try {
setInstallStageMethod.invoke(null, stageName, stageIndex, stageCount);
} catch (Throwable t) {
setInstallStageMethod = null;
}
}
}
@@ -1,5 +1,7 @@
package me.sashegdev.zernmc.launcher.utils; package me.sashegdev.zernmc.launcher.utils;
import me.sashegdev.zernmc.launcher.ui.jfx.JFXBridge;
import java.text.DecimalFormat; import java.text.DecimalFormat;
public class ProgressBar { public class ProgressBar {
@@ -14,11 +16,7 @@ public class ProgressBar {
currentLabel = label; currentLabel = label;
currentTotal = total; currentTotal = total;
try { JFXBridge.setInstallProgress(label, (int) current, (int) total);
Class<?> jfxClass = Class.forName("me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher");
java.lang.reflect.Method setProgress = jfxClass.getMethod("setInstallProgress", String.class, int.class, int.class);
setProgress.invoke(null, label, (int) current, (int) total);
} catch (Exception ignored) {}
if (total <= 0) { if (total <= 0) {
System.out.print("\r" + ZAnsi.cyan(label) + " ..."); System.out.print("\r" + ZAnsi.cyan(label) + " ...");
@@ -40,11 +38,7 @@ public class ProgressBar {
currentLabel = label; currentLabel = label;
currentTotal = totalBytes; currentTotal = totalBytes;
try { JFXBridge.setInstallProgress(label + " " + formatBytes(downloaded) + "/" + formatBytes(totalBytes), (int) downloaded, (int) totalBytes);
Class<?> jfxClass = Class.forName("me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher");
java.lang.reflect.Method setProgress = jfxClass.getMethod("setInstallProgress", String.class, int.class, int.class);
setProgress.invoke(null, label + " " + formatBytes(downloaded) + "/" + formatBytes(totalBytes), (int) downloaded, (int) totalBytes);
} catch (Exception ignored) {}
if (totalBytes <= 0) { if (totalBytes <= 0) {
System.out.print("\r" + ZAnsi.cyan(label) + " ..."); System.out.print("\r" + ZAnsi.cyan(label) + " ...");
@@ -71,11 +65,7 @@ public class ProgressBar {
currentLabel = label; currentLabel = label;
currentTotal = total; currentTotal = total;
try { JFXBridge.setInstallProgress(label, (int) current, (int) (total > 0 ? total : 100));
Class<?> jfxClass = Class.forName("me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher");
java.lang.reflect.Method setProgress = jfxClass.getMethod("setInstallProgress", String.class, int.class, int.class);
setProgress.invoke(null, label, (int) current, (int) (total > 0 ? total : 100));
} catch (Exception ignored) {}
if (total <= 0) { if (total <= 0) {
char[] spinner = {'|', '/', '-', '\\'}; char[] spinner = {'|', '/', '-', '\\'};
@@ -92,11 +82,7 @@ public class ProgressBar {
} }
public static void setStage(String stageName, int stageIndex, int stageCount) { public static void setStage(String stageName, int stageIndex, int stageCount) {
try { JFXBridge.setInstallStage(stageName, stageIndex, stageCount);
Class<?> jfxClass = Class.forName("me.sashegdev.zernmc.launcher.ui.jfx.JFXLauncher");
java.lang.reflect.Method setStage = jfxClass.getMethod("setInstallStage", String.class, int.class, int.class);
setStage.invoke(null, stageName, stageIndex, stageCount);
} catch (Exception ignored) {}
} }
public static void clearLine() { public static void clearLine() {
+7 -7
View File
@@ -18,8 +18,8 @@
</modules> </modules>
<properties> <properties>
<revision>1.0.15</revision> <revision>1.0.16</revision>
<hotfix>3</hotfix> <hotfix>0</hotfix>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -74,31 +74,31 @@
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId> <artifactId>javafx-controls</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId> <artifactId>javafx-web</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId> <artifactId>javafx-graphics</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId> <artifactId>javafx-base</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId> <artifactId>javafx-media</artifactId>
<version>23</version> <version>23.0.1</version>
<classifier>win</classifier> <classifier>win</classifier>
</dependency> </dependency>
</dependencies> </dependencies>
+7 -2
View File
@@ -1332,8 +1332,13 @@ def generate_launcher_builds_meta():
rel_path = str(file_path.relative_to(BUILDS_DIR)) rel_path = str(file_path.relative_to(BUILDS_DIR))
# Only include runtime files needed for launcher updates # Only include runtime files needed for launcher updates
# Skip: JRE, JavaFX, old ZIPs, extracted versions, docs, root JARs # Skip: JRE, old ZIPs, extracted versions, docs, root JARs.
if rel_path.startswith(("jre21/", "lib/", "lib-javafx/", "versions/", "libs/")): # lib/javafx/*-win.jar IS included so existing clients get the
# JavaFX update (e.g. 23 -> 23.0.1 WebKit WebSocket fix) via the
# incremental updater, not only through a full ZIP reinstall.
if rel_path.startswith(("jre21/", "lib-javafx/", "versions/", "libs/", "logs/")):
continue
if rel_path.startswith("lib/") and not rel_path.startswith("lib/javafx/"):
continue continue
if rel_path.endswith(".zip") or rel_path in ("README.txt", "build.version"): if rel_path.endswith(".zip") or rel_path in ("README.txt", "build.version"):
continue continue