mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-22 12:47:44 +00:00
Improve the config/data directory, introduce more separation
The data directory has been rearranged, and all the Dalamud data is stored separately, so it's no longer clogging up everything. Dalamud logs (and our own logs, when that's implemented) now exist in XDG_STATE_HOME, instead of the data directory. The game directory now exists under the data directory, instead of ~/.wine. The user path is set before launching the game, and it now exists under the data directory too. These are also prefixed to the user and profile UUID that it belongs to. The "keep patches" option is now implemented (which is off by default) and it lives in the temporary directory now.
This commit is contained in:
parent
0584b3a978
commit
8dd26f74a5
18 changed files with 175 additions and 75 deletions
|
@ -17,6 +17,7 @@ target_sources(astra PRIVATE
|
||||||
include/squareboot.h
|
include/squareboot.h
|
||||||
include/squarelauncher.h
|
include/squarelauncher.h
|
||||||
include/steamapi.h
|
include/steamapi.h
|
||||||
|
include/utility.h
|
||||||
|
|
||||||
src/account.cpp
|
src/account.cpp
|
||||||
src/accountmanager.cpp
|
src/accountmanager.cpp
|
||||||
|
@ -32,6 +33,7 @@ target_sources(astra PRIVATE
|
||||||
src/squareboot.cpp
|
src/squareboot.cpp
|
||||||
src/squarelauncher.cpp
|
src/squarelauncher.cpp
|
||||||
src/steamapi.cpp
|
src/steamapi.cpp
|
||||||
|
src/utility.cpp
|
||||||
|
|
||||||
resources.qrc)
|
resources.qrc)
|
||||||
kconfig_add_kcfg_files(astra GENERATE_MOC config.kcfgc accountconfig.kcfgc profileconfig.kcfgc)
|
kconfig_add_kcfg_files(astra GENERATE_MOC config.kcfgc accountconfig.kcfgc profileconfig.kcfgc)
|
||||||
|
|
|
@ -17,5 +17,8 @@ SPDX-License-Identifier: CC0-1.0
|
||||||
</entry>
|
</entry>
|
||||||
<entry name="AutoLogin" type="string">
|
<entry name="AutoLogin" type="string">
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="KeepPatches" type="bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
</kcfg>
|
</kcfg>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "accountconfig.h"
|
#include "accountconfig.h"
|
||||||
|
@ -66,6 +67,8 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE QString getOTP();
|
Q_INVOKABLE QString getOTP();
|
||||||
|
|
||||||
|
QDir getConfigDir() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
void lodestoneIdChanged();
|
void lodestoneIdChanged();
|
||||||
|
|
|
@ -37,6 +37,11 @@ private:
|
||||||
QString remoteRuntimeVersion;
|
QString remoteRuntimeVersion;
|
||||||
|
|
||||||
QTemporaryDir tempDir;
|
QTemporaryDir tempDir;
|
||||||
|
QDir dataDir;
|
||||||
|
QDir appDataDir;
|
||||||
|
QDir dalamudDir;
|
||||||
|
QDir dalamudAssetDir;
|
||||||
|
QDir dalamudRuntimeDir;
|
||||||
|
|
||||||
bool doneDownloadingDalamud = false;
|
bool doneDownloadingDalamud = false;
|
||||||
bool doneDownloadingRuntimeCore = false;
|
bool doneDownloadingRuntimeCore = false;
|
||||||
|
@ -48,6 +53,5 @@ private:
|
||||||
QList<QString> dalamudAssetNeededFilenames;
|
QList<QString> dalamudAssetNeededFilenames;
|
||||||
QJsonArray remoteDalamudAssetArray;
|
QJsonArray remoteDalamudAssetArray;
|
||||||
|
|
||||||
QString dataDir;
|
|
||||||
Profile &m_profile;
|
Profile &m_profile;
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,6 +63,7 @@ class LauncherCore : public QObject
|
||||||
Q_PROPERTY(AccountManager *accountManager READ accountManager CONSTANT)
|
Q_PROPERTY(AccountManager *accountManager READ accountManager CONSTANT)
|
||||||
Q_PROPERTY(bool closeWhenLaunched READ closeWhenLaunched WRITE setCloseWhenLaunched NOTIFY closeWhenLaunchedChanged)
|
Q_PROPERTY(bool closeWhenLaunched READ closeWhenLaunched WRITE setCloseWhenLaunched NOTIFY closeWhenLaunchedChanged)
|
||||||
Q_PROPERTY(bool showNews READ showNews WRITE setShowNews NOTIFY showNewsChanged)
|
Q_PROPERTY(bool showNews READ showNews WRITE setShowNews NOTIFY showNewsChanged)
|
||||||
|
Q_PROPERTY(bool keepPatches READ keepPatches WRITE setKeepPatches NOTIFY keepPatchesChanged)
|
||||||
Q_PROPERTY(Headline *headline READ headline NOTIFY newsChanged)
|
Q_PROPERTY(Headline *headline READ headline NOTIFY newsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -120,6 +121,9 @@ public:
|
||||||
bool showNews() const;
|
bool showNews() const;
|
||||||
void setShowNews(bool value);
|
void setShowNews(bool value);
|
||||||
|
|
||||||
|
bool keepPatches() const;
|
||||||
|
void setKeepPatches(bool value);
|
||||||
|
|
||||||
int defaultProfileIndex = 0;
|
int defaultProfileIndex = 0;
|
||||||
|
|
||||||
bool m_isSteam = false;
|
bool m_isSteam = false;
|
||||||
|
@ -147,6 +151,7 @@ signals:
|
||||||
void gameClosed();
|
void gameClosed();
|
||||||
void closeWhenLaunchedChanged();
|
void closeWhenLaunchedChanged();
|
||||||
void showNewsChanged();
|
void showNewsChanged();
|
||||||
|
void keepPatchesChanged();
|
||||||
void loginError(QString message);
|
void loginError(QString message);
|
||||||
void stageChanged(QString message);
|
void stageChanged(QString message);
|
||||||
void stageIndeterminate();
|
void stageIndeterminate();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <physis.hpp>
|
#include <physis.hpp>
|
||||||
|
@ -25,6 +26,7 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkIfDone();
|
void checkIfDone();
|
||||||
|
void setupDirectories();
|
||||||
|
|
||||||
[[nodiscard]] bool isBoot() const
|
[[nodiscard]] bool isBoot() const
|
||||||
{
|
{
|
||||||
|
@ -42,6 +44,7 @@ private:
|
||||||
|
|
||||||
QVector<QueuedPatch> patchQueue;
|
QVector<QueuedPatch> patchQueue;
|
||||||
|
|
||||||
|
QDir patchesDir;
|
||||||
QString baseDirectory;
|
QString baseDirectory;
|
||||||
BootData *boot_data = nullptr;
|
BootData *boot_data = nullptr;
|
||||||
GameData *game_data = nullptr;
|
GameData *game_data = nullptr;
|
||||||
|
|
|
@ -150,6 +150,8 @@ public:
|
||||||
return !m_wineVersion.isEmpty();
|
return !m_wineVersion.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString dalamudChannelName() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void gameInstallChanged();
|
void gameInstallChanged();
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE bool canDelete(Profile *account) const;
|
Q_INVOKABLE bool canDelete(Profile *account) const;
|
||||||
|
|
||||||
static QString getDefaultGamePath();
|
static QString getDefaultGamePath(const QString &uuid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void insertProfile(Profile *profile);
|
void insertProfile(Profile *profile);
|
||||||
|
|
9
launcher/include/utility.h
Normal file
9
launcher/include/utility.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
namespace Utility
|
||||||
|
{
|
||||||
|
QDir stateDirectory();
|
||||||
|
QString toWindowsPath(const QDir &dir);
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: CC0-1.0
|
||||||
<default>1</default>
|
<default>1</default>
|
||||||
</entry>
|
</entry>
|
||||||
<entry key="GamePath" type="Path">
|
<entry key="GamePath" type="Path">
|
||||||
<default code="true">ProfileManager::getDefaultGamePath()</default>
|
<default code="true">ProfileManager::getDefaultGamePath(mParamuuid)</default>
|
||||||
</entry>
|
</entry>
|
||||||
<entry key="WinePath" type="Path">
|
<entry key="WinePath" type="Path">
|
||||||
</entry>
|
</entry>
|
||||||
|
|
|
@ -178,6 +178,13 @@ QString Account::getOTP()
|
||||||
return totpStr;
|
return totpStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDir Account::getConfigDir() const
|
||||||
|
{
|
||||||
|
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
|
const QDir userDir = dataDir.absoluteFilePath("user");
|
||||||
|
return userDir.absoluteFilePath(m_key);
|
||||||
|
}
|
||||||
|
|
||||||
void Account::fetchAvatar()
|
void Account::fetchAvatar()
|
||||||
{
|
{
|
||||||
if (lodestoneId().isEmpty()) {
|
if (lodestoneId().isEmpty()) {
|
||||||
|
|
|
@ -35,9 +35,19 @@ AssetUpdater::AssetUpdater(Profile &profile, LauncherCore &launcher, QObject *pa
|
||||||
launcher.mgr->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
launcher.mgr->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
|
|
||||||
dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
|
dalamudDir = dataDir.absoluteFilePath("dalamud");
|
||||||
|
dalamudAssetDir = dalamudDir.absoluteFilePath("assets");
|
||||||
|
dalamudRuntimeDir = dalamudDir.absoluteFilePath("runtime");
|
||||||
|
|
||||||
if (!QDir().exists(dataDir))
|
const auto createIfNeeded = [](const QDir &dir) {
|
||||||
QDir().mkdir(dataDir);
|
if (!QDir().exists(dir.absolutePath()))
|
||||||
|
QDir().mkdir(dir.absolutePath());
|
||||||
|
};
|
||||||
|
|
||||||
|
createIfNeeded(dataDir);
|
||||||
|
createIfNeeded(dalamudDir);
|
||||||
|
createIfNeeded(dalamudAssetDir);
|
||||||
|
createIfNeeded(dalamudRuntimeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetUpdater::update()
|
void AssetUpdater::update()
|
||||||
|
@ -124,7 +134,7 @@ void AssetUpdater::update()
|
||||||
void AssetUpdater::beginInstall()
|
void AssetUpdater::beginInstall()
|
||||||
{
|
{
|
||||||
if (needsDalamudInstall) {
|
if (needsDalamudInstall) {
|
||||||
bool success = !JlCompress::extractDir(tempDir.path() + "/latest.zip", dataDir + "/Dalamud").empty();
|
bool success = !JlCompress::extractDir(tempDir.path() + "/latest.zip", dalamudDir.absoluteFilePath(m_profile.dalamudChannelName())).empty();
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// TODO: handle failure here
|
// TODO: handle failure here
|
||||||
|
@ -135,14 +145,14 @@ void AssetUpdater::beginInstall()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsRuntimeInstall) {
|
if (needsRuntimeInstall) {
|
||||||
bool success = !JlCompress::extractDir(tempDir.path() + "/dotnet-core.zip", dataDir + "/DalamudRuntime").empty();
|
bool success = !JlCompress::extractDir(tempDir.path() + "/dotnet-core.zip", dalamudRuntimeDir.absolutePath()).empty();
|
||||||
|
|
||||||
success |= !JlCompress::extractDir(tempDir.path() + "/dotnet-desktop.zip", dataDir + "/DalamudRuntime").empty();
|
success |= !JlCompress::extractDir(tempDir.path() + "/dotnet-desktop.zip", dalamudRuntimeDir.absolutePath()).empty();
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qInfo() << "Failed to install dotnet!";
|
qInfo() << "Failed to install dotnet!";
|
||||||
} else {
|
} else {
|
||||||
QFile file(dataDir + "/DalamudRuntime/runtime.ver");
|
QFile file(dalamudRuntimeDir.absoluteFilePath("runtime.ver"));
|
||||||
file.open(QIODevice::WriteOnly | QIODevice::Text);
|
file.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
file.write(remoteRuntimeVersion.toUtf8());
|
file.write(remoteRuntimeVersion.toUtf8());
|
||||||
file.close();
|
file.close();
|
||||||
|
@ -161,7 +171,7 @@ void AssetUpdater::checkIfDalamudAssetsDone()
|
||||||
|
|
||||||
m_profile.dalamudAssetVersion = remoteDalamudAssetVersion;
|
m_profile.dalamudAssetVersion = remoteDalamudAssetVersion;
|
||||||
|
|
||||||
QFile file(dataDir + "/DalamudAssets/" + "asset.ver");
|
QFile file(dalamudAssetDir.absoluteFilePath("asset.ver"));
|
||||||
file.open(QIODevice::WriteOnly | QIODevice::Text);
|
file.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
file.write(QString::number(remoteDalamudAssetVersion).toUtf8());
|
file.write(QString::number(remoteDalamudAssetVersion).toUtf8());
|
||||||
file.close();
|
file.close();
|
||||||
|
@ -294,21 +304,15 @@ void AssetUpdater::checkIfCheckingIsDone()
|
||||||
auto assetReply = launcher.mgr->get(assetRequest);
|
auto assetReply = launcher.mgr->get(assetRequest);
|
||||||
|
|
||||||
connect(assetReply, &QNetworkReply::finished, [this, assetReply, assetObject = assetObject.toObject()] {
|
connect(assetReply, &QNetworkReply::finished, [this, assetReply, assetObject = assetObject.toObject()] {
|
||||||
if (!QDir().exists(dataDir + "/DalamudAssets"))
|
|
||||||
QDir().mkdir(dataDir + "/DalamudAssets");
|
|
||||||
|
|
||||||
const QString fileName = assetObject["FileName"].toString();
|
const QString fileName = assetObject["FileName"].toString();
|
||||||
const QList<QString> dirPath = fileName.left(fileName.lastIndexOf("/")).split('/');
|
const QString dirPath = fileName.left(fileName.lastIndexOf("/"));
|
||||||
|
|
||||||
QString build = dataDir + "/DalamudAssets/";
|
const QString path = dalamudAssetDir.absoluteFilePath(dirPath);
|
||||||
for (const auto &dir : dirPath) {
|
|
||||||
if (!QDir().exists(build + dir))
|
|
||||||
QDir().mkdir(build + dir);
|
|
||||||
|
|
||||||
build += dir + "/";
|
if (!QDir().exists(path))
|
||||||
}
|
QDir().mkpath(path);
|
||||||
|
|
||||||
QFile file(dataDir + "/DalamudAssets/" + assetObject["FileName"].toString());
|
QFile file(dalamudAssetDir.absoluteFilePath(assetObject["FileName"].toString()));
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
file.write(assetReply->readAll());
|
file.write(assetReply->readAll());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "launchercore.h"
|
#include "launchercore.h"
|
||||||
#include "sapphirelauncher.h"
|
#include "sapphirelauncher.h"
|
||||||
#include "squarelauncher.h"
|
#include "squarelauncher.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
#ifdef ENABLE_WATCHDOG
|
#ifdef ENABLE_WATCHDOG
|
||||||
#include "watchdog.h"
|
#include "watchdog.h"
|
||||||
|
@ -103,11 +104,23 @@ void LauncherCore::beginVanillaGame(const QString &gameExecutablePath, const Pro
|
||||||
|
|
||||||
void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, const Profile &profile, const LoginAuth &auth)
|
void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, const Profile &profile, const LoginAuth &auth)
|
||||||
{
|
{
|
||||||
QString gamePath = gameExecutablePath;
|
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
gamePath = "Z:" + gamePath.replace('/', '\\');
|
const QDir configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||||
|
const QDir stateDir = Utility::stateDirectory();
|
||||||
|
|
||||||
QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
const QString logDir = stateDir.absoluteFilePath("logs");
|
||||||
dataDir = "Z:" + dataDir.replace('/', '\\');
|
|
||||||
|
if (!QDir().exists(logDir))
|
||||||
|
QDir().mkpath(logDir);
|
||||||
|
|
||||||
|
const QDir dalamudDir = dataDir.absoluteFilePath("dalamud");
|
||||||
|
const QDir dalamudRuntimeDir = dalamudDir.absoluteFilePath("runtime");
|
||||||
|
const QDir dalamudAssetDir = dalamudDir.absoluteFilePath("assets");
|
||||||
|
const QDir dalamudConfigPath = configDir.absoluteFilePath("dalamud-config.json");
|
||||||
|
const QDir dalamudPluginDir = dalamudDir.absoluteFilePath("plugins");
|
||||||
|
|
||||||
|
const QDir dalamudInstallDir = dalamudDir.absoluteFilePath(profile.dalamudChannelName());
|
||||||
|
const QString dalamudInjector = dalamudInstallDir.absoluteFilePath("Dalamud.Injector.exe");
|
||||||
|
|
||||||
auto dalamudProcess = new QProcess(this);
|
auto dalamudProcess = new QProcess(this);
|
||||||
connect(dalamudProcess, qOverload<int>(&QProcess::finished), this, [this](int exitCode) {
|
connect(dalamudProcess, qOverload<int>(&QProcess::finished), this, [this](int exitCode) {
|
||||||
|
@ -116,7 +129,7 @@ void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, const Pro
|
||||||
});
|
});
|
||||||
|
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
env.insert("DALAMUD_RUNTIME", dataDir + "\\DalamudRuntime");
|
env.insert("DALAMUD_RUNTIME", Utility::toWindowsPath(dalamudRuntimeDir));
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
||||||
env.insert("XL_WINEONLINUX", "true");
|
env.insert("XL_WINEONLINUX", "true");
|
||||||
|
@ -127,16 +140,17 @@ void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, const Pro
|
||||||
|
|
||||||
launchExecutable(profile,
|
launchExecutable(profile,
|
||||||
dalamudProcess,
|
dalamudProcess,
|
||||||
{dataDir + "/Dalamud/" + "Dalamud.Injector.exe",
|
{Utility::toWindowsPath(dalamudInjector),
|
||||||
"launch",
|
"launch",
|
||||||
"-m",
|
"-m",
|
||||||
"inject",
|
"inject",
|
||||||
"--game=" + gamePath,
|
"--game=" + Utility::toWindowsPath(gameExecutablePath),
|
||||||
"--dalamud-configuration-path=" + dataDir + "\\dalamudConfig.json",
|
"--dalamud-working-directory=" + Utility::toWindowsPath(dalamudDir),
|
||||||
"--dalamud-plugin-directory=" + dataDir + "\\installedPlugins",
|
"--dalamud-configuration-path=" + Utility::toWindowsPath(dalamudConfigPath),
|
||||||
"--dalamud-asset-directory=" + dataDir + "\\DalamudAssets",
|
"--dalamud-plugin-directory=" + Utility::toWindowsPath(dalamudPluginDir),
|
||||||
|
"--dalamud-asset-directory=" + Utility::toWindowsPath(dalamudAssetDir),
|
||||||
"--dalamud-client-language=" + QString::number(profile.language()),
|
"--dalamud-client-language=" + QString::number(profile.language()),
|
||||||
"--logpath=" + dataDir,
|
"--logpath=" + Utility::toWindowsPath(logDir),
|
||||||
"--",
|
"--",
|
||||||
args},
|
args},
|
||||||
true,
|
true,
|
||||||
|
@ -158,6 +172,12 @@ QString LauncherCore::getGameArgs(const Profile &profile, const LoginAuth &auth)
|
||||||
gameArgs.push_back({"SYS.Region", QString::number(auth.region)});
|
gameArgs.push_back({"SYS.Region", QString::number(auth.region)});
|
||||||
gameArgs.push_back({"language", QString::number(profile.language())});
|
gameArgs.push_back({"language", QString::number(profile.language())});
|
||||||
gameArgs.push_back({"ver", profile.repositories.repositories[0].version});
|
gameArgs.push_back({"ver", profile.repositories.repositories[0].version});
|
||||||
|
gameArgs.push_back({"UserPath", Utility::toWindowsPath(profile.account()->getConfigDir().absolutePath())});
|
||||||
|
|
||||||
|
// FIXME: this should belong somewhere else...
|
||||||
|
if (!QDir().exists(profile.account()->getConfigDir().absolutePath())) {
|
||||||
|
QDir().mkpath(profile.account()->getConfigDir().absolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
if (!auth.lobbyhost.isEmpty()) {
|
if (!auth.lobbyhost.isEmpty()) {
|
||||||
gameArgs.push_back({"DEV.GMServerHost", auth.frontierHost});
|
gameArgs.push_back({"DEV.GMServerHost", auth.frontierHost});
|
||||||
|
@ -431,6 +451,20 @@ void LauncherCore::setShowNews(const bool value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LauncherCore::keepPatches() const
|
||||||
|
{
|
||||||
|
return Config::keepPatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LauncherCore::setKeepPatches(const bool value)
|
||||||
|
{
|
||||||
|
if (value != Config::keepPatches()) {
|
||||||
|
Config::setKeepPatches(value);
|
||||||
|
Config::self()->save();
|
||||||
|
Q_EMIT keepPatchesChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LauncherCore::refreshNews()
|
void LauncherCore::refreshNews()
|
||||||
{
|
{
|
||||||
QUrlQuery query;
|
QUrlQuery query;
|
||||||
|
@ -524,33 +558,7 @@ void LauncherCore::openOfficialLauncher(Profile *profile)
|
||||||
executeArg = executeArg.arg(dateTime.time().hour(), 2, 10, QLatin1Char('0'));
|
executeArg = executeArg.arg(dateTime.time().hour(), 2, 10, QLatin1Char('0'));
|
||||||
executeArg = executeArg.arg(dateTime.time().minute(), 2, 10, QLatin1Char('0'));
|
executeArg = executeArg.arg(dateTime.time().minute(), 2, 10, QLatin1Char('0'));
|
||||||
|
|
||||||
QList<Argument> arguments;
|
QList<Argument> arguments{{"ExecuteArg", executeArg}, {"UserPath", Utility::toWindowsPath(profile->account()->getConfigDir().absolutePath())}};
|
||||||
arguments.push_back({"ExecuteArg", executeArg});
|
|
||||||
|
|
||||||
// find user path
|
|
||||||
QString userPath;
|
|
||||||
|
|
||||||
// TODO: don't put this here
|
|
||||||
QString searchDir;
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
|
||||||
searchDir = profile->winePrefixPath() + "/drive_c/users";
|
|
||||||
#else
|
|
||||||
searchDir = "C:/Users";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QDirIterator it(searchDir);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
QString dir = it.next();
|
|
||||||
QFileInfo fi(dir);
|
|
||||||
QString fileName = fi.fileName();
|
|
||||||
|
|
||||||
// FIXME: is there no easier way to filter out these in Qt?
|
|
||||||
if (fi.fileName() != "Public" && fi.fileName() != "." && fi.fileName() != "..") {
|
|
||||||
userPath = fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arguments.push_back({"UserPath", QString(R"(C:\Users\%1\Documents\My Games\FINAL FANTASY XIV - A Realm Reborn)").arg(userPath)});
|
|
||||||
|
|
||||||
const QString argFormat = " /%1 =%2";
|
const QString argFormat = " /%1 =%2";
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ Patcher::Patcher(LauncherCore &launcher, QString baseDirectory, BootData *boot_d
|
||||||
, boot_data(boot_data)
|
, boot_data(boot_data)
|
||||||
, m_launcher(launcher)
|
, m_launcher(launcher)
|
||||||
{
|
{
|
||||||
|
setupDirectories();
|
||||||
|
|
||||||
Q_EMIT m_launcher.stageChanged(i18n("Checking the FINAL FANTASY XIV Updater/Launcher version."));
|
Q_EMIT m_launcher.stageChanged(i18n("Checking the FINAL FANTASY XIV Updater/Launcher version."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +32,8 @@ Patcher::Patcher(LauncherCore &launcher, QString baseDirectory, GameData *game_d
|
||||||
, game_data(game_data)
|
, game_data(game_data)
|
||||||
, m_launcher(launcher)
|
, m_launcher(launcher)
|
||||||
{
|
{
|
||||||
|
setupDirectories();
|
||||||
|
|
||||||
Q_EMIT m_launcher.stageChanged(i18n("Checking the FINAL FANTASY XIV Game version."));
|
Q_EMIT m_launcher.stageChanged(i18n("Checking the FINAL FANTASY XIV Game version."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,18 +69,18 @@ void Patcher::processPatchList(QNetworkAccessManager &mgr, const QString &patchL
|
||||||
const QString name = version;
|
const QString name = version;
|
||||||
const QStringList hashes = patchParts.size() == 9 ? (patchParts[7].split(',')) : QStringList();
|
const QStringList hashes = patchParts.size() == 9 ? (patchParts[7].split(',')) : QStringList();
|
||||||
const QString url = patchParts[patchParts.size() == 9 ? 8 : 5];
|
const QString url = patchParts[patchParts.size() == 9 ? 8 : 5];
|
||||||
|
const QString filename = QStringLiteral("%1.patch").arg(name);
|
||||||
qDebug() << "Parsed patch name: " << name;
|
|
||||||
|
|
||||||
auto url_parts = url.split('/');
|
auto url_parts = url.split('/');
|
||||||
const QString repository = url_parts[url_parts.size() - 3];
|
const QString repository = url_parts[url_parts.size() - 3];
|
||||||
|
|
||||||
const QString patchesDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/patches/" + repository;
|
const QDir repositoryDir = patchesDir.absoluteFilePath(repository);
|
||||||
|
|
||||||
if (!QDir().exists(patchesDir))
|
if (!QDir().exists(repositoryDir.absolutePath()))
|
||||||
QDir().mkpath(patchesDir);
|
QDir().mkpath(repositoryDir.absolutePath());
|
||||||
|
|
||||||
if (!QFile::exists(patchesDir + "/" + name + ".patch")) {
|
const QString patchPath = repositoryDir.absoluteFilePath(filename);
|
||||||
|
if (!QFile::exists(patchPath)) {
|
||||||
qDebug() << "Need to download " + name;
|
qDebug() << "Need to download " + name;
|
||||||
|
|
||||||
QNetworkRequest patchRequest(url);
|
QNetworkRequest patchRequest(url);
|
||||||
|
@ -95,15 +99,13 @@ void Patcher::processPatchList(QNetworkAccessManager &mgr, const QString &patchL
|
||||||
|
|
||||||
connect(patchReply,
|
connect(patchReply,
|
||||||
&QNetworkReply::finished,
|
&QNetworkReply::finished,
|
||||||
[this, ourIndex, patchesDir, name, patchReply, repository, version, hashes, hashBlockSize, length] {
|
[this, ourIndex, patchPath, name, patchReply, repository, version, hashes, hashBlockSize, length] {
|
||||||
QFile file(patchesDir + "/" + name + ".patch");
|
QFile file(patchPath);
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
file.write(patchReply->readAll());
|
file.write(patchReply->readAll());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
auto patch_path = patchesDir + "/" + name + ".patch";
|
patchQueue[ourIndex] = {name, repository, version, patchPath, hashes, hashBlockSize, length};
|
||||||
|
|
||||||
patchQueue[ourIndex] = {name, repository, version, patch_path, hashes, hashBlockSize, length};
|
|
||||||
|
|
||||||
remainingPatches--;
|
remainingPatches--;
|
||||||
checkIfDone();
|
checkIfDone();
|
||||||
|
@ -111,7 +113,7 @@ void Patcher::processPatchList(QNetworkAccessManager &mgr, const QString &patchL
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Found existing patch: " << name;
|
qDebug() << "Found existing patch: " << name;
|
||||||
|
|
||||||
patchQueue[ourIndex] = {name, repository, version, patchesDir + "/" + name + ".patch", hashes, hashBlockSize, length};
|
patchQueue[ourIndex] = {name, repository, version, patchPath, hashes, hashBlockSize, length};
|
||||||
|
|
||||||
remainingPatches--;
|
remainingPatches--;
|
||||||
checkIfDone();
|
checkIfDone();
|
||||||
|
@ -190,3 +192,15 @@ void Patcher::processPatch(const QueuedPatch &patch)
|
||||||
verFile.write(patch.version.toUtf8());
|
verFile.write(patch.version.toUtf8());
|
||||||
verFile.close();
|
verFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Patcher::setupDirectories()
|
||||||
|
{
|
||||||
|
QDir dataDir;
|
||||||
|
if (m_launcher.keepPatches()) {
|
||||||
|
dataDir.setPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||||
|
} else {
|
||||||
|
dataDir.setPath(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
patchesDir.setPath(dataDir.absoluteFilePath("patches"));
|
||||||
|
}
|
||||||
|
|
|
@ -498,3 +498,17 @@ QString Profile::wineVersionText() const
|
||||||
return m_wineVersion;
|
return m_wineVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Profile::dalamudChannelName() const
|
||||||
|
{
|
||||||
|
switch (dalamudChannel()) {
|
||||||
|
case DalamudChannel::Stable:
|
||||||
|
return QStringLiteral("stable");
|
||||||
|
case DalamudChannel::Staging:
|
||||||
|
return QStringLiteral("staging");
|
||||||
|
case DalamudChannel::Net5:
|
||||||
|
return QStringLiteral("net5");
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ Profile *ProfileManager::addProfile()
|
||||||
|
|
||||||
newProfile->readWineInfo();
|
newProfile->readWineInfo();
|
||||||
|
|
||||||
newProfile->setGamePath(getDefaultGamePath());
|
|
||||||
newProfile->setWinePrefixPath(getDefaultWinePrefixPath());
|
newProfile->setWinePrefixPath(getDefaultWinePrefixPath());
|
||||||
|
|
||||||
insertProfile(newProfile);
|
insertProfile(newProfile);
|
||||||
|
@ -68,7 +67,7 @@ QString ProfileManager::getDefaultWinePrefixPath()
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ProfileManager::getDefaultGamePath()
|
QString ProfileManager::getDefaultGamePath(const QString &uuid)
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
return "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn";
|
return "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn";
|
||||||
|
@ -81,8 +80,9 @@ QString ProfileManager::getDefaultGamePath()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
const QString appData = QStandardPaths::standardLocations(QStandardPaths::StandardLocation::AppDataLocation)[0];
|
const QDir appData = QStandardPaths::standardLocations(QStandardPaths::StandardLocation::AppDataLocation)[0];
|
||||||
return QStringLiteral("%1/game").arg(appData);
|
const QDir gameDir = appData.absoluteFilePath("game");
|
||||||
|
return gameDir.absoluteFilePath(uuid);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
launcher/src/utility.cpp
Normal file
20
launcher/src/utility.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
QDir Utility::stateDirectory()
|
||||||
|
{
|
||||||
|
if (qEnvironmentVariableIsSet("XDG_STATE_HOME")) {
|
||||||
|
return qEnvironmentVariable("XDG_STATE_HOME");
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDir homeDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0];
|
||||||
|
const QDir localDir = homeDir.absoluteFilePath(".local");
|
||||||
|
const QDir stateDir = localDir.absoluteFilePath("state");
|
||||||
|
return stateDir.absoluteFilePath("astra");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Utility::toWindowsPath(const QDir &dir)
|
||||||
|
{
|
||||||
|
return "Z:" + dir.absolutePath().replace('/', '\\');
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ Kirigami.ScrollablePage {
|
||||||
MobileForm.FormCheckDelegate {
|
MobileForm.FormCheckDelegate {
|
||||||
text: i18n("Keep Patches")
|
text: i18n("Keep Patches")
|
||||||
description: i18n("Do not delete patches after they're used. Astra will not redownload patch data, if found.")
|
description: i18n("Do not delete patches after they're used. Astra will not redownload patch data, if found.")
|
||||||
|
checked: LauncherCore.keepPatches
|
||||||
|
onCheckedChanged: LauncherCore.keepPatches = checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue