diff --git a/launcher/dependency-reduced-pom.xml b/launcher/dependency-reduced-pom.xml
index 41197c7..477027c 100644
--- a/launcher/dependency-reduced-pom.xml
+++ b/launcher/dependency-reduced-pom.xml
@@ -91,6 +91,24 @@
+
+
+ global
+
+ ZernMC Launcher
+ global
+ http://87.120.187.36:1582
+
+
+
+ zernmc
+
+ ZernMC Private Launcher
+ zernmc
+ http://87.120.187.36:1582
+
+
+
21
me.sashegdev.zernmc.launcher.Main
diff --git a/launcher/pom.xml b/launcher/pom.xml
index e51e2fa..870a7f7 100644
--- a/launcher/pom.xml
+++ b/launcher/pom.xml
@@ -153,4 +153,29 @@
+
+
+
+ global
+
+ true
+
+
+ global
+ ZernMC Launcher
+ http://87.120.187.36:1582
+
+
+
+
+
+
+ zernmc
+
+ zernmc
+ ZernMC Private Launcher
+ http://87.120.187.36:1582
+
+
+
\ No newline at end of file
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/Main.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/Main.java
index fb73deb..8e97e0a 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/Main.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/Main.java
@@ -4,7 +4,6 @@ import me.sashegdev.zernmc.launcher.auth.AuthManager;
import me.sashegdev.zernmc.launcher.menu.*;
import me.sashegdev.zernmc.launcher.ui.ArrowMenu;
import me.sashegdev.zernmc.launcher.utils.*;
-
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
@@ -23,13 +22,12 @@ public class Main {
System.setProperty("file.encoding", "UTF-8");
System.setProperty("sun.err.encoding", "UTF-8");
System.setProperty("sun.stdout.encoding", "UTF-8");
- java.nio.charset.Charset.defaultCharset();
- ZAnsi.install();
+ ZAnsi.install();
System.out.print("\033[H\033[2J");
System.out.println(ZAnsi.brightGreen("Добро пожаловать в ZernMC Launcher " + CURRENT_VERSION));
- //проверка всех сервисов при старте
+ // Проверка всех сервисов при старте
ZHttpClient.checkAllServicesOnStartup();
checkAndAutoUpdateLauncher();
@@ -49,8 +47,8 @@ public class Main {
} else {
System.out.println(ZAnsi.brightGreen("Добро пожаловать обратно, " + AuthManager.getUsername() + "!"));
}
- // === КОНЕЦ АВТОРИЗАЦИИ ===
+ // === ГЛАВНЫЙ ЦИКЛ ===
try {
mainLoop();
} catch (Exception e) {
@@ -63,7 +61,6 @@ public class Main {
private static void checkAndAutoUpdateLauncher() {
System.out.println(ZAnsi.cyan("Проверка обновлений лаунчера..."));
-
try {
String json = ZHttpClient.getLauncherVersionInfo();
String serverVersion = extractVersion(json);
@@ -74,13 +71,11 @@ public class Main {
if (Version.isNewer(CURRENT_VERSION, serverVersion)) {
System.out.println(ZAnsi.brightYellow("\nДоступна новая версия лаунчера! (" + serverVersion + ")"));
System.out.println(ZAnsi.cyan("Начинается автоматическое обновление...\n"));
-
performAutoUpdate(serverVersion);
restartLauncher();
} else {
System.out.println(ZAnsi.brightGreen("Лаунчер актуален."));
}
-
} catch (Exception e) {
System.out.println(ZAnsi.yellow("Не удалось проверить обновления лаунчера."));
System.out.println(ZAnsi.white("Ошибка: ") + e.getMessage());
@@ -109,9 +104,7 @@ public class Main {
long size = Files.size(tempJar);
System.out.println(ZAnsi.brightGreen("Скачано успешно (" + (size / 1024) + " KB)"));
- // Заменяем текущий jar
Files.move(tempJar, currentJar, StandardCopyOption.REPLACE_EXISTING);
-
System.out.println(ZAnsi.brightGreen("Обновление успешно установлено!"));
}
@@ -152,27 +145,73 @@ public class Main {
}
}
+ // ====================== ГЛАВНЫЙ ЦИКЛ ======================
private static void mainLoop() throws Exception {
+ if (Config.isZernMCBuild()) {
+ zernMCFlow();
+ } else {
+ globalFlow();
+ }
+ }
+
+ // ====================== ZERNMC FLOW ======================
+ private static void zernMCFlow() throws Exception {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.header("=== ZernMC Private Launcher ==="));
+
+ // 1. Проверка подключения к серверу
+ System.out.println(ZAnsi.cyan("Проверка подключения к ZernMC серверу..."));
+ try {
+ String response = ZHttpClient.get("/health");
+ System.out.println(ZAnsi.brightGreen("✓ Сервер доступен"));
+ } catch (Exception e) {
+ System.out.println(ZAnsi.brightRed("✗ Не удалось подключиться к ZernMC серверу"));
+ System.out.println(ZAnsi.white("Ошибка: " + e.getMessage()));
+ ConsoleUtils.pause();
+ System.exit(1);
+ }
+
+ // 2. Авторизация
+ boolean sessionRestored = AuthManager.loadSavedSession();
+ if (!sessionRestored) {
+ LoginMenu loginMenu = new LoginMenu();
+ boolean loggedIn = loginMenu.show();
+ if (!loggedIn) {
+ System.exit(0);
+ }
+ } else {
+ System.out.println(ZAnsi.brightGreen("Добро пожаловать обратно, " + AuthManager.getUsername() + "!"));
+ }
+
+ // 3. Запуск меню (LaunchMenu сам определит режим и вызовет нужный flow)
+ LaunchMenu launchMenu = new LaunchMenu();
+ launchMenu.show(); // ← Здесь будет вызван showZernMCOnly() внутри
+ }
+
+ // ====================== GLOBAL FLOW ======================
+ private static void globalFlow() throws Exception {
while (true) {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.header("=== ZernMC Launcher ==="));
+
List options = List.of(
- "Запустить игру",
- "Проверка обновлений",
- "Настройки",
- "Проверка подключения к серверам Zern",
- "Выход"
+ "Запустить игру",
+ "Проверка обновлений",
+ "Настройки",
+ "Проверка подключения к серверам",
+ "Выход"
);
ArrowMenu menu = new ArrowMenu("Главное меню", options);
int choice = menu.show();
if (choice == -1 || choice == 4) {
- System.out.print("\033[H\033[2J");
System.out.println(ZAnsi.yellow("До свидания!"));
break;
}
switch (choice) {
- case 0 -> new LaunchMenu().show();
+ case 0 -> new LaunchMenu().show(); // обычный LaunchMenu
case 1 -> new UpdateMenu().show();
case 2 -> new SettingsMenu().show();
case 3 -> new ServerCheckMenu().show();
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java
index f6cd5b3..82dc04f 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java
@@ -203,31 +203,23 @@ public class AuthManager {
if (!isLoggedIn()) return false;
try {
String response = ZHttpClient.get("/auth/pass/my");
- return response.contains("\"is_active\":true");
+ JsonObject json = JsonParser.parseString(response).getAsJsonObject();
+ return json.has("has_active") && json.get("has_active").getAsBoolean();
} catch (Exception e) {
- System.err.println("Не удалось проверить проходки: " + e.getMessage());
+ System.err.println(ZAnsi.red("Не удалось проверить проходки: ") + e.getMessage());
return false;
}
}
- public static String activatePass(String passCode) {
+ public static String getPassStatus() {
+ if (!isLoggedIn()) return "Не авторизован";
try {
- String json = "{\"pass_code\":\"" + passCode.toUpperCase() + "\"}";
- SimpleHttpResponse resp = post("/auth/pass/activate", json);
-
- System.out.println(ZAnsi.cyan("[AUTH] Активация проходки: HTTP " + resp.statusCode()));
-
- if (resp.statusCode() == 200) {
- return "Проходка успешно активирована!";
- } else if (resp.statusCode() == 401) {
- return "Ошибка: Требуется авторизация. Перезайдите в аккаунт.";
- } else {
- String error = extractError(resp.body());
- return "Ошибка: " + error;
- }
+ String response = ZHttpClient.get("/auth/pass/my");
+ JsonObject json = JsonParser.parseString(response).getAsJsonObject();
+ boolean hasActive = json.has("has_active") && json.get("has_active").getAsBoolean();
+ return hasActive ? "Есть активная проходка" : "Проходка отсутствует";
} catch (Exception e) {
- e.printStackTrace();
- return "Ошибка соединения: " + e.getMessage();
+ return "Ошибка проверки";
}
}
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LaunchMenu.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LaunchMenu.java
index 8c22af4..17d28e7 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LaunchMenu.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LaunchMenu.java
@@ -10,12 +10,15 @@ import me.sashegdev.zernmc.launcher.minecraft.installer.VersionInstaller;
import me.sashegdev.zernmc.launcher.minecraft.model.LaunchOptions;
import me.sashegdev.zernmc.launcher.minecraft.model.MinecraftVersion;
import me.sashegdev.zernmc.launcher.ui.ArrowMenu;
+import me.sashegdev.zernmc.launcher.utils.Config;
import me.sashegdev.zernmc.launcher.utils.ConsoleUtils;
import me.sashegdev.zernmc.launcher.utils.Input;
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
+import java.awt.*;
import java.io.IOException;
+import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -23,6 +26,151 @@ import java.util.stream.Collectors;
public class LaunchMenu {
public void show() throws Exception {
+ if (Config.isZernMCBuild()) {
+ showZernMCOnly();
+ } else {
+ showGlobal();
+ }
+ }
+
+ // ====================== ZERNMC BUILD ======================
+ private void showZernMCOnly() throws Exception {
+ while (true) {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.header("=== ZernMC Private Launcher ==="));
+ System.out.println(ZAnsi.cyan("Доступны только серверные сборки"));
+
+ if (!awaitActivePass()) {
+ return;
+ }
+
+ PackDownloader tempDownloader = new PackDownloader(null);
+ List availablePacks = tempDownloader.getAvailablePacks();
+
+ if (availablePacks.isEmpty()) {
+ System.out.println(ZAnsi.yellow("На данный момент нет доступных сборок на сервере."));
+ ConsoleUtils.pause();
+ return;
+ }
+
+ List options = availablePacks.stream()
+ .map(p -> String.format("%s [%s + %s v%d] — %d файлов",
+ p.getName(),
+ p.getMinecraftVersion(),
+ p.getLoaderType(),
+ p.getVersion(),
+ p.getFilesCount()))
+ .collect(Collectors.toList());
+
+ options.add("Назад в главное меню");
+
+ ArrowMenu menu = new ArrowMenu("Выберите сборку", options);
+ int choice = menu.show();
+
+ if (choice == -1 || choice == options.size() - 1) return;
+
+ ServerPack selected = availablePacks.get(choice);
+ installAndRunServerPack(selected);
+ }
+ }
+
+ private boolean awaitActivePass() throws Exception {
+ if (AuthManager.hasActivePass()) {
+ System.out.println(ZAnsi.brightGreen("✓ Активная проходка подтверждена"));
+ return true;
+ }
+
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.brightRed("У вас нет активной проходки!"));
+ System.out.println(ZAnsi.white("Для доступа к сборкам ZernMC требуется активная проходка."));
+ System.out.println();
+
+ openActivationWebsite();
+
+ System.out.println(ZAnsi.cyan("Ожидаем активацию проходки... (проверка каждые 10 секунд)"));
+ System.out.println(ZAnsi.white("Нажмите Enter для отмены"));
+
+ for (int i = 0; i < 60; i++) {
+ try {
+ if (System.in.available() > 0) {
+ Input.readLine();
+ System.out.println(ZAnsi.yellow("\nОжидание отменено."));
+ return false;
+ }
+ } catch (Exception ignored) {}
+
+ Thread.sleep(10000);
+
+ if (AuthManager.hasActivePass()) {
+ System.out.println(ZAnsi.brightGreen("\n✓ Проходка успешно активирована!"));
+ return true;
+ }
+
+ System.out.print(ZAnsi.cyan("."));
+ if ((i + 1) % 6 == 0) System.out.println();
+ }
+
+ System.out.println(ZAnsi.brightRed("\n\nВремя ожидания истекло."));
+ return false;
+ }
+
+ private void openActivationWebsite() {
+ //String url = "https://launcher.ru.zernmc.ru/activate-pass";
+ String url = ZHttpClient.getBaseUrl() + "/activate-pass";
+
+ try {
+ if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
+ Desktop.getDesktop().browse(new URI(url));
+ System.out.println(ZAnsi.cyan("Браузер открыт: " + url));
+ } else {
+ System.out.println(ZAnsi.yellow("Не удалось открыть браузер автоматически."));
+ System.out.println(ZAnsi.white("Откройте вручную: " + url));
+ }
+ } catch (Exception e) {
+ System.out.println(ZAnsi.brightRed("Ошибка открытия браузера: " + e.getMessage()));
+ System.out.println(ZAnsi.white("Ссылка: " + url));
+ }
+ }
+
+ private void installAndRunServerPack(ServerPack selected) throws Exception {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.header("Установка сборки: " + selected.getName()));
+
+ System.out.println(ZAnsi.white(" Minecraft: ") + selected.getMinecraftVersion());
+ System.out.println(ZAnsi.white(" Лоадер: ") + selected.getLoaderType() +
+ (selected.getLoaderVersion() != null ? " " + selected.getLoaderVersion() : ""));
+ System.out.println(ZAnsi.white(" Версия: v") + selected.getVersion());
+ System.out.println(ZAnsi.white(" Файлов: ") + selected.getFilesCount());
+
+ String localName = askPackName();
+ if (localName == null) return;
+
+ if (InstanceManager.getInstance(localName) != null) {
+ System.out.println(ZAnsi.brightRed("Сборка с таким именем уже существует!"));
+ ConsoleUtils.pause();
+ return;
+ }
+
+ InstanceManager.createInstanceFolder(localName);
+ Instance newInstance = InstanceManager.getInstance(localName);
+
+ PackDownloader packDownloader = new PackDownloader(newInstance);
+ boolean success = packDownloader.installOrUpdatePack(selected.getName(), selected);
+
+ if (!success) {
+ System.out.println(ZAnsi.brightRed("\n[FAIL] Не удалось установить сборку."));
+ ConsoleUtils.pause();
+ return;
+ }
+
+ System.out.println(ZAnsi.brightGreen("\n[OK] Сборка '" + localName + "' успешно установлена!"));
+ ConsoleUtils.pause();
+
+ launchExistingInstance(newInstance);
+ }
+
+ // ====================== GLOBAL BUILD ======================
+ private void showGlobal() throws Exception {
while (true) {
ConsoleUtils.clearScreen();
List instances = InstanceManager.getAllInstances();
@@ -37,11 +185,10 @@ public class LaunchMenu {
ArrowMenu menu = new ArrowMenu("Управление сборками", options);
int choice = menu.show();
- if (choice == -1) break;
- if (choice == options.size() - 1) break;
+ if (choice == -1 || choice == options.size() - 1) break;
if (choice == instances.size()) {
- installNewPack();
+ installNewPackGlobal();
continue;
}
@@ -50,289 +197,101 @@ public class LaunchMenu {
}
}
- private void installNewPack() throws Exception {
+ private void installNewPackGlobal() throws Exception {
ConsoleUtils.clearScreen();
-
+
List options = List.of(
- "Установить сборку с сервера ZernMC",
- "Установить Vanilla Minecraft",
- "Создать сборку вручную (Fabric/Forge)",
- "Назад"
+ "Установить сборку с сервера ZernMC",
+ "Установить Vanilla Minecraft",
+ "Создать сборку вручную (Fabric/Forge)",
+ "Назад"
);
-
+
ArrowMenu menu = new ArrowMenu("Установка новой сборки", options);
int choice = menu.show();
-
+
if (choice == -1 || choice == 3) return;
-
+
switch (choice) {
- case 0 -> {
- try {
- installServerPack();
- } catch (Exception e) {
- System.out.println(ZAnsi.brightRed("Ошибка: " + e.getMessage()));
- e.printStackTrace();
- ConsoleUtils.pause();
- }
- }
+ case 0 -> installServerPackGlobal();
case 1 -> createVanillaInstance();
case 2 -> createCustomInstance();
}
}
- private void installServerPack() throws Exception {
- if (!AuthManager.hasActivePass()) {
- ConsoleUtils.clearScreen();
- System.out.println(ZAnsi.brightRed("У вас нет активной проходки!"));
- System.out.println(ZAnsi.white("Чтобы скачивать сборки с сервера ZernMC, необходимо активировать проходку."));
- System.out.println();
- System.out.print(ZAnsi.white("Введите код проходки (ZERN-XXXXXXX) или Enter для отмены: "));
-
- String code = Input.readLine();
- if (code.isEmpty()) return;
-
- String result = AuthManager.activatePass(code);
- System.out.println(ZAnsi.cyan(result));
-
- if (!result.contains("успешно")) {
- ConsoleUtils.pause();
- return;
- }
-
- // Повторная проверка
- if (!AuthManager.hasActivePass()) {
- System.out.println(ZAnsi.brightRed("Не удалось активировать проходку."));
- ConsoleUtils.pause();
- return;
- }
- }
+ private void installServerPackGlobal() throws Exception {
+ if (!awaitActivePass()) return;
ConsoleUtils.clearScreen();
- System.out.println(ZAnsi.cyan("Получение списка доступных сборок с сервера..."));
-
+ System.out.println(ZAnsi.cyan("Получение списка доступных сборок..."));
+
PackDownloader tempDownloader = new PackDownloader(null);
List availablePacks = tempDownloader.getAvailablePacks();
-
+
if (availablePacks.isEmpty()) {
System.out.println(ZAnsi.yellow("Нет доступных сборок на сервере."));
ConsoleUtils.pause();
return;
}
-
- // Исправлено: убраны спецсимволы для Windows
+
List options = availablePacks.stream()
- .map(p -> String.format("%s [%s + %s v%d] - %d файлов",
- p.getName(),
- p.getMinecraftVersion(),
- p.getLoaderType(),
- p.getVersion(),
- p.getFilesCount()))
- .collect(Collectors.toList());
+ .map(p -> String.format("%s [%s + %s v%d] — %d файлов",
+ p.getName(),
+ p.getMinecraftVersion(),
+ p.getLoaderType(),
+ p.getVersion(),
+ p.getFilesCount()))
+ .collect(Collectors.toList());
options.add("Назад");
-
+
ArrowMenu menu = new ArrowMenu("Выберите сборку для установки", options);
int choice = menu.show();
-
+
if (choice == -1 || choice == options.size() - 1) return;
-
+
ServerPack selected = availablePacks.get(choice);
-
- // Запрашиваем имя для локальной сборки
+
ConsoleUtils.clearScreen();
System.out.println(ZAnsi.header("Установка сборки: " + selected.getName()));
- System.out.println(ZAnsi.white(" Minecraft: ") + selected.getMinecraftVersion());
- System.out.println(ZAnsi.white(" Лоадер: ") + selected.getLoaderType() + " " + selected.getLoaderVersion());
- System.out.println(ZAnsi.white(" Версия: v") + selected.getVersion());
- System.out.println(ZAnsi.white(" Файлов: ") + selected.getFilesCount());
- System.out.println();
-
- System.out.print(ZAnsi.white("Введите название локальной сборки (Enter = использовать имя пака): "));
- String localName = Input.readLine();
- if (localName.isEmpty()) {
- localName = selected.getName();
- }
-
- // Проверяем, существует ли уже такая сборка
+
+ System.out.print(ZAnsi.white("\nВведите название локальной сборки (Enter = имя пака): "));
+ String localName = Input.readLine().trim();
+ if (localName.isEmpty()) localName = selected.getName();
+
if (InstanceManager.getInstance(localName) != null) {
System.out.println(ZAnsi.brightRed("Сборка с таким именем уже существует!"));
ConsoleUtils.pause();
return;
}
-
- // Создаем инстанс
+
InstanceManager.createInstanceFolder(localName);
Instance newInstance = InstanceManager.getInstance(localName);
-
- // Устанавливаем сборку
+
PackDownloader packDownloader = new PackDownloader(newInstance);
boolean success = packDownloader.installOrUpdatePack(selected.getName(), selected);
-
+
if (success) {
System.out.println(ZAnsi.brightGreen("\n[OK] Сборка '" + localName + "' успешно установлена!"));
} else {
System.out.println(ZAnsi.brightRed("\n[FAIL] Не удалось установить сборку."));
}
-
+
ConsoleUtils.pause();
}
- private void createVanillaInstance() throws Exception {
- ConsoleUtils.clearScreen();
- System.out.println(ZAnsi.cyan("Получение списка версий Minecraft..."));
-
- VersionInstaller versionInstaller = new VersionInstaller(null);
- List allVersions = versionInstaller.getAvailableVersions();
-
- List versionOptions = allVersions.stream()
- .map(v -> v.getId() + " (" + v.getType() + ")")
- .collect(Collectors.toList());
- versionOptions.add("Назад");
-
- ArrowMenu versionMenu = new ArrowMenu("Выбор версии Minecraft", versionOptions);
- int versionChoice = versionMenu.show();
-
- if (versionChoice == -1 || versionChoice == versionOptions.size() - 1) return;
-
- MinecraftVersion selectedMc = allVersions.get(versionChoice);
- String mcVersion = selectedMc.getId();
-
- String packName = askPackName();
- if (packName == null) return;
-
- if (InstanceManager.getInstance(packName) != null) {
- System.out.println(ZAnsi.brightRed("Сборка с таким именем уже существует!"));
- ConsoleUtils.pause();
- return;
- }
-
- InstanceManager.createInstanceFolder(packName);
- Instance newInstance = InstanceManager.getInstance(packName);
-
- MinecraftLib lib = new MinecraftLib(newInstance);
- boolean success = lib.installMinecraft(mcVersion);
-
- if (success) {
- System.out.println(ZAnsi.brightGreen("\n[OK] Vanilla сборка '" + packName + "' успешно создана!"));
- } else {
- System.out.println(ZAnsi.brightRed("\n[FAIL] Не удалось создать сборку."));
- }
-
- ConsoleUtils.pause();
- }
-
- private void createCustomInstance() throws Exception {
- ConsoleUtils.clearScreen();
- System.out.println(ZAnsi.cyan("Получение списка версий Minecraft..."));
-
- VersionInstaller versionInstaller = new VersionInstaller(null);
- List allVersions = versionInstaller.getAvailableVersions();
-
- List versionOptions = allVersions.stream()
- .map(v -> v.getId() + " (" + v.getType() + ")")
- .collect(Collectors.toList());
- versionOptions.add("Назад");
-
- ArrowMenu versionMenu = new ArrowMenu("Выбор версии Minecraft", versionOptions);
- int versionChoice = versionMenu.show();
-
- if (versionChoice == -1 || versionChoice == versionOptions.size() - 1) return;
-
- MinecraftVersion selectedMc = allVersions.get(versionChoice);
- String mcVersion = selectedMc.getId();
-
- // === Выбор лоадера с правильной проверкой поддержки ===
- List loaderOptions = buildLoaderOptions(mcVersion);
- ArrowMenu loaderMenu = new ArrowMenu("Выбор модлоадера для " + mcVersion, loaderOptions);
- int loaderChoice = loaderMenu.show();
-
- if (loaderChoice == -1 || loaderChoice == loaderOptions.size() - 1) return;
-
- String selectedLoader = loaderOptions.get(loaderChoice);
-
- if (selectedLoader.contains("Vanilla")) {
- createVanillaInstance();
- return;
- }
-
- String loaderType = selectedLoader.contains("Fabric") ? "fabric" : "forge";
-
- String loaderVersion;
- if (loaderType.equals("fabric")) {
- loaderVersion = askFabricLoaderVersion();
- } else {
- loaderVersion = askForgeVersion(mcVersion);
- }
-
- if (loaderVersion == null) return;
-
- String packName = askPackName();
- if (packName == null) return;
-
- if (InstanceManager.getInstance(packName) != null) {
- System.out.println(ZAnsi.brightRed("Сборка с таким именем уже существует!"));
- ConsoleUtils.pause();
- return;
- }
-
- InstanceManager.createInstanceFolder(packName);
- Instance newInstance = InstanceManager.getInstance(packName);
-
- MinecraftLib lib = new MinecraftLib(newInstance);
-
- boolean success = loaderType.equals("fabric")
- ? lib.installFabric(mcVersion, loaderVersion)
- : lib.installForge(mcVersion, loaderVersion);
-
- if (success) {
- System.out.println(ZAnsi.brightGreen("\n[OK] Сборка '" + packName + "' успешно установлена!"));
- } else {
- System.out.println(ZAnsi.brightRed("\n[FAIL] Не удалось установить сборку."));
- }
-
- ConsoleUtils.pause();
- }
-
- // ====================== Вспомогательные методы ======================
-
- private List buildLoaderOptions(String mcVersion) {
- List options = new ArrayList<>();
-
- if (isFabricSupported(mcVersion)) {
- options.add("Fabric");
- }
- if (isForgeSupported(mcVersion)) {
- options.add("Forge");
- }
- options.add("Vanilla");
- options.add("Назад");
-
- return options;
- }
-
- private boolean isFabricSupported(String version) {
- return version.matches("^1\\.(1[4-9]|[2-9]\\d).*");
- }
-
- private boolean isForgeSupported(String version) {
- if (version.matches("^1\\.2[2-9].*") || version.matches("^\\d{2}.*")) {
- return false;
- }
- return version.matches("^1\\.(1[2-9]|[2-9]\\d).*") ||
- version.matches("^1\\.20.*") || version.matches("^1\\.21.*");
- }
-
+ // ====================== manageInstance — полностью восстановлен ======================
private void manageInstance(Instance instance) throws Exception {
while (true) {
ConsoleUtils.clearScreen();
System.out.println(ZAnsi.header("Управление сборкой: " + instance.getName()));
System.out.println(ZAnsi.white("Версия: " + instance.getMinecraftVersion()));
- System.out.println(ZAnsi.white("Лоадер: " + instance.getLoaderType() +
+ System.out.println(ZAnsi.white("Лоадер: " + instance.getLoaderType() +
(instance.getLoaderVersion() != null ? " " + instance.getLoaderVersion() : "")));
-
+
if (instance.isServerPack()) {
System.out.println(ZAnsi.green("Серверная сборка: v" + instance.getServerVersion()));
}
-
+
List options = new ArrayList<>();
options.add("Запустить сборку");
if (instance.isServerPack()) {
@@ -341,12 +300,12 @@ public class LaunchMenu {
options.add("Изменить версию лоадера");
options.add("Удалить сборку");
options.add("Назад");
-
+
ArrowMenu menu = new ArrowMenu("Действия", options);
int choice = menu.show();
-
+
if (choice == -1 || choice == options.size() - 1) return;
-
+
switch (choice) {
case 0 -> launchExistingInstance(instance);
case 1 -> {
@@ -367,20 +326,20 @@ public class LaunchMenu {
}
}
}
-
+
private void checkAndUpdateServerPack(Instance instance) throws Exception {
ConsoleUtils.clearScreen();
System.out.println(ZAnsi.cyan("Проверка обновлений для " + instance.getName()));
-
+
PackDownloader downloader = new PackDownloader(instance);
boolean hasUpdate = downloader.checkForUpdates(instance.getServerPackName());
-
+
if (!hasUpdate) {
System.out.println(ZAnsi.green("Сборка актуальна (v" + instance.getServerVersion() + ")"));
ConsoleUtils.pause();
return;
}
-
+
System.out.println(ZAnsi.brightYellow("Доступно обновление!"));
if (Input.confirm("Обновить сборку")) {
boolean success = downloader.updatePack(instance.getServerPackName());
@@ -392,44 +351,43 @@ public class LaunchMenu {
} else {
System.out.println(ZAnsi.yellow("Обновление отменено."));
}
-
ConsoleUtils.pause();
}
-
+
private void changeLoaderVersion(Instance instance) throws Exception {
ConsoleUtils.clearScreen();
System.out.println(ZAnsi.cyan("Изменение версии лоадера для " + instance.getName()));
-
+
String currentLoader = instance.getLoaderType();
String mcVersion = instance.getMinecraftVersion();
-
+
if ("vanilla".equalsIgnoreCase(currentLoader)) {
System.out.println(ZAnsi.yellow("Это vanilla сборка. Нельзя изменить лоадер."));
ConsoleUtils.pause();
return;
}
-
+
String newLoaderVersion;
if ("fabric".equalsIgnoreCase(currentLoader)) {
newLoaderVersion = askFabricLoaderVersion();
} else {
newLoaderVersion = askForgeVersion(mcVersion);
}
-
+
if (newLoaderVersion == null) return;
-
+
System.out.println(ZAnsi.cyan("Переустановка лоадера " + currentLoader + " -> " + newLoaderVersion + "..."));
-
+
MinecraftLib lib = new MinecraftLib(instance);
boolean success;
-
+
try {
if ("fabric".equalsIgnoreCase(currentLoader)) {
success = lib.installFabric(mcVersion, newLoaderVersion);
} else {
success = lib.installForge(mcVersion, newLoaderVersion);
}
-
+
if (success) {
System.out.println(ZAnsi.brightGreen("Версия лоадера успешно изменена!"));
} else {
@@ -438,25 +396,25 @@ public class LaunchMenu {
} catch (Exception e) {
System.out.println(ZAnsi.brightRed("Ошибка при смене лоадера: " + e.getMessage()));
}
-
+
ConsoleUtils.pause();
}
-
+
private void deleteInstance(Instance instance) throws IOException {
ConsoleUtils.clearScreen();
-
+
List confirmOptions = List.of(
- "Да, удалить сборку",
- "Нет, отменить"
+ "Да, удалить сборку",
+ "Нет, отменить"
);
-
+
ArrowMenu confirmMenu = new ArrowMenu(
- "Вы действительно хотите удалить сборку '" + instance.getName() + "'?",
- confirmOptions
+ "Вы действительно хотите удалить сборку '" + instance.getName() + "'?",
+ confirmOptions
);
-
+
int choice = confirmMenu.show();
-
+
if (choice == 0) {
boolean deleted = InstanceManager.deleteInstance(instance.getName());
if (deleted) {
@@ -467,67 +425,10 @@ public class LaunchMenu {
} else {
System.out.println(ZAnsi.yellow("Удаление отменено."));
}
-
+
ConsoleUtils.pause();
}
-
- private String askFabricLoaderVersion() throws Exception {
- System.out.println(ZAnsi.cyan("Получение списка версий Fabric Loader..."));
- List versions = ZHttpClient.getFabricLoaderVersions();
-
- List options = versions.stream()
- .limit(30)
- .map(v -> "Fabric Loader " + v)
- .collect(Collectors.toList());
- options.add("Назад");
-
- ArrowMenu menu = new ArrowMenu("Выбор версии Fabric Loader", options);
- int choice = menu.show();
-
- if (choice == -1 || choice == options.size() - 1) return null;
- return versions.get(choice);
- }
-
- private String askForgeVersion(String mcVersion) throws Exception {
- System.out.println(ZAnsi.cyan("Получение списка версий Forge для " + mcVersion + "..."));
-
- List allForgeVersions = getAllForgeVersions();
-
- List compatibleVersions = allForgeVersions.stream()
- .filter(v -> v.startsWith(mcVersion + "-"))
- .map(v -> v.substring(mcVersion.length() + 1))
- .collect(Collectors.toList());
-
- if (compatibleVersions.isEmpty()) {
- System.out.println(ZAnsi.yellow("Не найдено совместимых версий Forge для " + mcVersion));
- ConsoleUtils.pause();
- return null;
- }
-
- List options = compatibleVersions.stream()
- .limit(30)
- .map(v -> "Forge " + v)
- .collect(Collectors.toList());
- options.add("Назад");
-
- ArrowMenu menu = new ArrowMenu("Выбор версии Forge для " + mcVersion, options);
- int choice = menu.show();
-
- if (choice == -1 || choice == options.size() - 1) return null;
-
- return compatibleVersions.get(choice);
- }
-
- private String askPackName() {
- System.out.print(ZAnsi.white("\nВведите название новой сборки: "));
- String name = Input.readLine();
- if (name.isEmpty()) {
- System.out.println(ZAnsi.yellow("Отменено."));
- return null;
- }
- return name;
- }
-
+
private void launchExistingInstance(Instance instance) {
if (instance.isServerPack() && !AuthManager.hasActivePass()) {
ConsoleUtils.clearScreen();
@@ -535,47 +436,236 @@ public class LaunchMenu {
ConsoleUtils.pause();
return;
}
+
ConsoleUtils.clearScreen();
System.out.println(ZAnsi.brightGreen("Запуск сборки: " + instance.getName()));
-
+
MinecraftLib lib = new MinecraftLib(instance);
- LaunchOptions options = new LaunchOptions();
-
- // Авторизация Minecraft
+ LaunchOptions options = new LaunchOptions();
+
options.setUsername(AuthManager.getUsername());
options.setUuid(AuthManager.getUuid());
options.setAccessToken(AuthManager.getAccessToken());
-
+
try {
lib.launch(options);
} catch (Exception e) {
System.out.println(ZAnsi.brightRed("Ошибка при запуске: " + e.getMessage()));
e.printStackTrace();
}
-
+
ConsoleUtils.pause();
}
-
+
+ // ====================== Остальные вспомогательные методы ======================
+
+ private String askPackName() {
+ System.out.print(ZAnsi.white("\nВведите название новой сборки: "));
+ String name = Input.readLine().trim();
+ if (name.isEmpty()) {
+ System.out.println(ZAnsi.yellow("Отменено."));
+ return null;
+ }
+ return name;
+ }
+
+ private void createVanillaInstance() throws Exception {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.cyan("Получение списка версий Minecraft..."));
+
+ VersionInstaller versionInstaller = new VersionInstaller(null);
+ List allVersions = versionInstaller.getAvailableVersions();
+
+ List versionOptions = allVersions.stream()
+ .map(v -> v.getId() + " (" + v.getType() + ")")
+ .collect(Collectors.toList());
+ versionOptions.add("Назад");
+
+ ArrowMenu versionMenu = new ArrowMenu("Выбор версии Minecraft", versionOptions);
+ int versionChoice = versionMenu.show();
+
+ if (versionChoice == -1 || versionChoice == versionOptions.size() - 1) return;
+
+ MinecraftVersion selectedMc = allVersions.get(versionChoice);
+ String mcVersion = selectedMc.getId();
+
+ String packName = askPackName();
+ if (packName == null) return;
+
+ if (InstanceManager.getInstance(packName) != null) {
+ System.out.println(ZAnsi.brightRed("Сборка с таким именем уже существует!"));
+ ConsoleUtils.pause();
+ return;
+ }
+
+ InstanceManager.createInstanceFolder(packName);
+ Instance newInstance = InstanceManager.getInstance(packName);
+
+ MinecraftLib lib = new MinecraftLib(newInstance);
+ boolean success = lib.installMinecraft(mcVersion);
+
+ if (success) {
+ System.out.println(ZAnsi.brightGreen("\n[OK] Vanilla сборка '" + packName + "' успешно создана!"));
+ } else {
+ System.out.println(ZAnsi.brightRed("\n[FAIL] Не удалось создать сборку."));
+ }
+
+ ConsoleUtils.pause();
+ }
+
+ private void createCustomInstance() throws Exception {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.cyan("Получение списка версий Minecraft..."));
+
+ VersionInstaller versionInstaller = new VersionInstaller(null);
+ List allVersions = versionInstaller.getAvailableVersions();
+
+ List versionOptions = allVersions.stream()
+ .map(v -> v.getId() + " (" + v.getType() + ")")
+ .collect(Collectors.toList());
+ versionOptions.add("Назад");
+
+ ArrowMenu versionMenu = new ArrowMenu("Выбор версии Minecraft", versionOptions);
+ int versionChoice = versionMenu.show();
+
+ if (versionChoice == -1 || versionChoice == versionOptions.size() - 1) return;
+
+ MinecraftVersion selectedMc = allVersions.get(versionChoice);
+ String mcVersion = selectedMc.getId();
+
+ List loaderOptions = buildLoaderOptions(mcVersion);
+ ArrowMenu loaderMenu = new ArrowMenu("Выбор модлоадера для " + mcVersion, loaderOptions);
+ int loaderChoice = loaderMenu.show();
+
+ if (loaderChoice == -1 || loaderChoice == loaderOptions.size() - 1) return;
+
+ String selectedLoader = loaderOptions.get(loaderChoice);
+
+ if (selectedLoader.contains("Vanilla")) {
+ createVanillaInstance();
+ return;
+ }
+
+ String loaderType = selectedLoader.contains("Fabric") ? "fabric" : "forge";
+
+ String loaderVersion = loaderType.equals("fabric")
+ ? askFabricLoaderVersion()
+ : askForgeVersion(mcVersion);
+
+ if (loaderVersion == null) return;
+
+ String packName = askPackName();
+ if (packName == null) return;
+
+ if (InstanceManager.getInstance(packName) != null) {
+ System.out.println(ZAnsi.brightRed("Сборка с таким именем уже существует!"));
+ ConsoleUtils.pause();
+ return;
+ }
+
+ InstanceManager.createInstanceFolder(packName);
+ Instance newInstance = InstanceManager.getInstance(packName);
+
+ MinecraftLib lib = new MinecraftLib(newInstance);
+
+ boolean success = loaderType.equals("fabric")
+ ? lib.installFabric(mcVersion, loaderVersion)
+ : lib.installForge(mcVersion, loaderVersion);
+
+ if (success) {
+ System.out.println(ZAnsi.brightGreen("\n[OK] Сборка '" + packName + "' успешно установлена!"));
+ } else {
+ System.out.println(ZAnsi.brightRed("\n[FAIL] Не удалось установить сборку."));
+ }
+
+ ConsoleUtils.pause();
+ }
+
+ private List buildLoaderOptions(String mcVersion) {
+ List options = new ArrayList<>();
+
+ if (isFabricSupported(mcVersion)) options.add("Fabric");
+ if (isForgeSupported(mcVersion)) options.add("Forge");
+ options.add("Vanilla");
+ options.add("Назад");
+
+ return options;
+ }
+
+ private boolean isFabricSupported(String version) {
+ return version.matches("^1\\.(1[4-9]|[2-9]\\d).*");
+ }
+
+ private boolean isForgeSupported(String version) {
+ if (version.matches("^1\\.2[2-9].*") || version.matches("^\\d{2}.*")) return false;
+ return version.matches("^1\\.(1[2-9]|[2-9]\\d).*") ||
+ version.matches("^1\\.20.*") || version.matches("^1\\.21.*");
+ }
+
+ private String askFabricLoaderVersion() throws Exception {
+ System.out.println(ZAnsi.cyan("Получение списка версий Fabric Loader..."));
+ List versions = ZHttpClient.getFabricLoaderVersions();
+
+ List options = versions.stream()
+ .limit(30)
+ .map(v -> "Fabric Loader " + v)
+ .collect(Collectors.toList());
+ options.add("Назад");
+
+ ArrowMenu menu = new ArrowMenu("Выбор версии Fabric Loader", options);
+ int choice = menu.show();
+
+ if (choice == -1 || choice == options.size() - 1) return null;
+ return versions.get(choice);
+ }
+
+ private String askForgeVersion(String mcVersion) throws Exception {
+ System.out.println(ZAnsi.cyan("Получение списка версий Forge для " + mcVersion + "..."));
+
+ List allForgeVersions = getAllForgeVersions();
+
+ List compatibleVersions = allForgeVersions.stream()
+ .filter(v -> v.startsWith(mcVersion + "-"))
+ .map(v -> v.substring(mcVersion.length() + 1))
+ .collect(Collectors.toList());
+
+ if (compatibleVersions.isEmpty()) {
+ System.out.println(ZAnsi.yellow("Не найдено совместимых версий Forge для " + mcVersion));
+ ConsoleUtils.pause();
+ return null;
+ }
+
+ List options = compatibleVersions.stream()
+ .limit(30)
+ .map(v -> "Forge " + v)
+ .collect(Collectors.toList());
+ options.add("Назад");
+
+ ArrowMenu menu = new ArrowMenu("Выбор версии Forge для " + mcVersion, options);
+ int choice = menu.show();
+
+ if (choice == -1 || choice == options.size() - 1) return null;
+
+ return compatibleVersions.get(choice);
+ }
+
private List getAllForgeVersions() throws Exception {
- String metadataUrl = "https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml";
-
- String xml = ZHttpClient.downloadString(metadataUrl);
-
+ String xml = ZHttpClient.downloadString("https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml");
+
List versions = new ArrayList<>();
int index = 0;
-
+
while ((index = xml.indexOf("", index)) != -1) {
int start = index + 9;
int end = xml.indexOf("", start);
if (end == -1) break;
-
+
String version = xml.substring(start, end).trim();
versions.add(version);
index = end;
}
-
+
versions.sort((a, b) -> b.compareTo(a));
-
return versions;
}
}
\ No newline at end of file
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LoginMenu.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LoginMenu.java
index 20482a0..ebdff19 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LoginMenu.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/LoginMenu.java
@@ -148,14 +148,46 @@ public class LoginMenu {
* Читаем пароль — стараемся скрыть вывод через Console,
* если недоступно (IDE/терминал без TTY) — читаем обычным способом.
*/
- private String readPassword(String prompt) {
- java.io.Console console = System.console();
- if (console != null) {
- char[] chars = console.readPassword(prompt);
- return chars != null ? new String(chars) : "";
+ private String readPassword(String prompt) throws IOException {
+ // Создаём временный терминал для ввода пароля
+ org.jline.terminal.Terminal passTerminal = org.jline.terminal.TerminalBuilder.builder()
+ .system(true)
+ .jna(true)
+ .build();
+
+ passTerminal.enterRawMode();
+ passTerminal.writer().print(prompt);
+ passTerminal.writer().flush();
+
+ StringBuilder password = new StringBuilder();
+
+ try {
+ while (true) {
+ int key = passTerminal.reader().read();
+
+ if (key == 13 || key == 10) { // Enter
+ passTerminal.writer().println();
+ break;
+ } else if (key == 127 || key == 8) { // Backspace
+ if (password.length() > 0) {
+ password.setLength(password.length() - 1);
+ passTerminal.writer().print("\b \b");
+ passTerminal.writer().flush();
+ }
+ } else if (key == 3) { // Ctrl+C
+ passTerminal.writer().println();
+ System.exit(0);
+ } else if (key >= 32 && key < 127) { // Печатные символы
+ password.append((char) key);
+ passTerminal.writer().print('*');
+ passTerminal.writer().flush();
+ }
+ }
+ } finally {
+ passTerminal.close();
}
- // Fallback: в IDE пароль будет виден
- return Input.readLine(prompt);
+
+ return password.toString();
}
private void printBanner() {
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/ServerCheckMenu.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/ServerCheckMenu.java
index 68bd045..51e113b 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/ServerCheckMenu.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/menu/ServerCheckMenu.java
@@ -16,71 +16,83 @@ import java.util.List;
public class ServerCheckMenu {
public void show() throws IOException {
- List options = List.of(
- "Проверить подключение к ZernMC серверу",
- "Проверить доступ к Mojang (Minecraft)",
- "Проверить доступ к Fabric Meta",
- "Назад в главное меню"
- );
+ while (true) {
+ ConsoleUtils.clearScreen();
+ System.out.println(ZAnsi.header("Диагностика подключения"));
- ArrowMenu menu = new ArrowMenu("Диагностика подключения", options);
- int choice = menu.show();
+ List options = List.of(
+ "Проверить подключение к ZernMC серверу",
+ "Проверить доступ к Mojang (Minecraft)",
+ "Проверить доступ к Fabric Meta",
+ "Проверить доступ к Forge Maven",
+ "Назад в главное меню"
+ );
- if (choice == -1 || choice == 4) return;
+ ArrowMenu menu = new ArrowMenu("Выберите проверку", options);
+ int choice = menu.show();
- ConsoleUtils.clearScreen();
+ if (choice == -1 || choice == 4) {
+ return;
+ }
- switch (choice) {
- case 0 -> checkZernServer();
- case 1 -> checkMojang();
- case 2 -> checkFabric();
+ ConsoleUtils.clearScreen();
+
+ switch (choice) {
+ case 0 -> checkZernServer();
+ case 1 -> checkMojang();
+ case 2 -> checkFabric();
+ case 3 -> checkForge();
+ }
+
+ ConsoleUtils.pause();
}
-
- ConsoleUtils.pause();
}
private void checkZernServer() {
System.out.println(ZAnsi.cyan("Проверка подключения к ZernMC серверу..."));
+
try {
String response = ZHttpClient.get("/health");
- System.out.println(ZAnsi.brightGreen("Сервер успешно подключён!"));
- System.out.println("Ответ: " + response);
+ System.out.println(ZAnsi.brightGreen("[OK] ZernMC сервер успешно подключён!"));
+ System.out.println(ZAnsi.white("Ответ сервера: ") + response);
} catch (Exception e) {
- System.out.println(ZAnsi.brightRed("Не удалось подключиться к ZernMC серверу"));
- System.out.println("Ошибка: " + e.getMessage());
+ System.out.println(ZAnsi.brightRed("[FAIL] Не удалось подключиться к ZernMC серверу"));
+ System.out.println(ZAnsi.white("Ошибка: ") + e.getMessage());
}
}
private void checkMojang() {
System.out.println(ZAnsi.cyan("Проверка доступа к Mojang..."));
+
try {
HttpClient client = HttpClient.newBuilder()
- .connectTimeout(Duration.ofSeconds(8))
+ .connectTimeout(Duration.ofSeconds(10))
.build();
HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"))
+ .uri(URI.create("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"))
.GET()
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
- System.out.println(ZAnsi.brightGreen("Mojang доступен"));
+ System.out.println(ZAnsi.brightGreen("[OK] Mojang доступен"));
} else {
- System.out.println(ZAnsi.brightRed("Mojang вернул код " + response.statusCode()));
+ System.out.println(ZAnsi.brightRed("[FAIL] Mojang вернул код " + response.statusCode()));
}
} catch (Exception e) {
- System.out.println(ZAnsi.brightRed("Нет доступа к Mojang"));
- System.out.println("Ошибка: " + e.getMessage());
+ System.out.println(ZAnsi.brightRed("[FAIL] Нет доступа к Mojang"));
+ System.out.println(ZAnsi.white("Ошибка: ") + e.getMessage());
}
}
private void checkFabric() {
System.out.println(ZAnsi.cyan("Проверка доступа к Fabric Meta..."));
+
try {
HttpClient client = HttpClient.newBuilder()
- .connectTimeout(Duration.ofSeconds(8))
+ .connectTimeout(Duration.ofSeconds(10))
.build();
HttpRequest request = HttpRequest.newBuilder()
@@ -91,13 +103,39 @@ public class ServerCheckMenu {
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
- System.out.println(ZAnsi.brightGreen("Fabric Meta доступен"));
+ System.out.println(ZAnsi.brightGreen("[OK] Fabric Meta доступен"));
} else {
- System.out.println(ZAnsi.brightRed("Fabric Meta вернул код " + response.statusCode()));
+ System.out.println(ZAnsi.brightRed("[FAIL] Fabric Meta вернул код " + response.statusCode()));
}
} catch (Exception e) {
- System.out.println(ZAnsi.brightRed("Нет доступа к Fabric Meta"));
- System.out.println("Ошибка: " + e.getMessage());
+ System.out.println(ZAnsi.brightRed("[FAIL] Нет доступа к Fabric Meta"));
+ System.out.println(ZAnsi.white("Ошибка: ") + e.getMessage());
+ }
+ }
+
+ private void checkForge() {
+ System.out.println(ZAnsi.cyan("Проверка доступа к Forge Maven..."));
+
+ try {
+ HttpClient client = HttpClient.newBuilder()
+ .connectTimeout(Duration.ofSeconds(10))
+ .build();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml"))
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() == 200) {
+ System.out.println(ZAnsi.brightGreen("[OK] Forge Maven доступен"));
+ } else {
+ System.out.println(ZAnsi.brightRed("[FAIL] Forge Maven вернул код " + response.statusCode()));
+ }
+ } catch (Exception e) {
+ System.out.println(ZAnsi.brightRed("[FAIL] Нет доступа к Forge Maven"));
+ System.out.println(ZAnsi.white("Ошибка: ") + e.getMessage());
}
}
}
\ No newline at end of file
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Config.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Config.java
index 942fc16..c22793e 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Config.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Config.java
@@ -10,6 +10,8 @@ public class Config {
private static final Path CONFIG_DIR = Path.of(System.getProperty("user.home"), ".zernmc");
private static final Path CONFIG_FILE = CONFIG_DIR.resolve("launcher.properties");
+ private static final String BUILD_PROFILE = System.getProperty("build.profile", "global");
+
private static final Properties props = new Properties();
// Настройки
@@ -83,6 +85,14 @@ public class Config {
return maxMemory;
}
+ public static boolean isZernMCBuild() {
+ return "zernmc".equalsIgnoreCase(BUILD_PROFILE);
+ }
+
+ public static boolean isGlobalBuild() {
+ return !isZernMCBuild();
+ }
+
public static void setMaxMemory(int memory) {
// Защита от слишком маленьких/больших значений
if (memory < 1024) memory = 1536;
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Input.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Input.java
index 7ece5e6..988505e 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Input.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/Input.java
@@ -19,6 +19,7 @@ public class Input {
}
public static String readLine(String prompt) {
+ flushInput(); // Очищаем буфер
System.out.print(prompt);
return scanner.nextLine().trim();
}
@@ -79,4 +80,18 @@ public class Input {
public static void close() {
scanner.close();
}
+
+
+ /**
+ * Очищает буфер ввода от оставшихся символов
+ */
+ public static void flushInput() {
+ try {
+ while (System.in.available() > 0) {
+ System.in.read();
+ }
+ } catch (IOException e) {
+ // Игнорируем
+ }
+ }
}
\ No newline at end of file
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/ZHttpClient.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/ZHttpClient.java
index 3e0bff0..292e6e4 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/ZHttpClient.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/utils/ZHttpClient.java
@@ -3,6 +3,8 @@ package me.sashegdev.zernmc.launcher.utils;
import org.json.JSONArray;
import org.json.JSONObject;
+import me.sashegdev.zernmc.launcher.auth.AuthManager;
+
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
@@ -380,13 +382,19 @@ public class ZHttpClient {
}
try {
- HttpRequest request = HttpRequest.newBuilder()
+ HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + endpoint))
.timeout(Duration.ofSeconds(15))
.header("User-Agent", "ZernMC-Launcher/1.0")
- .GET()
- .build();
+ .GET();
+ // ===== ДОБАВИТЬ ТОКЕН АВТОРИЗАЦИИ =====
+ String accessToken = AuthManager.getAccessToken();
+ if (accessToken != null && !accessToken.equals("0")) {
+ requestBuilder.header("Authorization", "Bearer " + accessToken);
+ }
+
+ HttpRequest request = requestBuilder.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
@@ -401,19 +409,25 @@ public class ZHttpClient {
private static String proxyGet(String endpoint) throws IOException {
try {
- HttpRequest request = HttpRequest.newBuilder()
+ HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/proxy" + endpoint))
.timeout(Duration.ofSeconds(30))
.header("User-Agent", "ZernMC-Launcher/1.0")
- .GET()
- .build();
-
+ .GET();
+
+ // ===== ДОБАВИТЬ ТОКЕН АВТОРИЗАЦИИ =====
+ String accessToken = AuthManager.getAccessToken();
+ if (accessToken != null && !accessToken.equals("0")) {
+ requestBuilder.header("Authorization", "Bearer " + accessToken);
+ }
+
+ HttpRequest request = requestBuilder.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
-
+
if (response.statusCode() != 200) {
throw new IOException("HTTP " + response.statusCode());
}
-
+
proxySuccessCount++;
return response.body();
} catch (Exception e) {
diff --git a/server/main.py b/server/main.py
index 0e4b013..d6466a5 100644
--- a/server/main.py
+++ b/server/main.py
@@ -15,6 +15,8 @@ from middleware import LoggingMiddleware
from cli import parse_args, run_test_mode, run_production_mode, run_development_mode
from log_manager import init_logging
+from fastapi.responses import Response
+
import httpx
import base64
from fastapi.responses import StreamingResponse
@@ -80,6 +82,331 @@ async def lifespan(app: FastAPI):
logger.info("Server shutting down...")
+
+# ====================== ШАБЛОН СТРАНИЦЫ АКТИВАЦИИ ======================
+ACTIVATE_PASS_HTML = """
+
+
+
+
+
+ Активация проходки | ZernMC
+
+
+
+
+
+
ZernMC
+
Активация проходки
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+
+
# Create app with lifespan
app = FastAPI(title="ZernMC Launcher Server", lifespan=lifespan)
@@ -144,6 +471,17 @@ async def health():
return {"status": "healthy", "timestamp": datetime.utcnow().isoformat()}
+# ====================== WEB ИНТЕРФЕЙС ДЛЯ АКТИВАЦИИ ПРОХОДКИ ======================
+
+@app.get("/activate-pass")
+async def activate_pass_page():
+ """Веб-интерфейс для активации проходки"""
+ return Response(
+ content=ACTIVATE_PASS_HTML,
+ media_type="text/html"
+ )
+
+
# ====================== ЭНДПОИНТЫ ДЛЯ ПАКОВ ======================
@app.get("/packs")