mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-20 11:47:46 +00:00
Improve patching experience further
Now there is more visible and consistent information such as the number of patches and how far you're into the patching process. It's harder to close or quit the window while patching to prevent errors, and installing patches no longer freezes the window. And fixes an issue where the boot component would never properly update.
This commit is contained in:
parent
af407cbf7c
commit
81bd81e1b6
7 changed files with 110 additions and 14 deletions
|
@ -105,6 +105,7 @@ public:
|
|||
[[nodiscard]] bool isLoadingFinished() const;
|
||||
[[nodiscard]] bool isSteam() const;
|
||||
[[nodiscard]] bool isSteamDeck() const;
|
||||
[[nodiscard]] Q_INVOKABLE bool isPatching() const;
|
||||
|
||||
[[nodiscard]] QNetworkAccessManager *mgr();
|
||||
[[nodiscard]] LauncherSettings *settings();
|
||||
|
@ -112,19 +113,24 @@ public:
|
|||
[[nodiscard]] AccountManager *accountManager();
|
||||
[[nodiscard]] Headline *headline() const;
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void loadingFinished();
|
||||
void successfulLaunch();
|
||||
void gameClosed();
|
||||
void loginError(QString message);
|
||||
void dalamudError(QString message);
|
||||
void stageChanged(QString message);
|
||||
void stageChanged(QString message, QString explanation = {});
|
||||
void stageIndeterminate();
|
||||
void stageDeterminate(int min, int max, int value);
|
||||
void newsChanged();
|
||||
void currentProfileChanged();
|
||||
void autoLoginProfileChanged();
|
||||
|
||||
protected:
|
||||
friend class Patcher;
|
||||
|
||||
bool m_isPatching = false;
|
||||
|
||||
private:
|
||||
QCoro::Task<> beginLogin(LoginInformation &info);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "patchlist.h"
|
||||
#include <QDir>
|
||||
#include <QMutex>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QString>
|
||||
#include <physis.hpp>
|
||||
|
@ -21,6 +22,7 @@ class Patcher : public QObject
|
|||
public:
|
||||
Patcher(LauncherCore &launcher, const QString &baseDirectory, GameData &gameData, QObject *parent = nullptr);
|
||||
Patcher(LauncherCore &launcher, const QString &baseDirectory, BootData &bootData, QObject *parent = nullptr);
|
||||
~Patcher() override;
|
||||
|
||||
QCoro::Task<bool> patch(const PatchList &patchList);
|
||||
|
||||
|
@ -40,6 +42,9 @@ private:
|
|||
long length;
|
||||
bool isBoot;
|
||||
|
||||
long bytesDownloaded;
|
||||
bool downloaded = false;
|
||||
|
||||
[[nodiscard]] QString getVersion() const
|
||||
{
|
||||
if (isBoot) {
|
||||
|
@ -62,4 +67,10 @@ private:
|
|||
int m_remainingPatches = -1;
|
||||
|
||||
LauncherCore &m_launcher;
|
||||
|
||||
QMutex m_finishedPatchesMutex;
|
||||
int m_finishedPatches = 0;
|
||||
|
||||
void updateDownloadProgress(int index, int received);
|
||||
void updateMessage();
|
||||
};
|
||||
|
|
|
@ -224,6 +224,11 @@ bool LauncherCore::isSteamDeck() const
|
|||
}
|
||||
}
|
||||
|
||||
bool LauncherCore::isPatching() const
|
||||
{
|
||||
return m_isPatching;
|
||||
}
|
||||
|
||||
QNetworkAccessManager *LauncherCore::mgr()
|
||||
{
|
||||
return m_mgr;
|
||||
|
|
|
@ -24,9 +24,11 @@ Patcher::Patcher(LauncherCore &launcher, const QString &baseDirectory, BootData
|
|||
, m_bootData(&bootData)
|
||||
, m_launcher(launcher)
|
||||
{
|
||||
m_launcher.m_isPatching = true;
|
||||
|
||||
setupDirectories();
|
||||
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Checking %1 version.", getBaseString()));
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Checking %1 version", getBaseString()));
|
||||
}
|
||||
|
||||
Patcher::Patcher(LauncherCore &launcher, const QString &baseDirectory, GameData &gameData, QObject *parent)
|
||||
|
@ -35,9 +37,16 @@ Patcher::Patcher(LauncherCore &launcher, const QString &baseDirectory, GameData
|
|||
, m_gameData(&gameData)
|
||||
, m_launcher(launcher)
|
||||
{
|
||||
m_launcher.m_isPatching = true;
|
||||
|
||||
setupDirectories();
|
||||
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Checking %1 version.", getBaseString()));
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Checking %1 version", getBaseString()));
|
||||
}
|
||||
|
||||
Patcher::~Patcher()
|
||||
{
|
||||
m_launcher.m_isPatching = false;
|
||||
}
|
||||
|
||||
QCoro::Task<bool> Patcher::patch(const PatchList &patchList)
|
||||
|
@ -47,7 +56,7 @@ QCoro::Task<bool> Patcher::patch(const PatchList &patchList)
|
|||
}
|
||||
|
||||
Q_EMIT m_launcher.stageIndeterminate();
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Checking %1 version.", getBaseString()));
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Updating %1", getBaseString()));
|
||||
|
||||
m_remainingPatches = patchList.patches().size();
|
||||
m_patchQueue.resize(m_remainingPatches);
|
||||
|
@ -86,18 +95,27 @@ QCoro::Task<bool> Patcher::patch(const PatchList &patchList)
|
|||
|
||||
auto patchReply = m_launcher.mgr()->get(patchRequest);
|
||||
|
||||
connect(patchReply, &QNetworkReply::downloadProgress, this, [this, queuedPatch](int received, int total) {
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Updating %1.\nDownloading %2", getBaseString(), queuedPatch.getVersion()));
|
||||
Q_EMIT m_launcher.stageDeterminate(0, total, received);
|
||||
connect(patchReply, &QNetworkReply::downloadProgress, this, [this, ourIndex, queuedPatch](int received, int total) {
|
||||
updateDownloadProgress(ourIndex, received);
|
||||
});
|
||||
|
||||
synchronizer.addFuture(QtFuture::connect(patchReply, &QNetworkReply::finished).then([patchPath, patchReply] {
|
||||
synchronizer.addFuture(QtFuture::connect(patchReply, &QNetworkReply::finished).then([this, ourIndex, patchPath, patchReply] {
|
||||
qDebug(ASTRA_PATCHER) << "Downloaded to" << patchPath;
|
||||
|
||||
QFile file(patchPath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(patchReply->readAll());
|
||||
file.close();
|
||||
|
||||
QMutexLocker locker(&m_finishedPatchesMutex);
|
||||
m_finishedPatches++;
|
||||
m_patchQueue[ourIndex].downloaded = true;
|
||||
|
||||
updateMessage();
|
||||
}));
|
||||
} else {
|
||||
m_patchQueue[ourIndex].downloaded = true;
|
||||
m_finishedPatches++;
|
||||
qDebug(ASTRA_PATCHER) << "Found existing patch: " << patch.name;
|
||||
}
|
||||
}
|
||||
|
@ -109,10 +127,17 @@ QCoro::Task<bool> Patcher::patch(const PatchList &patchList)
|
|||
// This must happen synchronously
|
||||
size_t i = 0;
|
||||
for (const auto &patch : m_patchQueue) {
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Updating %1.\nInstalling %2", getBaseString(), patch.getVersion()));
|
||||
QString repositoryName = patch.repository;
|
||||
if (repositoryName == QStringLiteral("game")) {
|
||||
repositoryName = QStringLiteral("ffxiv");
|
||||
}
|
||||
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Installing %1 - %2 [%3/%4]", repositoryName, patch.version, i++, m_remainingPatches));
|
||||
Q_EMIT m_launcher.stageDeterminate(0, m_patchQueue.size(), i++);
|
||||
|
||||
processPatch(patch);
|
||||
co_await QtConcurrent::run([this, patch] {
|
||||
processPatch(patch);
|
||||
});
|
||||
}
|
||||
|
||||
co_return true;
|
||||
|
@ -191,3 +216,33 @@ QString Patcher::getBaseString() const
|
|||
return i18n("FINAL FANTASY XIV Game");
|
||||
}
|
||||
}
|
||||
|
||||
void Patcher::updateDownloadProgress(const int index, int received)
|
||||
{
|
||||
QMutexLocker locker(&m_finishedPatchesMutex);
|
||||
|
||||
m_patchQueue[index].bytesDownloaded = received;
|
||||
|
||||
updateMessage();
|
||||
}
|
||||
|
||||
void Patcher::updateMessage()
|
||||
{
|
||||
// Find first not-downloaded patch
|
||||
for (const auto &patch : m_patchQueue) {
|
||||
if (!patch.downloaded) {
|
||||
QString repositoryName = patch.repository;
|
||||
if (repositoryName == QStringLiteral("game")) {
|
||||
repositoryName = QStringLiteral("ffxiv");
|
||||
}
|
||||
|
||||
const float progress = ((float)patch.bytesDownloaded / (float)patch.length) * 100.0f;
|
||||
const QString progressStr = QStringLiteral("%1").arg(progress, 1, 'f', 1, '0');
|
||||
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Downloading %1 - %2 [%3/%4]", repositoryName, patch.version, m_finishedPatches, m_remainingPatches),
|
||||
i18n("%1%", progressStr));
|
||||
Q_EMIT m_launcher.stageDeterminate(0, patch.length, patch.bytesDownloaded);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,12 +86,15 @@ QCoro::Task<> SquareEnixLogin::checkBootUpdates()
|
|||
Q_EMIT m_launcher.stageChanged(i18n("Checking for launcher updates..."));
|
||||
qInfo(ASTRA_LOG) << "Checking for updates to boot components...";
|
||||
|
||||
const QUrlQuery query{{QStringLiteral("time"), QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyy-MM-dd-HH-mm"))}};
|
||||
QString formattedDate = QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyy-MM-dd-HH-mm"));
|
||||
formattedDate[15] = '0';
|
||||
|
||||
const QUrlQuery query{{QStringLiteral("time"), formattedDate}};
|
||||
|
||||
QUrl url;
|
||||
url.setScheme(QStringLiteral("http"));
|
||||
url.setHost(QStringLiteral("patch-bootver.%1").arg(m_launcher.settings()->squareEnixServer()));
|
||||
url.setPath(QStringLiteral("/http/win32/ffxivneo_release_boot/%1").arg(m_info->profile->bootVersion()));
|
||||
url.setPath(QStringLiteral("/http/win32/ffxivneo_release_boot/%1/").arg(m_info->profile->bootVersion()));
|
||||
url.setQuery(query);
|
||||
|
||||
auto request = QNetworkRequest(url);
|
||||
|
|
|
@ -29,6 +29,13 @@ Kirigami.ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
onClosing: (close) => {
|
||||
if (LauncherCore.isPatching()) {
|
||||
applicationWindow().showPassiveNotification(i18n("Please do not quit while patching!"));
|
||||
}
|
||||
close.accepted = !LauncherCore.isPatching();
|
||||
}
|
||||
|
||||
function checkSetup() {
|
||||
if (!LauncherCore.loadingFinished) {
|
||||
return
|
||||
|
|
|
@ -12,6 +12,14 @@ Kirigami.Page {
|
|||
|
||||
title: i18n("Logging in...")
|
||||
|
||||
onBackRequested: (event) => {
|
||||
if (LauncherCore.isPatching()) {
|
||||
// Prevent going back
|
||||
applicationWindow().showPassiveNotification(i18n("Please do not quit while patching!"));
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.LoadingPlaceholder {
|
||||
id: placeholder
|
||||
|
||||
|
@ -48,8 +56,9 @@ Kirigami.Page {
|
|||
Connections {
|
||||
target: LauncherCore
|
||||
|
||||
function onStageChanged(message) {
|
||||
function onStageChanged(message, explanation) {
|
||||
placeholder.text = message
|
||||
placeholder.explanation = explanation
|
||||
}
|
||||
|
||||
function onStageIndeterminate() {
|
||||
|
|
Loading…
Add table
Reference in a new issue