Files
minecraft-launcher/versioninstaller.h
T

148 lines
5.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "minecraftversion.h"
#include <QCryptographicHash>
#include <QJsonObject>
#include <QList>
#include <QObject>
#include <QPair>
#include <QQueue>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <memory>
class QNetworkAccessManager;
class QNetworkReply;
class QSaveFile;
class QTimer;
class VersionManifestService;
// Один файл, который нужно положить в .minecraft.
struct DownloadTask
{
enum Kind { ClientJar, Library, AssetIndex, AssetObject, LoggingConfig };
Kind kind = ClientJar;
QUrl url;
QString path; // абсолютный путь назначения
QString sha1; // пусто — не проверяем
qint64 size = 0; // 0 — размер неизвестен
QString label; // что показать в панели прогресса
int attempts = 0;
};
// Файл в процессе скачивания. Пишем потоком: держать десятки мегабайт в памяти
// незачем, а нескольких параллельных загрузок хватило бы на сотни.
struct ActiveDownload
{
DownloadTask task;
QNetworkReply *reply = nullptr;
std::unique_ptr<QSaveFile> file;
QCryptographicHash hash{QCryptographicHash::Sha1};
qint64 received = 0;
};
// Фоновая установка версии в .minecraft: описание версии, клиентский jar,
// библиотеки, индекс ресурсов и сами ресурсы. Одна версия за раз, остальные
// ждут в очереди. Всё в GUI-потоке, как и остальной сетевой код лаунчера.
class VersionInstaller : public QObject
{
Q_OBJECT
public:
explicit VersionInstaller(VersionManifestService *manifest, QObject *parent = nullptr);
~VersionInstaller() override;
bool isRunning() const { return m_running; }
QString versionId() const { return m_versionId; }
QString stage() const { return m_stage; }
QString currentFile() const { return m_currentLabel; }
qint64 bytesDone() const;
qint64 bytesTotal() const { return m_bytesTotal; }
double fraction() const; // 0..1, либо -1 пока итог неизвестен
void install(const QString &gameDir, const QString &versionId);
bool isQueued(const QString &versionId) const;
void cancel();
signals:
void started(const QString &versionId);
void progressChanged(); // не чаще десяти раз в секунду
void finished(const QString &versionId);
void failed(const QString &versionId, const QString &message);
void canceled(const QString &versionId);
private:
void startNext();
void resolveManifestEntry();
void fetchVersionJson(const QUrl &url, const QString &expectedSha1);
bool prepareTasks();
void enqueue(DownloadTask task);
void schedulePump();
void pump();
void startTask(DownloadTask task);
void handleReplyFinished(const std::shared_ptr<ActiveDownload> &context);
bool retryOrFail(DownloadTask task, const QString &reason);
void expandAssetIndex(const QString &indexPath);
void afterDownloads();
void startLegacyCopy();
void legacyTick();
void complete();
void setStage(const QString &stage);
void scheduleProgress();
void flushProgress();
void resetInstallState();
void failInstall(const QString &message);
void abandonCurrent(); // версия уступает место родителю, без сигналов
void finalizeCancel();
VersionManifestService *m_manifest;
QNetworkAccessManager *m_network;
QQueue<QPair<QString, QString>> m_pendingInstalls; // {gameDir, versionId}
QString m_gameDir;
QString m_versionId;
QJsonObject m_versionJson;
MinecraftVersion m_version;
QQueue<DownloadTask> m_queue;
QList<std::shared_ptr<ActiveDownload>> m_active;
QStringList m_warnings;
qint64 m_bytesSettled = 0;
qint64 m_bytesTotal = 0;
qint64 m_assetsDeclaredTotal = 0;
bool m_running = false;
bool m_canceling = false;
bool m_pumpScheduled = false;
// Существующие файлы сверяются только по размеру: перехеширование сотен
// мегабайт при каждом добавлении версии дороже, чем риск битого файла.
// Флаг оставлен под будущую кнопку «проверить файлы».
bool m_verifyExisting = false;
QString m_stage;
QString m_currentLabel;
QTimer *m_progressTimer;
bool m_progressDirty = false;
// Ресурсы до 1.6 игра ищет не в assets/objects, а в плоской папке.
QJsonObject m_assetObjects;
bool m_assetsVirtual = false;
bool m_assetsMapToResources = false;
QList<QPair<QString, QString>> m_legacyCopies; // {источник, назначение}
int m_legacyIndex = 0;
QTimer *m_legacyTimer;
int m_inheritDepth = 0;
};