Files
minecraft-launcher/seasonalbuildservice.h
2026-08-31 00:59:14 +03:00

92 lines
3.6 KiB
C++

#pragma once
#include <QDate>
#include <QDateTime>
#include <QHash>
#include <QList>
#include <QObject>
#include <QString>
#include <QUrl>
#include <functional>
#include <optional>
class QNetworkAccessManager;
class QJsonObject;
// Одна готовая сборка с сервера сезонных сборок.
struct SeasonalBuildEntry
{
QString id; // season-5 — он же ключ, по которому сборка
// узнаётся среди локальных записей
QString name; // «Сезон 5: Пустоши»
int revision = 0; // растёт при каждой публикации
QString minecraftVersion; // 1.20.1
QString loader; // "" | forge | fabric | neoforge | quilt
QString loaderVersion; // 47.4.0
int modCount = 0;
QDate seasonStart;
QDate seasonEnd; // невалидная — сезон ещё не закончен
QString serverUrl; // адрес игрового сервера, не файлового
int javaMajor = 0; // 0 — определять по версии игры
QString description;
QUrl archiveUrl;
qint64 archiveSize = 0;
QString archiveSha256;
bool isValid() const { return !id.isEmpty() && revision > 0 && archiveUrl.isValid(); }
};
// Каталог сезонных сборок: скачивает index.json с файлового сервера, кэширует
// его в папке лаунчера и отдаёт из кэша, пока тот не устарел. Устройство
// повторяет VersionManifestService — включая то, что пустой разбор считается
// испорченным ответом и хороший кэш им не затирается.
class SeasonalBuildService : public QObject
{
Q_OBJECT
public:
// ok = true и непустой warning — данные отдали из устаревшего кэша.
using Callback = std::function<void(bool ok, const QString &warning)>;
explicit SeasonalBuildService(QObject *parent = nullptr);
QList<SeasonalBuildEntry> builds() const { return m_builds; }
bool hasData() const { return !m_builds.isEmpty(); }
bool isRefreshing() const { return m_refreshing; }
// Последняя ошибка обращения к серверу; пусто — всё в порядке.
QString lastError() const { return m_lastError; }
std::optional<SeasonalBuildEntry> find(const QString &id) const;
// Адрес сервера сборок. Меняется из настроек, поэтому при смене хоста
// накопленные данные и кэш сбрасываются: ссылки в них указывают на старый.
void setBaseUrl(const QUrl &baseUrl);
QUrl baseUrl() const { return m_baseUrl; }
void ensureLoaded(Callback callback, bool forceRefresh = false);
signals:
void buildsChanged();
void refreshingChanged();
private:
bool readCache();
void writeCache();
void startRefresh();
void finishRefresh(bool ok, const QString &warning);
void applyBuilds(QList<SeasonalBuildEntry> list);
QList<SeasonalBuildEntry> parseCatalog(const QJsonObject &root, QString *error) const;
QNetworkAccessManager *m_network;
QUrl m_baseUrl;
QList<SeasonalBuildEntry> m_builds;
QHash<QString, int> m_indexById;
QDateTime m_fetchedAt;
QString m_lastError;
bool m_refreshing = false;
bool m_cacheRead = false;
QList<Callback> m_pending;
};