Compare commits
10 Commits
82391e10ea
...
UI
| Author | SHA1 | Date | |
|---|---|---|---|
| 454d3389b6 | |||
| 012d1635dc | |||
| 70c4815032 | |||
| a46ef3e834 | |||
| cba8259e59 | |||
| 08417efe2f | |||
| 991252130d | |||
| 6fa97b7fda | |||
| 83abc600f3 | |||
| 300ce4b60b |
@@ -42,12 +42,21 @@
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.openjfx:*</artifact>
|
||||
<excludes>
|
||||
<exclude>**/*</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<dependencySet>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<unpack>true</unpack>
|
||||
<scope>runtime</scope>
|
||||
<excludes>
|
||||
<exclude>org.openjfx:*</exclude>
|
||||
</excludes>
|
||||
</dependencySet>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -85,11 +94,16 @@
|
||||
<configuration>
|
||||
<outfile>../server/builds/ZernMCLauncher-${project.version}.exe</outfile>
|
||||
<jar>../server/builds/ZernMCLauncher.jar</jar>
|
||||
<headerType>console</headerType>
|
||||
<headerType>gui</headerType>
|
||||
<dontWrapJar>false</dontWrapJar>
|
||||
<jre>
|
||||
<path>jre21</path>
|
||||
<minVersion>21</minVersion>
|
||||
<opts>
|
||||
<opt>--module-path=lib-javafx</opt>
|
||||
<opt>--add-modules=javafx.controls,javafx.web</opt>
|
||||
<opt>--add-reads=javafx.graphics=ALL-UNNAMED</opt>
|
||||
</opts>
|
||||
</jre>
|
||||
<versionInfo>
|
||||
<fileVersion>${project.version}.0</fileVersion>
|
||||
@@ -105,6 +119,9 @@
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<skip>${skip.launch4j}</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
@@ -121,6 +138,9 @@
|
||||
<copy>
|
||||
<fileset />
|
||||
</copy>
|
||||
<copy>
|
||||
<fileset />
|
||||
</copy>
|
||||
<zip />
|
||||
</target>
|
||||
</configuration>
|
||||
@@ -146,6 +166,22 @@
|
||||
<server.url>http://87.120.187.36:1582</server.url>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>win</id>
|
||||
<properties>
|
||||
<os.suffix>win</os.suffix>
|
||||
<javafx.classifier>win</javafx.classifier>
|
||||
<skip.launch4j>false</skip.launch4j>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>linux</id>
|
||||
<properties>
|
||||
<os.suffix>linux</os.suffix>
|
||||
<javafx.classifier>linux</javafx.classifier>
|
||||
<skip.launch4j>true</skip.launch4j>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -174,7 +210,10 @@
|
||||
<mainClass>me.sashegdev.zernmc.launcher.Main</mainClass>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<project.organization.name>ZernMC</project.organization.name>
|
||||
<javafx.classifier>win</javafx.classifier>
|
||||
<skip.launch4j>false</skip.launch4j>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<os.suffix>win</os.suffix>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.inceptionYear>2026</project.inceptionYear>
|
||||
</properties>
|
||||
|
||||
+84
-6
@@ -17,6 +17,9 @@
|
||||
<project.inceptionYear>2026</project.inceptionYear>
|
||||
<project.description>ZernMC Launcher - just a minimalistic launcher by SashegDev</project.description>
|
||||
<mainClass>me.sashegdev.zernmc.launcher.Main</mainClass>
|
||||
<javafx.classifier>win</javafx.classifier>
|
||||
<os.suffix>win</os.suffix>
|
||||
<skip.launch4j>false</skip.launch4j>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -74,11 +77,27 @@
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>21.0.2</version>
|
||||
<classifier>win</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-web</artifactId>
|
||||
<version>21.0.2</version>
|
||||
<classifier>win</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>21.0.2</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-web</artifactId>
|
||||
<version>21.0.2</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
@@ -130,12 +149,22 @@
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<!-- Исключаем JavaFX из shade полностью (он будет в lib-javafx) -->
|
||||
<filter>
|
||||
<artifact>org.openjfx:*</artifact>
|
||||
<excludes>
|
||||
<exclude>**/*</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<dependencySet>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<unpack>true</unpack>
|
||||
<scope>runtime</scope>
|
||||
<excludes>
|
||||
<exclude>org.openjfx:*</exclude>
|
||||
</excludes>
|
||||
</dependencySet>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -163,11 +192,14 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Launch4j для создания .exe -->
|
||||
<!-- Launch4j для создания .exe (только для Windows) -->
|
||||
<plugin>
|
||||
<groupId>com.akathist.maven.plugins.launch4j</groupId>
|
||||
<artifactId>launch4j-maven-plugin</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<configuration>
|
||||
<skip>${skip.launch4j}</skip>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>l4j</id>
|
||||
@@ -178,11 +210,16 @@
|
||||
<configuration>
|
||||
<outfile>../server/builds/ZernMCLauncher-${project.version}.exe</outfile>
|
||||
<jar>../server/builds/ZernMCLauncher.jar</jar>
|
||||
<headerType>console</headerType>
|
||||
<headerType>gui</headerType>
|
||||
<dontWrapJar>false</dontWrapJar>
|
||||
<jre>
|
||||
<path>jre21</path>
|
||||
<minVersion>21</minVersion>
|
||||
<opts>
|
||||
<opt>--module-path=lib-javafx</opt>
|
||||
<opt>--add-modules=javafx.controls,javafx.web</opt>
|
||||
<opt>--add-reads=javafx.graphics=ALL-UNNAMED</opt>
|
||||
</opts>
|
||||
</jre>
|
||||
<versionInfo>
|
||||
<fileVersion>${project.version}.0</fileVersion>
|
||||
@@ -218,11 +255,22 @@
|
||||
<fileset dir="${user.home}/launcher/jre/jre21"/>
|
||||
</copy>
|
||||
|
||||
<!-- Создаём zip только с .exe и jre21 (без .jar и build.version) -->
|
||||
<zip destfile="../server/builds/ZernMCLauncher-${project.version}.zip"
|
||||
<!-- Копируем JavaFX JAR в builds -->
|
||||
<copy todir="../server/builds/lib-javafx" overwrite="true">
|
||||
<fileset dir="${project.build.directory}/lib-javafx"/>
|
||||
</copy>
|
||||
|
||||
<!-- Копируем shell script для Linux -->
|
||||
<copy file="${project.basedir}/src/main/resources/launcher.sh"
|
||||
todir="../server/builds"
|
||||
overwrite="true"/>
|
||||
<chmod file="../server/builds/launcher.sh" perm="+x"/>
|
||||
|
||||
<!-- Создаём zip с .exe, jre21, lib-javafx и launcher.sh (без .jar и build.version) -->
|
||||
<zip destfile="../server/builds/ZernMCLauncher-${project.version}-${os.suffix}.zip"
|
||||
basedir="../server/builds"
|
||||
includes="ZernMCLauncher.exe,jre21/**"
|
||||
excludes="*.jar,build.version"/>
|
||||
includes="ZernMCLauncher.exe,ZernMCLauncher.jar,jre21/**,lib-javafx/**,launcher.sh"
|
||||
excludes="build.version"/>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -254,5 +302,35 @@
|
||||
<server.url>http://87.120.187.36:1582</server.url>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<!-- ==================== WINDOWS BUILD ==================== -->
|
||||
<profile>
|
||||
<id>win</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>windows</family>
|
||||
</os>
|
||||
</activation>
|
||||
<properties>
|
||||
<javafx.classifier>win</javafx.classifier>
|
||||
<os.suffix>win</os.suffix>
|
||||
<skip.launch4j>false</skip.launch4j>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<!-- ==================== LINUX BUILD ==================== -->
|
||||
<profile>
|
||||
<id>linux</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>unix</family>
|
||||
</os>
|
||||
</activation>
|
||||
<properties>
|
||||
<javafx.classifier>linux</javafx.classifier>
|
||||
<os.suffix>linux</os.suffix>
|
||||
<skip.launch4j>true</skip.launch4j>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -34,6 +34,7 @@ public class Main {
|
||||
startWebUI(args);
|
||||
} catch (Exception e) {
|
||||
System.err.println(ZAnsi.red("UI не запустился: " + e.getMessage()));
|
||||
e.printStackTrace();
|
||||
System.out.println(ZAnsi.yellow("Переключаюсь на режим TUI..."));
|
||||
runTUI(args);
|
||||
}
|
||||
@@ -70,12 +71,16 @@ public class Main {
|
||||
// Даем серверу время запуститься
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Проверяем headless перед запуском JavaFX
|
||||
if (java.awt.GraphicsEnvironment.isHeadless()) {
|
||||
System.out.println(ZAnsi.yellow("Дисплей недоступен, переключаюсь на TUI..."));
|
||||
WebServer.stop();
|
||||
runTUI(args);
|
||||
return;
|
||||
// Проверяем headless перед запуском JavaFX (только для не-Windows систем)
|
||||
if (!System.getProperty("os.name").toLowerCase().contains("win")) {
|
||||
boolean isHeadless = java.awt.GraphicsEnvironment.isHeadless();
|
||||
String display = System.getenv("DISPLAY");
|
||||
if (isHeadless && (display == null || display.isEmpty())) {
|
||||
System.out.println(ZAnsi.yellow("Дисплей недоступен, переключаюсь на TUI..."));
|
||||
WebServer.stop();
|
||||
runTUI(args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Проверка обновлений лаунчера
|
||||
@@ -181,12 +186,20 @@ public class Main {
|
||||
try {
|
||||
String javaPath = System.getProperty("java.home") + "/bin/java";
|
||||
String jarPath = getCurrentJarPath().toAbsolutePath().toString();
|
||||
String launcherDir = jarPath.substring(0, jarPath.lastIndexOf(java.io.File.separator));
|
||||
String javafxPath = launcherDir + java.io.File.separator + "lib-javafx";
|
||||
|
||||
System.out.println(ZAnsi.brightGreen("Перезапуск лаунчера с новой версией..."));
|
||||
|
||||
new ProcessBuilder(javaPath, "-jar", jarPath)
|
||||
.inheritIO()
|
||||
.start();
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
javaPath,
|
||||
"--module-path=" + javafxPath,
|
||||
"--add-modules=javafx.controls,javafx.web",
|
||||
"--add-reads=javafx.graphics=ALL-UNNAMED",
|
||||
"-jar", jarPath
|
||||
);
|
||||
pb.inheritIO();
|
||||
pb.start();
|
||||
|
||||
System.exit(0);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -17,11 +17,6 @@ public class UIWindow extends Application {
|
||||
private static int port;
|
||||
|
||||
public static void start(int port) {
|
||||
// Backup проверка headless
|
||||
if (java.awt.GraphicsEnvironment.isHeadless()) {
|
||||
throw new RuntimeException("Headless environment - no display available");
|
||||
}
|
||||
|
||||
UIWindow.port = port;
|
||||
UIWindow.url = "http://localhost:" + port;
|
||||
Application.launch(UIWindow.class);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
JAVA_HOME="$SCRIPT_DIR/jre21"
|
||||
JAVA="$JAVA_HOME/bin/java"
|
||||
|
||||
JAVAFX_PATH="$SCRIPT_DIR/lib-javafx"
|
||||
|
||||
exec "$JAVA" \
|
||||
--module-path="$JAVAFX_PATH" \
|
||||
--add-modules=javafx.controls,javafx.web \
|
||||
--add-reads=javafx.graphics=ALL-UNNAMED \
|
||||
-jar "$SCRIPT_DIR/ZernMCLauncher.jar" "$@"
|
||||
@@ -686,6 +686,30 @@ body {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.progress-file {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.progress-fill.animated {
|
||||
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary), var(--accent-primary));
|
||||
background-size: 200% 100%;
|
||||
animation: progressShimmer 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes progressShimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
/* ==================== LOADING ==================== */
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
|
||||
@@ -325,7 +325,43 @@ class App {
|
||||
}
|
||||
|
||||
this.addLog('Обновление сборки...', 'info');
|
||||
this.showProgress('Обновление сборки...');
|
||||
this.enablePlayButton(false);
|
||||
|
||||
const progressContainer = this.showAnimatedProgress('Обновление сборки...');
|
||||
|
||||
let eventSource = null;
|
||||
let progressData = { totalFiles: 0, downloadedFiles: 0 };
|
||||
|
||||
try {
|
||||
eventSource = new EventSource(`/api/instances/${this.currentInstance.name}/install/stream`);
|
||||
eventSource.onmessage = (e) => {
|
||||
try {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.phase === 'starting') {
|
||||
progressData.totalFiles = data.totalFiles || 0;
|
||||
this.updateAnimatedProgress(progressContainer, `Загрузка: 0/${progressData.totalFiles} файлов`, 5);
|
||||
} else if (data.phase === 'downloading') {
|
||||
progressData.downloadedFiles = data.downloadedFiles || 0;
|
||||
const total = data.totalFiles || progressData.totalFiles || 1;
|
||||
const percent = Math.round((progressData.downloadedFiles / total) * 100);
|
||||
const fileName = data.currentFile ? data.currentFile.split('/').pop() : '';
|
||||
const filePercent = data.filePercent || 0;
|
||||
this.updateAnimatedProgress(progressContainer,
|
||||
`Файл ${progressData.downloadedFiles}/${total} (${percent}%)`,
|
||||
percent,
|
||||
fileName,
|
||||
filePercent
|
||||
);
|
||||
} else if (data.phase === 'complete') {
|
||||
this.updateAnimatedProgress(progressContainer, 'Готово!', 100);
|
||||
} else if (data.phase === 'error') {
|
||||
this.addLog('Ошибка: ' + (data.message || 'неизвестная ошибка'), 'error');
|
||||
}
|
||||
} catch (err) {}
|
||||
};
|
||||
} catch (e) {
|
||||
console.log('SSE not available, using fallback progress');
|
||||
}
|
||||
|
||||
const result = await this.request('/instances/zernmc/install', {
|
||||
method: 'POST',
|
||||
@@ -335,6 +371,10 @@ class App {
|
||||
})
|
||||
});
|
||||
|
||||
if (eventSource) {
|
||||
eventSource.close();
|
||||
}
|
||||
|
||||
this.hideProgress();
|
||||
|
||||
if (result.success) {
|
||||
@@ -362,6 +402,31 @@ class App {
|
||||
}
|
||||
}
|
||||
|
||||
showAnimatedProgress(text) {
|
||||
const progress = document.getElementById('download-progress');
|
||||
const progressText = document.getElementById('progress-text');
|
||||
const progressFill = document.getElementById('progress-fill');
|
||||
|
||||
progress.classList.remove('hidden');
|
||||
progressText.innerHTML = `<div class="progress-label">${text}</div>
|
||||
<div class="progress-file"></div>`;
|
||||
progressFill.style.width = '5%';
|
||||
progressFill.classList.add('animated');
|
||||
|
||||
return { container: progress, text: progressText, fill: progressFill };
|
||||
}
|
||||
|
||||
updateAnimatedProgress(progressContainer, text, percent, fileName = '', filePercent = 0) {
|
||||
const { text: progressText, fill: progressFill } = progressContainer;
|
||||
if (fileName) {
|
||||
progressText.innerHTML = `<div class="progress-label">${text}</div>
|
||||
<div class="progress-file">${fileName} (${filePercent}%)</div>`;
|
||||
} else {
|
||||
progressText.innerHTML = `<div class="progress-label">${text}</div>`;
|
||||
}
|
||||
progressFill.style.width = percent + '%';
|
||||
}
|
||||
|
||||
// ==================== DOWNLOAD MODAL ====================
|
||||
async showDownloadModal() {
|
||||
document.getElementById('download-modal').classList.remove('hidden');
|
||||
|
||||
Reference in New Issue
Block a user