125 lines
5.2 KiB
C++
125 lines
5.2 KiB
C++
#pragma once
|
||
|
||
#include "modloader.h"
|
||
|
||
#include <QObject>
|
||
#include <QString>
|
||
#include <QStringList>
|
||
|
||
class QFile;
|
||
class QNetworkAccessManager;
|
||
class QNetworkReply;
|
||
class QProcess;
|
||
class ModLoaderVersionService;
|
||
class VersionInstaller;
|
||
|
||
// Установка модлоадера в .minecraft. Два разных пути под одним фасадом:
|
||
//
|
||
// * Fabric и Quilt отдают готовое описание версии — кладём его в
|
||
// versions/<id>/<id>.json и передаём дальше VersionInstaller, который по
|
||
// inheritsFrom сам поставит ванильную версию и библиотеки лоадера.
|
||
//
|
||
// * Forge и NeoForge так не умеют: их установка — это патч клиентского jar,
|
||
// поэтому запускаем официальный installer.jar найденной Java в headless-режиме
|
||
// и смотрим, какой профиль появился в versions. Процессу установщика при этом
|
||
// подсовывается эталонный zlib — см. ZlibReference.
|
||
//
|
||
// Оба пути начинаются одинаково: пока ванильная версия не скачана целиком,
|
||
// ставить лоадер некуда, поэтому ensureBaseVersion стоит перед обеими ветками.
|
||
//
|
||
// Набор геттеров повторяет VersionInstaller: панель загрузки в интерфейсе
|
||
// читает их одинаково, независимо от того, кто сейчас работает.
|
||
class ModLoaderInstaller : public QObject
|
||
{
|
||
Q_OBJECT
|
||
|
||
public:
|
||
ModLoaderInstaller(ModLoaderVersionService *meta,
|
||
VersionInstaller *versionInstaller,
|
||
QObject *parent = nullptr);
|
||
~ModLoaderInstaller() override;
|
||
|
||
bool isRunning() const { return m_running; }
|
||
QString label() const { return m_label; }
|
||
QString stage() const { return m_stage; }
|
||
QString currentFile() const { return m_currentFile; }
|
||
|
||
qint64 bytesDone() const { return m_bytesDone; }
|
||
qint64 bytesTotal() const { return m_bytesTotal; }
|
||
double fraction() const; // 0..1, либо -1 пока итог неизвестен
|
||
|
||
void install(const QString &gameDir,
|
||
ModLoader loader,
|
||
const QString &gameVersion,
|
||
const QString &loaderVersion,
|
||
const QString &javaPreference);
|
||
void cancel();
|
||
|
||
signals:
|
||
void started(const QString &label);
|
||
void progressChanged();
|
||
void finished(const QString &loaderKey,
|
||
const QString &gameVersion,
|
||
const QString &loaderVersion,
|
||
const QString &producedVersionId);
|
||
void failed(const QString &label, const QString &message);
|
||
void canceled(const QString &label);
|
||
void log(const QString &line);
|
||
|
||
private:
|
||
void beginFabricLike();
|
||
void beginInstallerJar();
|
||
void ensureBaseVersion(std::function<void()> next);
|
||
void downloadInstaller(const QUrl &url, std::function<void(const QString &)> next);
|
||
bool writeLauncherProfilesStub();
|
||
void runInstaller(const QString &installerPath);
|
||
void handleInstallerFinished(int exitCode, bool crashed);
|
||
QStringList versionsAddedByInstaller() const;
|
||
void removeVersionsAddedByInstaller();
|
||
QString installerFailureHint() const;
|
||
void appendInstallerLog(const QString &line);
|
||
void closeInstallerLog();
|
||
|
||
void handOffToVersionInstaller(const QString &versionId);
|
||
void setStage(const QString &stage);
|
||
void reset();
|
||
void fail(const QString &message);
|
||
|
||
ModLoaderVersionService *m_meta;
|
||
VersionInstaller *m_versionInstaller;
|
||
QNetworkAccessManager *m_network;
|
||
QNetworkReply *m_reply = nullptr;
|
||
QProcess *m_process = nullptr;
|
||
|
||
QString m_gameDir;
|
||
ModLoader m_loader = ModLoader::Fabric;
|
||
QString m_gameVersion;
|
||
QString m_loaderVersion;
|
||
QString m_javaPreference;
|
||
QString m_label;
|
||
|
||
QString m_stage;
|
||
QString m_currentFile;
|
||
qint64 m_bytesDone = 0;
|
||
qint64 m_bytesTotal = 0;
|
||
|
||
// Профили, которые были в versions до запуска installer.jar: новый ищем
|
||
// разницей, а не угадыванием строки — id у Forge разные по эпохам.
|
||
QStringList m_versionsBefore;
|
||
QStringList m_installerLog;
|
||
// Установщик успел отработать — значит, за появившиеся в versions папки
|
||
// отвечаем мы и при неудаче их надо убрать.
|
||
bool m_installerStarted = false;
|
||
// В системе zlib-ng, а подменить его было нечем: почти наверняка причина
|
||
// расхождения sha1, о которой стоит сказать прямым текстом.
|
||
bool m_zlibNgUnpatched = false;
|
||
QFile *m_installerLogFile = nullptr;
|
||
QString m_installerLogPath;
|
||
|
||
// Ждём, пока VersionInstaller докачает то, что установщик не положил.
|
||
QString m_awaitingVersionId;
|
||
|
||
bool m_running = false;
|
||
bool m_canceling = false;
|
||
};
|