#pragma once #include "modloader.h" #include #include #include class QFile; class QNetworkAccessManager; class QNetworkReply; class QProcess; class ModLoaderVersionService; class VersionInstaller; // Установка модлоадера в .minecraft. Два разных пути под одним фасадом: // // * Fabric и Quilt отдают готовое описание версии — кладём его в // versions//.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 next); void downloadInstaller(const QUrl &url, std::function 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; };