diff --git a/package-lock.json b/package-lock.json index ad8cceb..18becad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "@mui/icons-material": "^7.2.0", "@mui/material": "^7.2.0", "@xmcl/core": "^2.14.1", - "@xmcl/installer": "^6.1.0", + "@xmcl/file-transfer": "^2.0.3", + "@xmcl/installer": "^6.1.2", "@xmcl/resourcepack": "^1.2.4", "@xmcl/user": "^4.2.0", "electron-debug": "^4.1.0", @@ -30,7 +31,7 @@ "skinview3d": "^3.4.1", "stream-browserify": "^3.0.0", "three": "^0.178.0", - "undici": "^7.11.0", + "undici": "^7.16.0", "util": "^0.12.5", "uuid": "^11.1.0" }, @@ -5967,9 +5968,9 @@ } }, "node_modules/@xmcl/core": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/@xmcl/core/-/core-2.14.1.tgz", - "integrity": "sha512-oaaanDX1AG9/eHS6gxg/oYOxKn7bQMcOHFBF7i/gBk/AlhEB72lIkAxssoJZ2zggAz7p1gNNsNCt7ialrhWSkQ==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@xmcl/core/-/core-2.15.1.tgz", + "integrity": "sha512-ldVWtFGRTnQ836oRnex3YiwCogQmy2XdKfdYz9uAoEbXofMrH/Yq/uEK593iQ9iVJa8Rlfik+LjzGAfsYzR1SQ==", "license": "MIT", "dependencies": { "@xmcl/unzip": "2.1.2" @@ -5979,9 +5980,9 @@ } }, "node_modules/@xmcl/file-transfer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@xmcl/file-transfer/-/file-transfer-2.0.2.tgz", - "integrity": "sha512-4HZ18relTy2HKB0YPVzWzrGs5Bb74yvMvi6qwl+IYoPqJdUV4xLySGxY7xfTEff5Ct/cy74ZbvqaDFYly0L8Rw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@xmcl/file-transfer/-/file-transfer-2.0.3.tgz", + "integrity": "sha512-IzS1EsmirFF7fHQyJ3Otpu8W7l1vD4qzAlJtFDpkCrMRhfG99smgTiprhlfPzK8XklPe3cq8qKoiEO3v11VI9w==", "license": "MIT", "dependencies": { "@types/http-cache-semantics": "^4.0.1", @@ -6014,14 +6015,14 @@ } }, "node_modules/@xmcl/installer": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@xmcl/installer/-/installer-6.1.0.tgz", - "integrity": "sha512-m52Zl5945+ggc/y8unr9i2A0TY7vHwKJEdjvIeSqIPJuWMl57HBOgsi0JUFN3HRlHQOFC4aj+Yw5gt/2PFhv4A==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@xmcl/installer/-/installer-6.1.2.tgz", + "integrity": "sha512-q0meO1I4oyL0jCd8mfRD8D92ODgTbg+sQvkfilWwG1115EBd1KNBzqFRKYXzkmEGwjrcCdhbA5Q4ECpJ87Ro0Q==", "license": "MIT", "dependencies": { "@xmcl/asm": "1.0.1", - "@xmcl/core": "2.14.1", - "@xmcl/file-transfer": "2.0.2", + "@xmcl/core": "2.15.1", + "@xmcl/file-transfer": "2.0.3", "@xmcl/forge-site-parser": "2.0.9", "@xmcl/task": "4.1.1", "@xmcl/unzip": "2.1.2", @@ -21355,9 +21356,9 @@ } }, "node_modules/undici": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.11.0.tgz", - "integrity": "sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", "license": "MIT", "engines": { "node": ">=20.18.1" diff --git a/package.json b/package.json index 42fd2e2..289b5d3 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,8 @@ "@mui/icons-material": "^7.2.0", "@mui/material": "^7.2.0", "@xmcl/core": "^2.14.1", - "@xmcl/installer": "^6.1.0", + "@xmcl/file-transfer": "^2.0.3", + "@xmcl/installer": "^6.1.2", "@xmcl/resourcepack": "^1.2.4", "@xmcl/user": "^4.2.0", "electron-debug": "^4.1.0", @@ -124,7 +125,7 @@ "skinview3d": "^3.4.1", "stream-browserify": "^3.0.0", "three": "^0.178.0", - "undici": "^7.11.0", + "undici": "^7.16.0", "util": "^0.12.5", "uuid": "^11.1.0" }, diff --git a/src/main/minecraft-launcher.ts b/src/main/minecraft-launcher.ts index d9e3ed7..ce8d517 100644 --- a/src/main/minecraft-launcher.ts +++ b/src/main/minecraft-launcher.ts @@ -484,7 +484,7 @@ export function initMinecraftHandlers() { packName = 'Comfort', // Название основной сборки versionToLaunchOverride = '', // Возможность переопределить версию для запуска serverIp = 'popa-popa.ru', - serverPort, // Добавляем опциональный порт без значения по умолчанию + serverPort, // опциональный порт } = gameConfig || {}; const appPath = path.dirname(app.getPath('exe')); @@ -516,7 +516,7 @@ export function initMinecraftHandlers() { console.log('Запускаем версию:', versionToLaunch); - // Находим путь к Java + // --- Поиск Java --- event.sender.send('installation-status', { step: 'java', message: 'Поиск Java...', @@ -524,7 +524,7 @@ export function initMinecraftHandlers() { console.log('Поиск Java...'); - let javaPath; + let javaPath: string; try { javaPath = await findJava(); } catch (error) { @@ -536,8 +536,9 @@ export function initMinecraftHandlers() { javaPath = 'java'; } - // Далее пробуем установить Minecraft, но продолжаем даже при ошибках - let resolvedVersion; + // --- Установка Minecraft / Fabric / зависимостей --- + let resolvedVersion: any; + try { // 1. Получаем список версий и устанавливаем ванильный Minecraft event.sender.send('installation-status', { @@ -563,53 +564,30 @@ export function initMinecraftHandlers() { console.log('Установка Minecraft...'); - try { - const installMcTask = installTask(minecraftVersion, minecraftDir, { - skipRevalidate: true, - }); + const installMcTask = installTask(minecraftVersion, minecraftDir, { + // немного уменьшаем агрессию загрузчика + skipRevalidate: true, + assetsDownloadConcurrency: 2, + librariesDownloadConcurrency: 2, + }); - console.log('installMcTask:', installMcTask); + console.log('installMcTask started for', minecraftVersion.id); - await installMcTask.startAndWait({ - onStart(task) { - event.sender.send('installation-status', { - step: `minecraft-install.${task.path}`, - message: `Начало: ${task.name || task.path}`, - }); - }, - onUpdate(task) { - const percentage = - Math.round( - (installMcTask.progress / installMcTask.total) * 100, - ) || 0; + await installMcTask.startAndWait({ + onFailed(task, error) { + const stepName = (task as any).path || task.name || 'unknown'; + console.warn( + `[minecraft-install] step "${stepName}" failed: ${ + (error as any).code ?? '' + } ${(error as any).message}`, + ); - event.sender.send('download-progress', percentage); - event.sender.send('installation-status', { - step: `minecraft-install.${task.path}`, - message: `Прогресс ${task.name || task.path}: ${percentage}% (${installMcTask.progress}/${installMcTask.total})`, - }); - }, - onFailed(task, error) { - console.log('onFailed:', task, error); - console.warn( - `Ошибка при установке ${task.path}, продолжаем:`, - error, - ); - event.sender.send('installation-status', { - step: `minecraft-install.${task.path}`, - message: `Ошибка: ${error.message}`, - }); - }, - onSucceed(task) { - event.sender.send('installation-status', { - step: `minecraft-install.${task.path}`, - message: `Завершено: ${task.name || task.path}`, - }); - }, - }); - } catch (error) { - console.log('Ошибка при установке Minecraft, продолжаем:', error); - } + event.sender.send('installation-status', { + step: `minecraft-install.${stepName}`, + message: `Ошибка: ${(error as any).message}`, + }); + }, + }); // 2. Устанавливаем Fabric console.log('Попытка установки Fabric:', { @@ -617,6 +595,7 @@ export function initMinecraftHandlers() { fabricVersion: fabricVersion, minecraftDir: minecraftDir, }); + try { event.sender.send('installation-status', { step: 'fabric-list', @@ -637,7 +616,7 @@ export function initMinecraftHandlers() { await installFabric({ minecraftVersion: baseVersion, - version: fabricVersion, // Используйте напрямую, без .version + version: fabricVersion, minecraft: minecraftDir, }); } @@ -647,7 +626,6 @@ export function initMinecraftHandlers() { // 3. Подготовка версии и установка зависимостей try { - // Используем идентификатор Fabric-версии const fabricVersionId = `${baseVersion}-fabric${fabricVersion}`; console.log('version-parse:', fabricVersionId); @@ -673,67 +651,64 @@ export function initMinecraftHandlers() { }); const depsTask = installDependenciesTask(resolvedVersion, { - assetsDownloadConcurrency: 4, + // максимально душим параллельность + assetsDownloadConcurrency: 2, + librariesDownloadConcurrency: 2, + // общие оптимизации skipRevalidate: true, prevalidSizeOnly: true, - checksumValidatorResolver: (checksum) => ({ + checksumValidatorResolver: () => ({ validate: async () => { - /* void */ + // отключаем проверку хэшей, чтобы не падать от мелких расхождений }, }), }); try { await depsTask.startAndWait({ - onStart(task) { - event.sender.send('installation-status', { - step: `dependencies.${task.path}`, - message: `Начало: ${task.name || task.path}`, - }); - }, - onUpdate(task) { - const percentage = - Math.round((depsTask.progress / depsTask.total) * 100) || 0; - - event.sender.send('download-progress', percentage); - event.sender.send('installation-status', { - step: `dependencies.${task.path}`, - message: `Установка ${task.name || task.path}: ${percentage}%`, - }); - }, onFailed(task, error) { - console.log('onFailed:', task, error); + const stepName = (task as any).path || task.name || 'unknown'; console.warn( - `Ошибка при установке ${task.path}, продолжаем:`, - error, + `[deps] step "${stepName}" failed: ${ + (error as any).code ?? '' + } ${(error as any).message}`, ); + event.sender.send('installation-status', { - step: `dependencies.${task.path}`, - message: `Ошибка: ${error.message}`, - }); - }, - onSucceed(task) { - event.sender.send('installation-status', { - step: `dependencies.${task.path}`, - message: `Завершено: ${task.name || task.path}`, + step: `dependencies.${stepName}`, + message: `Ошибка: ${(error as any).message}`, }); }, }); - } catch (error) { + } catch (error: any) { console.log( 'Ошибка при загрузке ресурсов, продолжаем запуск:', - error, + error.message || error, ); } - } catch (error) { - console.log('Ошибка при подготовке версии, продолжаем:', error); + } catch (error: any) { + console.log( + 'Ошибка при подготовке версии, продолжаем:', + error.message || error, + ); } + } else { + console.warn( + `Версия ${baseVersion} не найдена в списке версий Minecraft`, + ); } - } catch (error) { - console.log('Произошла ошибка при подготовке Minecraft:', error); + } catch (error: any) { + const agg = error as any; + const innerCount = Array.isArray(agg?.errors) ? agg.errors.length : 0; + + console.log( + 'Ошибка при установке Minecraft/Fabric/зависимостей, продолжаем:', + agg?.message || String(agg), + innerCount ? `(внутренних ошибок: ${innerCount})` : '', + ); } - // Загрузка и проверка authlib-injector + // --- authlib-injector --- const authlibPath = await ensureAuthlibInjectorExists(appPath); console.log('authlibPath:', authlibPath); @@ -742,7 +717,7 @@ export function initMinecraftHandlers() { message: 'authlib-injector готов', }); - // Запускаем Minecraft с authlib-injector для Ely.by + // --- Запуск игры --- console.log('Запуск игры...'); event.sender.send('installation-status', { @@ -750,15 +725,9 @@ export function initMinecraftHandlers() { message: 'Запуск игры...', }); - console.log('Запуск игры...'); - - // При запуске используем переданные параметры const packDir = path.join(versionsDir, packName); - // При формировании конфигурации запуска создаем объект server только с нужными параметрами const serverConfig: any = { ip: serverIp }; - - // Добавляем порт только если он был передан if (serverPort) { serverConfig.port = serverPort; } @@ -785,7 +754,6 @@ export function initMinecraftHandlers() { '--quickPlayMultiplayer', `${serverIp}:${serverPort || 25565}`, ], - // Используем данные аутентификации Yggdrasil accessToken, gameProfile: { id: uuid, @@ -793,7 +761,6 @@ export function initMinecraftHandlers() { }, }); - // Логирование proc.stdout?.on('data', (data) => { console.log(`Minecraft stdout: ${data}`); }); @@ -804,14 +771,14 @@ export function initMinecraftHandlers() { console.log('Запуск игры...'); return { success: true, pid: proc.pid }; - } catch (error) { + } catch (error: any) { console.error('Ошибка при запуске Minecraft:', error); event.sender.send('installation-status', { step: 'error', - message: `Ошибка запуска: ${error.message}`, + message: `Ошибка запуска: ${error.message || String(error)}`, }); - return { success: false, error: error.message }; + return { success: false, error: error.message || String(error) }; } });