2026-08-27 09:21:51 +03:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
|
|
#include "modloader.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <QObject>
|
|
|
|
|
|
#include <QString>
|
|
|
|
|
|
#include <QStringList>
|
|
|
|
|
|
|
2026-08-28 00:13:59 +03:00
|
|
|
|
class QFile;
|
2026-08-27 09:21:51 +03:00
|
|
|
|
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-режиме
|
2026-08-28 00:13:59 +03:00
|
|
|
|
// и смотрим, какой профиль появился в versions. Процессу установщика при этом
|
|
|
|
|
|
// подсовывается эталонный zlib — см. ZlibReference.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Оба пути начинаются одинаково: пока ванильная версия не скачана целиком,
|
|
|
|
|
|
// ставить лоадер некуда, поэтому ensureBaseVersion стоит перед обеими ветками.
|
2026-08-27 09:21:51 +03:00
|
|
|
|
//
|
|
|
|
|
|
// Набор геттеров повторяет 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);
|
2026-08-28 00:13:59 +03:00
|
|
|
|
QStringList versionsAddedByInstaller() const;
|
|
|
|
|
|
void removeVersionsAddedByInstaller();
|
|
|
|
|
|
QString installerFailureHint() const;
|
|
|
|
|
|
void appendInstallerLog(const QString &line);
|
|
|
|
|
|
void closeInstallerLog();
|
2026-08-27 09:21:51 +03:00
|
|
|
|
|
|
|
|
|
|
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;
|
2026-08-28 00:13:59 +03:00
|
|
|
|
// Установщик успел отработать — значит, за появившиеся в versions папки
|
|
|
|
|
|
// отвечаем мы и при неудаче их надо убрать.
|
|
|
|
|
|
bool m_installerStarted = false;
|
|
|
|
|
|
// В системе zlib-ng, а подменить его было нечем: почти наверняка причина
|
|
|
|
|
|
// расхождения sha1, о которой стоит сказать прямым текстом.
|
|
|
|
|
|
bool m_zlibNgUnpatched = false;
|
|
|
|
|
|
QFile *m_installerLogFile = nullptr;
|
|
|
|
|
|
QString m_installerLogPath;
|
2026-08-27 09:21:51 +03:00
|
|
|
|
|
|
|
|
|
|
// Ждём, пока VersionInstaller докачает то, что установщик не положил.
|
|
|
|
|
|
QString m_awaitingVersionId;
|
|
|
|
|
|
|
|
|
|
|
|
bool m_running = false;
|
|
|
|
|
|
bool m_canceling = false;
|
|
|
|
|
|
};
|