diff --git a/src/assetupdater.cpp b/src/assetupdater.cpp index 034e417..c5c8821 100644 --- a/src/assetupdater.cpp +++ b/src/assetupdater.cpp @@ -43,26 +43,51 @@ void AssetUpdater::update(const ProfileSettings& profile) { qInfo() << "Starting update sequence..."; - const bool hasDalamud = QFile::exists(dataDir + "/NativeLauncher.exe") && - QFile::exists(dataDir + "/Dalamud"); - bool isDalamudUpdated = false; - if (hasDalamud) { - if (remoteDalamudVersion.isEmpty()) { - QNetworkRequest request(dalamudVersionPath); + if (remoteDalamudVersion.isEmpty()) { + QNetworkRequest request(dalamudVersionPath); - auto reply = launcher.mgr->get(request); - reply->setObjectName("DalamudVersionCheck"); - currentSettings = &profile; // TODO: this is dirty, should change + auto reply = launcher.mgr->get(request); + reply->setObjectName("DalamudVersionCheck"); + currentSettings = &profile; // TODO: this is dirty, should change - return; + return; + } else { + if (profile.dalamudVersion != remoteDalamudVersion) { + isDalamudUpdated = false; } else { - if (profile.dalamudVersion != remoteDalamudVersion) { - isDalamudUpdated = false; - } else { - qInfo() << "No need to update Dalamud."; - isDalamudUpdated = true; + qInfo() << "No need to update Dalamud."; + isDalamudUpdated = true; + } + + if(profile.runtimeVersion != remoteRuntimeVersion) { + doneDownloadingRuntimeCore = false; + doneDownloadingRuntimeDesktop = false; + needsRuntimeInstall = true; + + // core + { + QNetworkRequest request( + QString("https://dotnetcli.azureedge.net/dotnet/Runtime/%1/dotnet-runtime-%1-win-x64.zip") + .arg(remoteRuntimeVersion)); + + auto reply = launcher.mgr->get(request); + reply->setObjectName("Dotnet-core"); } + + // desktop + { + QNetworkRequest request( + QString("https://dotnetcli.azureedge.net/dotnet/WindowsDesktop/%1/windowsdesktop-runtime-%1-win-x64.zip") + .arg(remoteRuntimeVersion)); + + auto reply = launcher.mgr->get(request); + reply->setObjectName("Dotnet-desktop"); + } + } else { + qInfo() << "No need to update Runtime."; + doneDownloadingRuntimeCore = true; + doneDownloadingRuntimeDesktop = true; } } @@ -159,16 +184,26 @@ void AssetUpdater::update(const ProfileSettings& profile) { }); } - // first we determine if we need dalamud - const bool needsDalamud = - profile.enableDalamud && (!hasDalamud || !isDalamudUpdated); - if (needsDalamud) { + if(remoteDalamudVersion != profile.dalamudVersion) { + qInfo() << "Downloading Dalamud..."; + doneDownloadingDalamud = false; + needsDalamudInstall = true; + + QNetworkRequest request(dalamudRemotePath + dalamudVersion + + ".zip"); + + auto reply = launcher.mgr->get(request); + reply->setObjectName("Dalamud"); + } + + const bool hasNative = QFile::exists(dataDir + "/NativeLauncher.exe"); + if (!hasNative) { // download nativelauncher release (needed to launch the game with fixed // ACLs) { qInfo() << "Downloading NativeLauncher..."; doneDownloadingNativelauncher = false; - needsInstall = true; + needsNativeInstall = true; QNetworkRequest request(nativeLauncherRemotePath + nativeLauncherVersion + @@ -177,19 +212,6 @@ void AssetUpdater::update(const ProfileSettings& profile) { auto reply = launcher.mgr->get(request); reply->setObjectName("NativeLauncher"); } - - // download dalamud (... duh) - { - qInfo() << "Downloading Dalamud..."; - doneDownloadingDalamud = false; - needsInstall = true; - - QNetworkRequest request(dalamudRemotePath + dalamudVersion + - ".zip"); - - auto reply = launcher.mgr->get(request); - reply->setObjectName("Dalamud"); - } } } @@ -203,6 +225,7 @@ void AssetUpdater::finishDownload(QNetworkReply* reply) { file.close(); doneDownloadingDalamud = true; + checkIfFinished(); } else if (reply->objectName() == "NativeLauncher") { qInfo() << "NativeLauncher finished downloading!"; @@ -213,6 +236,7 @@ void AssetUpdater::finishDownload(QNetworkReply* reply) { file.close(); doneDownloadingNativelauncher = true; + checkIfFinished(); } else if (reply->objectName() == "DalamudVersionCheck") { QByteArray str = reply->readAll(); @@ -228,29 +252,83 @@ void AssetUpdater::finishDownload(QNetworkReply* reply) { QJsonDocument doc = QJsonDocument::fromJson(reassmbled.toUtf8()); remoteDalamudVersion = doc["AssemblyVersion"].toString(); + remoteRuntimeVersion = doc["RuntimeVersion"].toString(); qInfo() << "Latest Dalamud version reported: " << remoteDalamudVersion; + qInfo() << "Latest NET runtime reported: " << remoteRuntimeVersion; update(*currentSettings); currentSettings = nullptr; + } else if(reply->objectName() == "Dotnet-core") { + qInfo() << "Dotnet-core finished downloading!"; + + QFile file(tempDir.path() + "/dotnet-core.zip"); + file.open(QIODevice::WriteOnly); + file.write(reply->readAll()); + file.close(); + + doneDownloadingRuntimeCore = true; + + checkIfFinished(); + } else if(reply->objectName() == "Dotnet-desktop") { + qInfo() << "Dotnet-desktop finished downloading!"; + + QFile file(tempDir.path() + "/dotnet-desktop.zip"); + file.open(QIODevice::WriteOnly); + file.write(reply->readAll()); + file.close(); + + doneDownloadingRuntimeDesktop = true; + + checkIfFinished(); } } void AssetUpdater::beginInstall() { - QString dataDir = + const QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - bool success = !JlCompress::extractDir(tempDir.path() + "/latest.zip", - dataDir + "/Dalamud") - .empty(); - if (success) { + if(needsDalamudInstall) { + bool success = !JlCompress::extractDir(tempDir.path() + "/latest.zip", + dataDir + "/Dalamud") + .empty(); + + if(!success) { + // TODO: handle failure here + } else { + needsDalamudInstall = false; + } + } + + if(needsNativeInstall) { QFile::copy(tempDir.path() + "/NativeLauncher.exe", dataDir + "/NativeLauncher.exe"); - finishedUpdating(); - } else { - // STUB: install failure + needsNativeInstall = false; } + + if(needsRuntimeInstall) { + bool success = !JlCompress::extractDir(tempDir.path() + "/dotnet-core.zip", + dataDir + "/DalamudRuntime") + .empty(); + + success |= !JlCompress::extractDir(tempDir.path() + "/dotnet-desktop.zip", + dataDir + "/DalamudRuntime") + .empty(); + + if(!success) { + // TODO: handle failure here + } else { + QFile file(dataDir + "/DalamudRuntime/runtime.ver"); + file.open(QIODevice::WriteOnly | QIODevice::Text); + file.write(remoteRuntimeVersion.toUtf8()); + file.close(); + + needsRuntimeInstall = false; + } + } + + checkIfFinished(); } void AssetUpdater::checkIfDalamudAssetsDone() { @@ -268,11 +346,14 @@ void AssetUpdater::checkIfDalamudAssetsDone() { checkIfFinished(); } } + void AssetUpdater::checkIfFinished() { if (doneDownloadingDalamud && doneDownloadingNativelauncher && + doneDownloadingRuntimeCore && + doneDownloadingRuntimeDesktop && dalamudAssetNeededFilenames.empty()) { - if(needsInstall) + if(needsRuntimeInstall || needsNativeInstall || needsDalamudInstall) beginInstall(); else finishedUpdating(); diff --git a/src/assetupdater.h b/src/assetupdater.h index 11052be..72ed88c 100644 --- a/src/assetupdater.h +++ b/src/assetupdater.h @@ -28,12 +28,17 @@ private: const ProfileSettings* currentSettings = nullptr; QString remoteDalamudVersion; + QString remoteRuntimeVersion; QTemporaryDir tempDir; bool doneDownloadingDalamud = true; bool doneDownloadingNativelauncher = true; - bool needsInstall = false; + bool doneDownloadingRuntimeCore = true; + bool doneDownloadingRuntimeDesktop = true; + bool needsRuntimeInstall = false; + bool needsDalamudInstall = false; + bool needsNativeInstall = false; int remoteDalamudAssetVersion; QList dalamudAssetNeededFilenames; diff --git a/src/launchercore.cpp b/src/launchercore.cpp index 6482e4d..e19adb9 100755 --- a/src/launchercore.cpp +++ b/src/launchercore.cpp @@ -149,14 +149,21 @@ void LauncherCore::launchGame(const ProfileSettings& profile, const LoginAuth au } auto gameProcess = new QProcess(this); + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + if(profile.useSteam) { gameArgs.push_back({"IsSteam", "1"}); - gameProcess->environment() << "IS_FFXIV_LAUNCH_FROM_STEAM=1"; + env.insert("IS_FFXIV_LAUNCH_FROM_STEAM", QString::number(1)); } + env.insert("DALAMUD_RUNTIME", "Z:" + dataDir.replace('/', '\\') + "\\DalamudRuntime"); + + gameProcess->setProcessEnvironment(env); + gameProcess->setProcessChannelMode(QProcess::MergedChannels); if(profile.enableDalamud) { - connect(gameProcess, &QProcess::readyReadStandardOutput, [this, gameProcess, profile, dataDir] { + connect(gameProcess, &QProcess::readyReadStandardOutput, [this, gameProcess, profile] { QString output = gameProcess->readAllStandardOutput(); bool success; int dec = output.toInt(&success, 10); @@ -167,13 +174,16 @@ void LauncherCore::launchGame(const ProfileSettings& profile, const LoginAuth au qDebug() << "Now launching dalamud..."; + QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + dataDir = "Z:" + dataDir.replace('/', '\\'); + QJsonObject startInfo; - startInfo["WorkingDirectory"] = QJsonValue(); - startInfo["ConfigurationPath"] = dataDir + "/dalamudConfig.json"; - startInfo["PluginDirectory"] = dataDir + "/installedPlugins"; - startInfo["AssetDirectory"] = dataDir + "/DalamudAssets"; - startInfo["DefaultPluginDirectory"] = dataDir + "/devPlugins"; - startInfo["DelayInitializeMs"] = 5; + startInfo["WorkingDirectory"] = dataDir; + startInfo["ConfigurationPath"] = dataDir + "\\dalamudConfig.json"; + startInfo["PluginDirectory"] = dataDir + "\\installedPlugins"; + startInfo["AssetDirectory"] = dataDir + "\\DalamudAssets"; + startInfo["DefaultPluginDirectory"] = dataDir + "\\devPlugins"; + startInfo["DelayInitializeMs"] = 0; startInfo["GameVersion"] = profile.gameVersion; startInfo["Language"] = profile.language; startInfo["OptOutMbCollection"] = false; @@ -183,16 +193,17 @@ void LauncherCore::launchGame(const ProfileSettings& profile, const LoginAuth au auto dalamudProcess = new QProcess(); dalamudProcess->setProcessChannelMode(QProcess::ForwardedChannels); - QStringList dalamudEnv = gameProcess->environment(); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("DALAMUD_RUNTIME", dataDir + "\\DalamudRuntime"); #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) - dalamudEnv << "XL_WINEONLINUX=true"; + env.insert("XL_WINEONLINUX", "true"); #endif + dalamudProcess->setProcessEnvironment(env); - dalamudProcess->setEnvironment(dalamudEnv); - - QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + auto list = dalamudProcess->processEnvironment().toStringList(); + // TODO: what if we aren't on wine? dalamudProcess->start(profile.winePath, {dataDir + "/Dalamud/" + "Dalamud.Injector.exe", output, argsEncoded}); }); } @@ -227,7 +238,7 @@ void LauncherCore::launchExecutable(const ProfileSettings& profile, const QStrin void LauncherCore::launchExecutable(const ProfileSettings& profile, QProcess* process, const QStringList args) { QList arguments; - QStringList env = QProcess::systemEnvironment(); + auto env = process->processEnvironment(); #if defined(Q_OS_LINUX) if(profile.useGamescope) { @@ -253,17 +264,17 @@ void LauncherCore::launchExecutable(const ProfileSettings& profile, QProcess* pr arguments.push_back("gamemoderun"); if(profile.useEsync) { - env << "WINEESYNC=1"; - env << "WINEFSYNC=1"; - env << "WINEFSYNC_FUTEX2=1"; + env.insert("WINEESYNC", QString::number(1)); + env.insert("WINEFSYNC", QString::number(1)); + env.insert("WINEFSYNC_FUTEX2", QString::number(1)); } #endif #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) - env << "WINEPREFIX=" + profile.winePrefixPath; + env.insert("WINEPREFIX", profile.winePrefixPath); if(profile.enableDXVKhud) - env << "DXVK_HUD=full"; + env.insert("DXVK_HUD", "full"); arguments.push_back(profile.winePath); #endif @@ -274,7 +285,7 @@ void LauncherCore::launchExecutable(const ProfileSettings& profile, QProcess* pr arguments.removeFirst(); process->setWorkingDirectory(profile.gamePath + "/game/"); - process->setEnvironment(env); + process->setProcessEnvironment(env); process->start(executable, arguments); } @@ -343,6 +354,13 @@ void LauncherCore::readInitialInformation() { profile.dalamudAssetVersion = QString(assetJson.readAll()).toInt(); } + + if(QFile::exists(dataDir + "/DalamudRuntime/runtime.ver")) { + QFile runtimeVer(dataDir + "/DalamudRuntime/runtime.ver"); + runtimeVer.open(QFile::ReadOnly | QFile::Text); + + profile.runtimeVersion = QString(runtimeVer.readAll()); + } } if(settings.contains("gamePath") && settings.value("gamePath").canConvert() && !settings.value("gamePath").toString().isEmpty()) { diff --git a/src/launchercore.h b/src/launchercore.h index 0824308..b3909b7 100755 --- a/src/launchercore.h +++ b/src/launchercore.h @@ -49,6 +49,7 @@ struct ProfileSettings { QString dalamudVersion; // TODO: move out of profile settings int dalamudAssetVersion = -1; + QString runtimeVersion; // login bool encryptArguments = true;