diff --git a/neutralino.config.json b/neutralino.config.json index bfdba11..bf29705 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "com.gitlab.KRypt0n_.an-anime-game-launcher", - "version": "2.1.5", + "version": "2.2.0", "defaultMode": "window", "port": 0, "documentRoot": "/bundle/", diff --git a/package.json b/package.json index d17ff16..a1612d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "an-anime-game-launcher", - "version": "2.1.5", + "version": "2.2.0", "license": "GPL-3.0", "type": "module", "scripts": { @@ -18,17 +18,17 @@ "yaml": "^1.10.2" }, "devDependencies": { - "@neutralinojs/neu": "^9.1.2", + "@neutralinojs/neu": "^9.2.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.37", "@tsconfig/svelte": "^3.0.0", "@types/js-md5": "^0.4.3", "neutralino-appimage-bundler": "^1.3.2", - "sass": "^1.49.7", + "sass": "^1.49.8", "svelte": "^3.46.4", - "svelte-check": "^2.4.3", + "svelte-check": "^2.4.5", "svelte-preprocess": "^4.10.3", "tslib": "^2.3.1", "typescript": "^4.5.5", - "vite": "^2.8.2" + "vite": "^2.8.4" } } diff --git a/public/hdiffpatch/LICENSE b/public/hdiffpatch/LICENSE new file mode 100644 index 0000000..a289e34 --- /dev/null +++ b/public/hdiffpatch/LICENSE @@ -0,0 +1,48 @@ +MIT License + +HDiffPatch +Copyright (c) 2012-2021 housisong + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------------- + +libdivsufsort +Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/public/hdiffpatch/hpatchz b/public/hdiffpatch/hpatchz new file mode 100755 index 0000000..7f89cec Binary files /dev/null and b/public/hdiffpatch/hpatchz differ diff --git a/public/locales/de-de.yaml b/public/locales/de-de.yaml index 412212b..b770f6e 100644 --- a/public/locales/de-de.yaml +++ b/public/locales/de-de.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Spiel ist am herunterladen... unpacking: Spiel wird entpackt... + applying_changes: Änderungen werden angewandt... deleting_outdated: Lösche veraltete dateien... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: DXVK installieren install: Installieren update: Updaten + + apply_changes: + title: Änderungen anwenden + hint: hdiff-Änderungen an den Spieldateien anwenden + + remove_outdated: + title: Alte Dateien löschen + hint: Veraltete Dateien löschen # When the game should be patched patching: @@ -292,6 +301,11 @@ notifications: title: An Anime Game Launcher body: Alle Patch-Repositories sind nicht verfügbar. Sie können das Spiel starten aber der Launcher kann sich nicht sicher sein dass es gepatcht ist. + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: Ein Fehler geschah, während das Spiel aktualisiert wurde + body: '{files} Dateien konnten nicht aktualisiert werden' + # ToS violation warning window tos_violation: title: ToS-Verletzungswarnung diff --git a/public/locales/en-us.yaml b/public/locales/en-us.yaml index 97e05bc..fe485f6 100644 --- a/public/locales/en-us.yaml +++ b/public/locales/en-us.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Downloading game... unpacking: Unpacking game... + applying_changes: Applying changes... deleting_outdated: Deleting outdated files... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: Install DXVK install: Install update: Update + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # When the game should be patched patching: @@ -291,6 +300,11 @@ notifications: title: An Anime Game Launcher body: None of the patch repositories are available. You'll be able to run the game, but launcher can't be sure is it patched properly + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: ToS violation warning diff --git a/public/locales/es-es.yaml b/public/locales/es-es.yaml index 92eb860..4e79f57 100644 --- a/public/locales/es-es.yaml +++ b/public/locales/es-es.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Descargando el juego... unpacking: Descomprimiendo el juego... + applying_changes: Applying changes... deleting_outdated: Borrando archivos viejos... # Instalación de paquetes de voz @@ -39,6 +40,14 @@ launcher: install_dxvk: Instalar DXVK install: Instalar update: Actualizar + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # Cuando el juego debe ser parcheado patching: @@ -290,6 +299,11 @@ notifications: title: An Anime Game Launcher body: Ninguno de los repositorios del parche está disponible. Podrás ejecutar el juego, pero no podemos asegurar que el parche esté aplicado correctamente + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: Advertencia de violación de ToS diff --git a/public/locales/fr-fr.yaml b/public/locales/fr-fr.yaml index 27845c4..cefca77 100644 --- a/public/locales/fr-fr.yaml +++ b/public/locales/fr-fr.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Téléchargement du jeu... unpacking: Décompression du jeu... + applying_changes: Applying changes... deleting_outdated: Suppression des fichiers non à jour... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: Installer DXVK install: Installer update: Mise à jour + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # When the game should be patched patching: @@ -299,6 +308,11 @@ notifications: title: An Anime Game Launcher body: Pas tous les dépôts des patchs sont disponibles. Vous pouvez lancer le jeu, mais le Launcher ne peut pas garantir que celui-ci est correctement patcher + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: Violation du contrat d'utilisation diff --git a/public/locales/hu-hu.yaml b/public/locales/hu-hu.yaml index 350b54d..724e757 100644 --- a/public/locales/hu-hu.yaml +++ b/public/locales/hu-hu.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Játék letöltése folyamatban... unpacking: Játék kibontása folyamatban... + applying_changes: Applying changes... deleting_outdated: Lejárt fájlok kitörlése... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: DXVK telepítése install: Telepítés update: Frissítés + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # When the game should be patched patching: @@ -291,6 +300,11 @@ notifications: title: An Anime Game Launcher body: A patch adattárjai nem elérhetőek. Eltudod indítani a játékot, de a launcher nem tudja meghatározni hogy patch-elve van-e + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: Felhasználói feltételek megsértése diff --git a/public/locales/id-id.yaml b/public/locales/id-id.yaml index 0c3a4e5..b302ec3 100644 --- a/public/locales/id-id.yaml +++ b/public/locales/id-id.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Mengunduh game... unpacking: Membongkar game... + applying_changes: Applying changes... deleting_outdated: Menghapus file lama... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: Pasang DXVK install: Pasang update: Perbarui + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # When the game should be patched patching: @@ -291,6 +300,11 @@ notifications: title: An Anime Game Launcher body: Semua repositori patch tidak terseidia. Kamu dapat menjalankan game ini, tetapi peluncur tidak tahu secara pasti pakah patch sudah terpasang dengan benar + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: Peringatan pelanggaran Ketentuan Layanan (ToS) diff --git a/public/locales/it-it.yaml b/public/locales/it-it.yaml index 0e23430..014e024 100644 --- a/public/locales/it-it.yaml +++ b/public/locales/it-it.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Scaricando il gioco... unpacking: Decomprimendo il gioco... + applying_changes: Applying changes... deleting_outdated: Cancellando file vecchi... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: Installa DXVK install: Installa update: Aggiorna + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # When the game should be patched patching: @@ -290,6 +299,11 @@ notifications: body: Tutte le repository della patch non sono disponibili. Puoi avviare il gioco, ma il launcher non si può assicurare che la patch è stata applicata correttamente + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: Avviso di violazione ToS diff --git a/public/locales/nb-no.yaml b/public/locales/nb-no.yaml index f602536..0a745d8 100644 --- a/public/locales/nb-no.yaml +++ b/public/locales/nb-no.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Laster ned spill... unpacking: Pakker ut spill... + applying_changes: Applying changes... deleting_outdated: Fjerner utdaterte filer... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: Installer DXVK install: Installer update: Oppdater + + apply_changes: + title: Apply changes + hint: Apply hdiff changes to the game files + + remove_outdated: + title: Remove outdated + hint: Remove outdated game files # When the game should be patched patching: @@ -291,6 +300,11 @@ notifications: title: An Anime Game Launcher body: Ingen av patch oppbevaringstedene er tilgjengelig. Det er mulig å kjøre spillet, men det er ikke mulig å forsikre seg at spillet er patchet riktig + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: An error occurred during game updating + body: '{files} files couldn''t be updated by the hdiff patch' + # ToS violation warning window tos_violation: title: ToS brudd advarsel diff --git a/public/locales/ru-ru.yaml b/public/locales/ru-ru.yaml index d127ae0..cd2f314 100644 --- a/public/locales/ru-ru.yaml +++ b/public/locales/ru-ru.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: Скачивание игры... unpacking: Распаковка игры... + applying_changes: Применение изменений... deleting_outdated: Удаление устаревших файлов... # Установка звуковых пакетов @@ -40,6 +41,14 @@ launcher: install: Установить update: Обновить + apply_changes: + title: Применить изменения + hint: Применить hdiff изменения к файлам игры + + remove_outdated: + title: Удалить устаревшее + hint: Удалить устаревшие файлы игры + # Когда игра должна быть пропатчена patching: # Патч недоступен @@ -290,6 +299,11 @@ notifications: title: An Anime Game Launcher body: Все репозитории патча недоступны. Вы сможете запустить игру, однако лаунчер не может знать пропатчена ли она корректно + # HDiffPatch не смог успешно применить hdiff патчи к файлам игры + game_changes_applying_error: + title: Возникла ошибка во время обновления игры + body: '{files} файлов не смогли быть обновлены с помощью hdiff патча' + # Окно предупреждения о нарушении условий использования tos_violation: title: Предупреждение о нарушении правил использования diff --git a/public/locales/uwu.yaml b/public/locales/uwu.yaml index 40a27da..0e14123 100644 --- a/public/locales/uwu.yaml +++ b/public/locales/uwu.yaml @@ -23,6 +23,7 @@ launcher: game: downloading: downwoading game... -.- unpacking: unpacking g-game (o^▽^o) + applying_changes: appwying changes... deleting_outdated: deweting outdated fiwes... # Voice packages installation @@ -39,6 +40,14 @@ launcher: install_dxvk: install DXVK (◕ ω ◕✿) install: install update: u-update (/≧ ω\) + + apply_changes: + title: appwy changes + hint: appwy hdiff changes to the game files + + remove_outdated: + title: wemove outdated + hint: wemove outdated game files # When the game should be patched patching: @@ -290,6 +299,11 @@ notifications: title: an anime game waunchew body: a-all the patch wepositowies are not avaiwable. you'll b-be able to wun the game, but waunchew can't be sure is it patched pwopewwy + # HDiffPatch couldn't successfully apply game files changes + game_changes_applying_error: + title: an ewwow o-occuwwed duwing game updating + body: '{files} files couwdn''t b-be updated b-by the hdiff patch' + # ToS violation warning window tos_violation: title: ToS violation warning diff --git a/scripts/bundle-appimage.cjs b/scripts/bundle-appimage.cjs index e4d84d4..162869d 100644 --- a/scripts/bundle-appimage.cjs +++ b/scripts/bundle-appimage.cjs @@ -39,7 +39,7 @@ const bundler = new Bundler({ output: path.join(__dirname, '../dist/An Anime Game Launcher.AppImage'), // Application version - version: '2.1.5' + version: '2.2.0' }); // Bundle project diff --git a/src/ts/core/HDiffPatch.ts b/src/ts/core/HDiffPatch.ts new file mode 100644 index 0000000..eeb74c3 --- /dev/null +++ b/src/ts/core/HDiffPatch.ts @@ -0,0 +1,23 @@ +import { Debug } from '../../empathize'; +import { path } from '../../empathize'; + +declare const Neutralino; + +export default class HDiffPatch +{ + public static patch(file: string, patch: string, output: string): Promise + { + return new Promise(async (resolve) => { + let result = await Neutralino.os.execCommand(`./public/hdiffpatch/hpatchz -f "${path.addSlashes(file)}" "${path.addSlashes(patch)}" "${path.addSlashes(output)}"`); + + result = (result.stdOut ?? result.stdErr).includes('patch ok!'); + + Debug.log({ + function: 'HDiffPatch.patch', + message: { file, patch, output, result } + }); + + resolve(result); + }); + } +}; diff --git a/src/ts/launcher/State.ts b/src/ts/launcher/State.ts index 1ebb732..05c365b 100644 --- a/src/ts/launcher/State.ts +++ b/src/ts/launcher/State.ts @@ -38,6 +38,8 @@ export default class State 'game-installation-available': import('./states/Install'), 'game-update-available': import('./states/Install'), 'game-voice-update-required': import('./states/InstallVoice'), + 'game-files-changes-applying-required': import('./states/ApplyChanges'), + 'game-outdated-files-deletion-required': import('./states/RemoveOutdated'), 'test-patch-available': import('./states/ApplyPatch'), 'patch-available': import('./states/ApplyPatch'), @@ -254,6 +256,20 @@ export default class State break; + case 'game-files-changes-applying-required': + this.launchButton.textContent = dictionary['installation']['apply_changes']['title']; + + this.launchButton.setAttribute('aria-label', dictionary['installation']['apply_changes']['hint']); + + break; + + case 'game-outdated-files-deletion-required': + this.launchButton.textContent = dictionary['installation']['remove_outdated']['title']; + + this.launchButton.setAttribute('aria-label', dictionary['installation']['remove_outdated']['hint']); + + break; + case 'patch-available': this.launchButton.textContent = dictionary['patching']['stable']; @@ -385,67 +401,78 @@ export default class State else { - const installedVoices = await Voice.installed; - const selectedVoices = await Voice.selected; + const gameDir = await constants.paths.gameDir; - let voiceUpdateRequired = installedVoices.length != selectedVoices.length || installedVoices.length === 0; + if (await fs.exists(`${gameDir}/hdifffiles.txt`)) + state = 'game-files-changes-applying-required'; - if (!voiceUpdateRequired) - { - for (const installedVoice of installedVoices) - if (installedVoice.version != gameCurrent || !selectedVoices.includes(installedVoice.lang)) - { - voiceUpdateRequired = true; - - break; - } - } - - // TODO: download default voice language if user removed all of them - if (voiceUpdateRequired) - state = 'game-voice-update-required'; + else if (await fs.exists(`${gameDir}/deletefiles.txt`)) + state = 'game-outdated-files-deletion-required'; else { - try - { - const patch = await Patch.latest; + const installedVoices = await Voice.installed; + const selectedVoices = await Voice.selected; - // If the latest game version is, for example, 2.3.0 - // and the patch is 2.4.0 preparation, it means that - // 2.4.0 will be released soon, but since it's still not released - // we shouldn't show something about it to user and just let him play the game - if (gameLatest.game.latest.version === patch.version && !patch.applied) + let voiceUpdateRequired = installedVoices.length != selectedVoices.length || installedVoices.length === 0; + + if (!voiceUpdateRequired) + { + for (const installedVoice of installedVoices) + if (installedVoice.version != gameCurrent || !selectedVoices.includes(installedVoice.lang)) + { + voiceUpdateRequired = true; + + break; + } + } + + // TODO: download default voice language if user removed all of them + if (voiceUpdateRequired) + state = 'game-voice-update-required'; + + else + { + try { - state = patch.state == 'preparation' ? - 'patch-unavailable' : (patch.state == 'testing' ? - 'test-patch-available' : 'patch-available'); + const patch = await Patch.latest; + + // If the latest game version is, for example, 2.3.0 + // and the patch is 2.4.0 preparation, it means that + // 2.4.0 will be released soon, but since it's still not released + // we shouldn't show something about it to user and just let him play the game + if (gameLatest.game.latest.version === patch.version && !patch.applied) + { + state = patch.state == 'preparation' ? + 'patch-unavailable' : (patch.state == 'testing' ? + 'test-patch-available' : 'patch-available'); + } + + // Patch is more important than game pre-downloading + // because otherwise we will not be able to play the game + else if (gameLatest.pre_download_game && !await Game.isUpdatePredownloaded()) + state = 'game-pre-installation-available'; + + else if (gameLatest.pre_download_game && !await Voice.isUpdatePredownloaded(await Voice.selected)) + state = 'game-voice-pre-installation-available'; + + else state = 'game-launch-available'; } - // Patch is more important than game pre-downloading - // because otherwise we will not be able to play the game - else if (gameLatest.pre_download_game && !await Game.isUpdatePredownloaded()) - state = 'game-pre-installation-available'; + // Patch.latest can throw an error if all of patch's servers + // are not available, and we must notify user about that + catch + { + state = 'game-launch-available'; - else if (gameLatest.pre_download_game && !await Voice.isUpdatePredownloaded(await Voice.selected)) - state = 'game-voice-pre-installation-available'; - - else state = 'game-launch-available'; + Notification.show({ + ...(Locales.translate('notifications.patch_repos_unavailable') as { title: string, body: string }), + icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`, + importance: 'critical' + }); + } } - - // Patch.latest can throw an error if all of patch's servers - // are not available, and we must notify user about that - catch - { - state = 'game-launch-available'; - - Notification.show({ - ...(Locales.translate('notifications.patch_repos_unavailable') as { title: string, body: string }), - icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`, - importance: 'critical' - }); - } - } + } } } diff --git a/src/ts/launcher/states/ApplyChanges.ts b/src/ts/launcher/states/ApplyChanges.ts new file mode 100644 index 0000000..7e5cf6c --- /dev/null +++ b/src/ts/launcher/states/ApplyChanges.ts @@ -0,0 +1,95 @@ +import type Launcher from '../../Launcher'; + +import { Debug, Notification, fs } from '../../../empathize'; + +import constants from '../../Constants'; +import Locales from '../Locales'; +import HDiffPatch from '../../core/HDiffPatch'; + +declare const Neutralino; + +export default (launcher: Launcher): Promise => { + return new Promise(async (resolve) => { + const gameDir = await constants.paths.gameDir; + + Neutralino.filesystem.readFile(`${gameDir}/hdifffiles.txt`) + .then(async (files) => { + let patchErrors = 0; + + files = files.split(/\r\n|\r|\n/).filter((file) => file != ''); + + if (files.length > 0) + { + launcher.progressBar?.init({ + label: Locales.translate('launcher.progress.game.applying_changes') as string, + showSpeed: false, + showEta: true, + showPercents: true, + showTotals: false + }); + + launcher.progressBar?.show(); + + let current = 0, total = files.length; + + for (const file of files) + { + // {"remoteName": "AnAnimeGame_Data/StreamingAssets/Audio/GeneratedSoundBanks/Windows/Banks0.pck"} + const filePatchInfo = JSON.parse(file) as { remoteName: string }; + + if (await fs.exists(`${gameDir}/${filePatchInfo.remoteName}.hdiff`)) + { + const patchResult = await HDiffPatch.patch( + `${gameDir}/${filePatchInfo.remoteName}`, + `${gameDir}/${filePatchInfo.remoteName}.hdiff`, + `${gameDir}/${filePatchInfo.remoteName}.hdiff_patched` + ); + + if (patchResult) + { + await Neutralino.filesystem.removeFile(`${gameDir}/${filePatchInfo.remoteName}`); + await Neutralino.filesystem.removeFile(`${gameDir}/${filePatchInfo.remoteName}.hdiff`); + + await Neutralino.filesystem.moveFile( + `${gameDir}/${filePatchInfo.remoteName}.hdiff_patched`, + `${gameDir}/${filePatchInfo.remoteName}` + ); + } + + else ++patchErrors; + } + + launcher.progressBar?.update(++current, total, 1); + } + + if (patchErrors > 0) + { + const locale = Locales.translate('notifications.game_changes_applying_error') as { title: string, body: string }; + + Notification.show({ + title: locale.title, + body: locale.body.replace('{files}', patchErrors.toString()), + icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`, + importance: 'critical' + }); + } + + Debug.log({ + function: 'Launcher/States/Install', + message: [ + `Applied changes${patchErrors > 0 ? ` (${patchErrors} errors)` : ''}:`, + ...files + ] + }); + } + + if (patchErrors === 0) + await Neutralino.filesystem.removeFile(`${gameDir}/hdifffiles.txt`); + + launcher.progressBar?.hide(); + + resolve(); + }) + .catch(() => resolve()); + }); +}; diff --git a/src/ts/launcher/states/Install.ts b/src/ts/launcher/states/Install.ts index b38bb6c..05cdb6b 100644 --- a/src/ts/launcher/states/Install.ts +++ b/src/ts/launcher/states/Install.ts @@ -1,15 +1,10 @@ -import { get as svelteget } from 'svelte/store'; -import { _ } from 'svelte-i18n'; - import type Launcher from '../../Launcher'; -import { Debug } from '../../../empathize'; - import Game from '../../Game'; import Prefix from '../../core/Prefix'; import constants from '../../Constants'; - -declare const Neutralino; +import Locales from '../Locales'; +import { promisify } from '@empathize/framework'; export default (launcher: Launcher): Promise => { return new Promise(async (resolve) => { @@ -31,7 +26,7 @@ export default (launcher: Launcher): Promise => { Game.update(prevGameVersion).then((stream) => { launcher.progressBar?.init({ - label: svelteget(_)('launcher.progress.game.downloading'), + label: Locales.translate('launcher.progress.game.downloading') as string, showSpeed: true, showEta: true, showPercents: true, @@ -48,14 +43,14 @@ export default (launcher: Launcher): Promise => { { stream?.pauseDownload(); - launcher.state!.pauseButton.textContent = svelteget(_)('launcher.progress.resume'); + launcher.state!.pauseButton.textContent = Locales.translate('launcher.progress.resume') as string; } else { stream?.resumeDownload(); - launcher.state!.pauseButton.textContent = svelteget(_)('launcher.progress.pause'); + launcher.state!.pauseButton.textContent = Locales.translate('launcher.progress.pause') as string; } paused = !paused; @@ -69,7 +64,7 @@ export default (launcher: Launcher): Promise => { stream?.unpackStart(() => { launcher.progressBar?.init({ - label: svelteget(_)('launcher.progress.game.unpacking'), + label: Locales.translate('launcher.progress.game.unpacking') as string, showSpeed: true, showEta: true, showPercents: true, @@ -87,56 +82,31 @@ export default (launcher: Launcher): Promise => { }); stream?.unpackFinish(async () => { - const gameDir = await constants.paths.gameDir; + // Hide pause/resume button + launcher.state!.pauseButton.style['display'] = 'none'; - // Deleting outdated files - Neutralino.filesystem.readFile(`${gameDir}/deletefiles.txt`) - .then(async (files) => { - files = files.split(/\r\n|\r|\n/).filter((file) => file != ''); - - if (files.length > 0) - { - launcher.progressBar?.init({ - label: svelteget(_)('launcher.progress.game.deleting_outdated'), - showSpeed: false, - showEta: true, - showPercents: true, - showTotals: false + await promisify({ + callbacks: [ + // Applying game's files changes + (): Promise => new Promise((resolve) => { + import('./ApplyChanges').then((module) => { + module.default(launcher).then(() => resolve()); }); + }), - let current = 0, total = files.length; - - for (const file of files) - { - await Neutralino.filesystem.removeFile(`${gameDir}/${file}`); - - launcher.progressBar?.update(++current, total, 1); - } - - Debug.log({ - function: 'Launcher/States/Install', - message: [ - 'Deleted outdated files:', - ...files - ] + // Deleting outdated files + (): Promise => new Promise((resolve) => { + import('./RemoveOutdated').then((module) => { + module.default(launcher).then(() => resolve()); }); - } - - await Neutralino.filesystem.removeFile(`${gameDir}/deletefiles.txt`); - - installVoice(); - }) - .catch(() => installVoice()); + }) + ] + }); // Download voice package when the game itself has been installed - const installVoice = () => { - // Hide pause/resume button - launcher.state!.pauseButton.style['display'] = 'none'; - - import('./InstallVoice').then((module) => { - module.default(launcher).then(() => resolve()); - }); - }; + import('./InstallVoice').then((module) => { + module.default(launcher).then(() => resolve()); + }); }); }); }; diff --git a/src/ts/launcher/states/RemoveOutdated.ts b/src/ts/launcher/states/RemoveOutdated.ts new file mode 100644 index 0000000..4786fa2 --- /dev/null +++ b/src/ts/launcher/states/RemoveOutdated.ts @@ -0,0 +1,56 @@ +import type Launcher from '../../Launcher'; + +import { Debug } from '../../../empathize'; + +import constants from '../../Constants'; +import Locales from '../Locales'; + +declare const Neutralino; + +export default (launcher: Launcher): Promise => { + return new Promise(async (resolve) => { + const gameDir = await constants.paths.gameDir; + + Neutralino.filesystem.readFile(`${gameDir}/deletefiles.txt`) + .then(async (files) => { + files = files.split(/\r\n|\r|\n/).filter((file) => file != ''); + + if (files.length > 0) + { + launcher.progressBar?.init({ + label: Locales.translate('launcher.progress.game.deleting_outdated') as string, + showSpeed: false, + showEta: true, + showPercents: true, + showTotals: false + }); + + launcher.progressBar?.show(); + + let current = 0, total = files.length; + + for (const file of files) + { + await Neutralino.filesystem.removeFile(`${gameDir}/${file}`); + + launcher.progressBar?.update(++current, total, 1); + } + + Debug.log({ + function: 'Launcher/States/RemoveOutdated', + message: [ + 'Deleted outdated files:', + ...files + ] + }); + } + + await Neutralino.filesystem.removeFile(`${gameDir}/deletefiles.txt`); + + launcher.progressBar?.hide(); + + resolve(); + }) + .catch(() => resolve()); + }); +}; diff --git a/src/ts/types/Launcher.ts b/src/ts/types/Launcher.ts index 0409298..cfcd945 100644 --- a/src/ts/types/Launcher.ts +++ b/src/ts/types/Launcher.ts @@ -21,6 +21,8 @@ type LauncherState = | 'game-installation-available' | 'game-update-available' | 'game-voice-update-required' + | 'game-files-changes-applying-required' + | 'game-outdated-files-deletion-required' | 'game-pre-installation-available' | 'game-voice-pre-installation-available' | 'game-launch-available';