seasonal builds

This commit is contained in:
2026-08-31 00:59:14 +03:00
parent 4689e59b5a
commit c25e071b29
17 changed files with 2312 additions and 18 deletions
+79
View File
@@ -1,6 +1,7 @@
#pragma once
#include "minecraftversion.h"
#include "seasonalbuildservice.h"
#include <QJsonArray>
#include <QJsonDocument>
@@ -20,6 +21,8 @@ class ModLoaderInstaller;
class BuildSwitcher;
class JavaRuntimeService;
class JavaInstaller;
class SeasonalBuildService;
class SeasonalPackDownloader;
class LauncherBackend : public QObject
{
@@ -55,6 +58,15 @@ class LauncherBackend : public QObject
Q_PROPERTY(QVariantList javaCatalog READ javaCatalog NOTIFY javaCatalogChanged)
Q_PROPERTY(bool javaCatalogLoading READ javaCatalogLoading NOTIFY javaCatalogLoadingChanged)
// Готовые сборки с сервера. Строки таблицы уже сведены с локальными
// записями: окно показывает статус, не считая ничего само.
Q_PROPERTY(QVariantList seasonalCatalog READ seasonalCatalog NOTIFY seasonalCatalogChanged)
Q_PROPERTY(bool seasonalCatalogLoading READ seasonalCatalogLoading
NOTIFY seasonalCatalogLoadingChanged)
Q_PROPERTY(QString seasonalCatalogError READ seasonalCatalogError NOTIFY seasonalCatalogChanged)
// Идёт установка сезонной сборки: окно не даёт начать вторую.
Q_PROPERTY(bool seasonalInstalling READ seasonalInstalling NOTIFY seasonalInstallingChanged)
// Одного сигнала на все свойства загрузки достаточно: установщик уже
// ограничивает частоту, а QML всё равно перечитывает их разом.
Q_PROPERTY(bool downloading READ downloading NOTIFY downloadChanged)
@@ -88,6 +100,11 @@ public:
QVariantList javaCatalog() const;
bool javaCatalogLoading() const;
QVariantList seasonalCatalog() const;
bool seasonalCatalogLoading() const;
QString seasonalCatalogError() const;
bool seasonalInstalling() const;
bool downloading() const;
double downloadProgress() const;
QString downloadVersion() const;
@@ -168,6 +185,13 @@ public:
// Минимальная Java для версии игры выбранной сборки; 0 — версия не выбрана.
Q_INVOKABLE int requiredJavaMajor(int buildIndex) const;
// ── Сезонные сборки ─────────────────────────────────────────────────
Q_INVOKABLE void refreshSeasonalCatalog(bool force = false);
// Ставит или обновляет сборку целиком: запись, версия, модлоадер, Java и
// файлы — одной цепочкой.
Q_INVOKABLE void installSeasonalBuild(const QString &seasonalId);
Q_INVOKABLE void cancelSeasonalInstall();
Q_INVOKABLE void openMinecraftFolder();
Q_INVOKABLE void openGameFolder();
@@ -185,8 +209,14 @@ signals:
void catalogLoadingChanged();
void javaCatalogChanged();
void javaCatalogLoadingChanged();
void seasonalCatalogChanged();
void seasonalCatalogLoadingChanged();
void seasonalInstallingChanged();
void downloadChanged();
// Сезонная сборка установлена и активна — можно запускать игру.
void seasonalInstallFinished(const QString &seasonalId, const QString &buildName);
// Сборка Java установлена: окно настроек обновляет подпись, не переоткрываясь.
void javaRuntimeInstalled(const QString &runtimeId);
@@ -215,6 +245,24 @@ private:
QString loader; // "" | forge | fabric | neoforge | quilt
QString loaderVersion; // 47.4.0 | 0.19.3
QString resolvedVersionId; // versions/<id>, который реально запускается
// Сборка приехала с сервера сезонных сборок: id её строки в каталоге и
// установленная ревизия. Пусто — обычная пользовательская сборка.
QString seasonalId;
int seasonalRevision = 0;
};
// Шаг установки сезонной сборки. Порядок жёсткий: Java нужна установщику
// Forge, а раскатывать файлы поверх имеет смысл только когда всё остальное
// на месте.
enum class SeasonStage { Idle, Switching, Java, Loader, Downloading, Applying };
struct SeasonalInstall
{
SeasonStage stage = SeasonStage::Idle;
int buildId = -1;
QString packPath;
// Копия строки каталога на момент старта: обновление списка посреди
// установки не должно менять то, что ставится.
SeasonalBuildEntry entry;
};
void loadData();
@@ -246,6 +294,30 @@ private:
void rebuildCatalog() const;
void invalidateJavaCatalog();
void rebuildJavaCatalog() const;
void invalidateSeasonalCatalog();
void rebuildSeasonalCatalog() const;
// Панель загрузки занята скачиванием пака сезонной сборки.
bool packDownloadShown() const;
// ── Установка сезонной сборки ───────────────────────────────────────
// Каждый шаг либо запускает асинхронную операцию и возвращает true, либо
// решает, что делать нечего, и уступает следующему.
void seasonAdvance();
bool seasonBeginSwitch();
bool seasonBeginJava();
bool seasonBeginLoader();
bool seasonBeginDownload();
bool seasonBeginApply();
// message пусто — о причине уже сообщил тот, кто её обнаружил.
void seasonFail(const QString &message);
void seasonFinish();
int indexOfSeasonalBuild(const QString &seasonalId) const;
// Что принесла установленная ревизия сборки; пусто — сезонных файлов нет.
QStringList seasonalPackEntries(int buildId) const;
// Запоминает раскатанную ревизию: и в builds/<id>/season.json, и в записи
// сборки. Вызывается и после доигрывания прерванной установки.
void recordSeasonalPack(int buildId, const QJsonObject &note, const QStringList &entries);
QUrl seasonalBaseUrl() const;
// Панель загрузки занята установкой Java, а не версии или модлоадера.
bool javaDownloadShown() const;
// Путь к java выбранной сборки из папки лаунчера. Пусто — сборка не выбрана
@@ -277,6 +349,8 @@ private:
BuildSwitcher *m_switcher;
JavaRuntimeService *m_javaMeta;
JavaInstaller *m_javaInstaller;
SeasonalBuildService *m_seasonalMeta;
SeasonalPackDownloader *m_packDownloader;
// Сборка, для которой сейчас ставится модлоадер: по её id находим запись,
// когда установщик отчитается.
@@ -290,6 +364,11 @@ private:
mutable QVariantList m_javaCatalog;
mutable bool m_javaCatalogDirty = true;
mutable QVariantList m_seasonalCatalog;
mutable bool m_seasonalCatalogDirty = true;
SeasonalInstall m_season;
bool m_busy = false;
// Состояние запуска, начатого до асинхронной авторизации.