123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- import QtQuick 2.0
- import Qt.labs.settings 1.0
- import Qt.labs.platform 1.1
- import FileIO 1.0
- import "components"
- Item {
- id: installer
- readonly property string homePath: FileIO.userHomePath()
- readonly property string defaultGamePath: "drive_c/Program Files/Genshin Impact/Genshin Impact Game"
- readonly property string defaultLocation: `${homePath}/.wine/${defaultGamePath}`
- readonly property string configIni: "config.ini"
- readonly property string versionNotInstalled: "Not installed"
- readonly property var possibleLocations: [
- `.wine*/${defaultGamePath}`,
- `.steam/steam/steamapps/common/Proton */dist/share/default_pfx/${defaultGamePath}`
- ]
- property string patchRepo: "https://notabug.org/Krock/dawn"
- property alias installedVersion: localVersionLoader.version
- property string availableVersion
- property string preDownloadVersion
- property bool isPreDownloading: false
- property bool quitAfterCancel: false
- property bool startupUpdateChecked: false
- anchors.fill: parent
- InstallerUi {
- id: ui
- anchors.fill: parent
- progressText: clientInstaller.progressText
- progress: clientInstaller.progressPercent / 100.0
- onBrowseClicked: {
- fileDialog.open()
- }
- onInstallClicked: {
- ui.uiState = ui.uiStateInstalling
- dependenciesInstaller.check()
- }
- onCancelConfirmed: {
- clientInstaller.cancel()
- ui.log(qsTr("Canceled"))
- ui.log(qsTr(""))
- revertUiState()
- if (quitAfterCancel) {
- quitAfterCancel = false
- window.close()
- }
- }
- onCancelRejected: {
- quitAfterCancel = false
- }
- onPreDownloadClicked: {
- isPreDownloading = true
- dependenciesInstaller.check()
- }
- onUpdateClicked: {
- ui.uiState = ui.uiStateUpdating
- dependenciesInstaller.check()
- }
- onRetryClicked: checkForUpdates()
- onHdiffPatchClicked: {
- ui.uiState = ui.uiStateUpdating
- clientInstaller.installHDiffPatches()
- }
- onRepatchClicked: clientInstaller.reapplyWinePatch()
- onStartClicked: {
- ui.uiState = ui.uiStateStarting
- clientLauncher.start()
- }
- onStopConfirmed: {
- ui.uiState = ui.uiStateStopping
- clientLauncher.stop()
- }
- onKillWineServerClicked: clientLauncher.killWineServer()
- onCheckSelfUpdateClicked: selfUpdate.check()
- onCheckIntegrityClicked: {
- ui.uiState = ui.uiStateChecking
- integrityCheck.checkAll()
- }
- onCheckStopClicked: {
- ui.log(qsTr("Integrity check canceled."))
- integrityCheck.stop()
- checkFinished()
- }
- }
- Settings {
- id: settings
- category: "game"
- property string gamePath: ""
- property alias isLogVisible: ui.isLogVisible
- property bool multiConnections: false
- property bool limitDownload: false
- property bool checkLauncherUpdatesAtStartup: true
- property string multiConnectionsValue: "4"
- property string limitDownloadValue: "1M"
- property bool hideBackground: false
- property bool firstRun: true
- }
- LocalVersionLoader {
- id: localVersionLoader
- iniFilePath: settings.gamePath + configIni
- }
- WebVersionLoader {
- id: webVersionLoader
- onJsonChanged: tryCheckVersion()
- onError: {
- ui.showLog()
- ui.uiState = ui.uiStateRetry
- ui.log(qsTr("Failed to check version info. Check your Internet connection and try again."))
- }
- }
- DependenciesInstaller {
- id: dependenciesInstaller
- anchors.fill: parent
- onDependenciesInstallCanceled: {
- isPreDownloading = false
- ui.uiState = ui.uiStateInstall
- }
- onDependenciesInstallError: {
- ui.showLog()
- ui.log(qsTr("Failed to install dependencies"))
- revertUiState()
- }
- onDependenciesInstalled: startInstallUpdate()
- }
- ClientInstaller {
- id: clientInstaller
- anchors.fill: parent
- onPredownloadFinished: {
- isPreDownloading = false
- ui.hasPreDownload = false
- }
- onInstallError: {
- ui.showLog()
- switch (ui.uiState) {
- case ui.uiStateInstalling:
- ui.uiState = ui.uiStateInstall
- ui.log(qsTr("Error installing client"))
- return
- case ui.uiStateUpdating:
- ui.log(qsTr("Error updating client"))
- break
- case ui.uiStatePatch:
- ui.log(qsTr("Error patching client"))
- break
- }
- ui.log(qsTr(""))
- revertUiState()
- }
- onInstallCanceled: {
- switch (ui.uiState) {
- case ui.uiStateInstalling:
- ui.log(qsTr("Installation canceled"))
- return
- case ui.uiStateUpdating:
- ui.log(qsTr("Update canceled"))
- break
- }
- ui.log(qsTr(""))
- revertUiState()
- }
- onInstallFinished: {
- switch (ui.uiState) {
- case ui.uiStateInstalling:
- ui.log(qsTr("Installation completed!"))
- break
- case ui.uiStateUpdating:
- ui.log(qsTr("Update completed!"))
- break
- }
- ui.log(qsTr(""))
- checkFinished()
- isPreDownloading = false
- }
- onInstallSelectLanguagesCanceled: {
- revertUiState()
- }
- }
- IntegrityCheck {
- id: integrityCheck
- onProgressChanged: {
- if (progress.total) {
- clientInstaller.progressText = qsTr("Checking file ")
- + progress.value + qsTr(" of ") + progress.total
- } else {
- clientInstaller.progressText = qsTr("Checking files...")
- }
- clientInstaller.progressPercent = progress.value * 100.0 / progress.total
- }
- onFinished: checkFinished()
- }
- ClientLauncher {
- id: clientLauncher
- onIsRunningChanged: {
- if (isRunning) {
- ui.uiState = ui.uiStateRunning
- } else {
- checkFinished()
- }
- }
- }
- SelfUpdate {
- id: selfUpdate
- anchors.fill: parent
- Component.onCompleted: {
- if (settings.checkLauncherUpdatesAtStartup && !startupUpdateChecked) {
- startupUpdateChecked = true
- selfUpdate.check()
- }
- }
- }
- FolderDialog {
- id: fileDialog
- title: qsTr(`Please choose 'Genshin Impact Game' directory`)
- folder: "file://" + (settings.gamePath || shortcuts.home)
- onAccepted: {
- let path = fileDialog.folder.toString().replace("file://", "")
- if (!path.endsWith('/')) {
- path += '/'
- }
- settings.gamePath = path
- ui.clearLog()
- if (!bootstrap()) {
- showInstallState()
- }
- }
- }
- function checkFinished() {
- ui.hasUpdate = !!availableVersion && availableVersion !== installedVersion
- if (!clientInstaller.isHdiffPatchInstalled()) {
- ui.log(qsTr("HDiff patches aren't installed. Press Update to install them..."))
- ui.uiState = ui.uiStateHdiffPatch
- } else if (!clientInstaller.isWinePatchInstalled()) {
- ui.uiState = ui.uiStatePatch
- } else {
- ui.uiState = ui.uiStateStart
- }
- }
- function tryCheckVersion() {
- if (!webVersionLoader.json) {
- return
- }
- let game = webVersionLoader.json.data.game
- availableVersion = game.latest.version
- ui.log(qsTr("Web Version:") + " " + availableVersion)
- ui.hasUpdate = availableVersion !== installedVersion
- if (!ui.hasUpdate) {
- ui.log(qsTr("The game is up to date!"))
- checkFinished()
- let existingPreDownloadedVersion = clientInstaller.getPreDownloadedVersion()
- let preDownload = webVersionLoader.json.data.pre_download_game
- let hasPreDownload = preDownload && preDownload.latest && preDownload.latest.version || false
- if (hasPreDownload) {
- let latestPreDownloadVersion = preDownload.latest.version
- if (latestPreDownloadVersion !== existingPreDownloadedVersion) {
- preDownloadVersion = preDownload.latest.version
- ui.log(qsTr("Pre-download available") + " " + latestPreDownloadVersion)
- } else {
- ui.log(qsTr("The version") + " " + existingPreDownloadedVersion + " " + qsTr("is pre-downloaded"))
- hasPreDownload = false
- }
- }
- ui.hasPreDownload = hasPreDownload
- return
- }
- ui.log(qsTr("Update available"))
- switch (ui.uiState) {
- case ui.uiStateInstalling:
- clientInstaller.start()
- break
- case ui.uiStateLoading:
- checkFinished()
- break
- }
- }
- function tryLoadGameSettings() {
- if (!settings.gamePath) {
- console.debug("settings.gamePath is not set")
- return false
- }
- ui.log(qsTr("Game path: ") + settings.gamePath)
- const gameConfigPath = settings.gamePath + configIni
- if (!FileIO.isFileExists(gameConfigPath)) {
- console.debug(`${gameConfigPath} doesn't exist`)
- return false
- }
- localVersionLoader.load()
- return true
- }
- function checkForUpdates() {
- ui.log(qsTr("Installed Version:") + " " + installedVersion)
- ui.log(qsTr("Checking for updates..."))
- ui.uiState = ui.uiStateLoading
- webVersionLoader.loadVersion()
- }
- function detectLocation() {
- let foundPath
- for (let location of possibleLocations) {
- let foundLocations = FileIO.matchByWildcard(homePath + "/" + location + "/" + configIni)
- var foundLocation = foundLocations[0]
- if (foundLocation) {
- foundPath = foundLocation.substr(0, foundLocation.length - configIni.length)
- break
- }
- }
- return foundPath
- }
- function bootstrap() {
- if (tryLoadGameSettings()) {
- if (!FileIO.isFileExists(settings.gamePath + "GenshinImpact.exe")) {
- ui.log(qsTr("⚠ Wrong directory set as game directory."))
- ui.log(qsTr("⚠ Please choose 'Genshin Imact Game' dir, not the 'Genshin Impact'!"))
- ui.uiState = ui.uiStateWrongDir
- return true
- }
- if (!localVersionLoader.version) {
- ui.log(qsTr("⚠ Can't read game_version from config.ini, update wouldn't be possible."))
- checkFinished()
- return true
- }
- checkForUpdates()
- integrityCheck.reload()
- return true
- }
- return false
- }
- function handleAppExit() {
- if (!clientInstaller.isActive) {
- return true
- }
- quitAfterCancel = true
- ui.confirmCancelInstall()
- return false
- }
- function revertUiState() {
- switch (ui.uiState) {
- case ui.uiStateInstalling:
- ui.uiState = ui.uiStateInstall
- break
- case ui.uiStateInstall:
- break
- default:
- checkFinished()
- }
- isPreDownloading = false
- }
- function startInstallUpdate() {
- if (!webVersionLoader.json && !webVersionLoader.isLoading) {
- webVersionLoader.loadVersion()
- return
- }
- clientInstaller.start()
- }
- function showInstallState() {
- // in case we have empty directory as game path
- ui.log(qsTr("Install to specified location or press 'Browse...' to browse for game dir"))
- ui.uiState = ui.uiStateInstall
- }
- Component.onCompleted: {
- ui.log(qsTr("Please refrain from sharing this project in public."))
- ui.log("")
- if (!settings.gamePath.endsWith('/')) {
- settings.gamePath += '/'
- }
- if (bootstrap()) {
- return
- }
- if (settings.gamePath) {
- showInstallState()
- return
- }
- let foundPath = detectLocation()
- if (foundPath) {
- ui.log(qsTr("Location detected:") + " " + foundPath)
- settings.gamePath = foundPath
- if (bootstrap()) {
- return
- }
- }
- if (!foundPath) {
- ui.log(qsTr("No previously installed game detected."))
- } else {
- ui.log(qsTr("Failed to load game config."))
- }
- ui.log(qsTr("Install to default location or press 'Browse...' to browse for game dir"))
- ui.log(qsTr("Location to install:"))
- ui.log(defaultLocation)
- settings.gamePath = defaultLocation
- ui.uiState = ui.uiStateInstall
- }
- }
|