new builds menu and modloaders implementation
This commit is contained in:
+84
-22
@@ -15,6 +15,9 @@ class AuthService;
|
||||
class GameLauncher;
|
||||
class VersionManifestService;
|
||||
class VersionInstaller;
|
||||
class ModLoaderVersionService;
|
||||
class ModLoaderInstaller;
|
||||
class BuildSwitcher;
|
||||
|
||||
class LauncherBackend : public QObject
|
||||
{
|
||||
@@ -22,9 +25,22 @@ class LauncherBackend : public QObject
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(QStringList profileNames READ profileNames NOTIFY profilesChanged)
|
||||
Q_PROPERTY(QStringList versionNames READ versionNames NOTIFY versionsChanged)
|
||||
Q_PROPERTY(QStringList customBuildNames READ customBuildNames NOTIFY customBuildsChanged)
|
||||
|
||||
// Сборка, которую запускает кнопка игры. Хранится по id сборки, а не по
|
||||
// индексу: удаление соседней записи не должно переназначать активную.
|
||||
Q_PROPERTY(int activeBuildIndex READ activeBuildIndex WRITE setActiveBuildIndex
|
||||
NOTIFY activeBuildChanged)
|
||||
Q_PROPERTY(QString activeBuildName READ activeBuildName NOTIFY activeBuildChanged)
|
||||
Q_PROPERTY(QStringList installedVersions READ installedVersions NOTIFY installedVersionsChanged)
|
||||
Q_PROPERTY(bool gameRunning READ gameRunning NOTIFY gameRunningChanged)
|
||||
|
||||
// Идёт архивация/распаковка .minecraft при смене сборки. Отдельно от busy,
|
||||
// потому что на это время блокируется ещё и список сборок.
|
||||
Q_PROPERTY(bool switching READ switching NOTIFY switchChanged)
|
||||
Q_PROPERTY(double switchProgress READ switchProgress NOTIFY switchChanged)
|
||||
Q_PROPERTY(QString switchStage READ switchStage NOTIFY switchChanged)
|
||||
Q_PROPERTY(QString switchStatus READ switchStatus NOTIFY switchChanged)
|
||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||
|
||||
// Объединённый список для выпадающего меню версий: установленные, разделитель,
|
||||
@@ -46,9 +62,16 @@ public:
|
||||
~LauncherBackend() override;
|
||||
|
||||
QStringList profileNames() const;
|
||||
QStringList versionNames() const;
|
||||
QStringList customBuildNames() const;
|
||||
int activeBuildIndex() const;
|
||||
void setActiveBuildIndex(int index);
|
||||
QString activeBuildName() const;
|
||||
QStringList installedVersions() const;
|
||||
bool gameRunning() const;
|
||||
bool switching() const;
|
||||
double switchProgress() const;
|
||||
QString switchStage() const;
|
||||
QString switchStatus() const;
|
||||
// Пока идёт загрузка версии, лаунчер тоже занят: кнопка запуска гаснет.
|
||||
bool busy() const;
|
||||
|
||||
@@ -66,32 +89,35 @@ public:
|
||||
const QString &login,
|
||||
const QString &password,
|
||||
const QString &authType = QStringLiteral("offline"));
|
||||
Q_INVOKABLE void addVersion(const QString &name,
|
||||
const QString &serverUrl,
|
||||
const QString &versionId = QString());
|
||||
Q_INVOKABLE void addCustomBuild(const QString &name,
|
||||
const QString &serverUrl,
|
||||
const QString &minecraftVersion = QString());
|
||||
Q_INVOKABLE void updateProfile(int index,
|
||||
const QString &name,
|
||||
const QString &login,
|
||||
const QString &password,
|
||||
const QString &authType = QStringLiteral("offline"));
|
||||
Q_INVOKABLE void updateVersion(int index,
|
||||
const QString &name,
|
||||
const QString &serverUrl,
|
||||
const QString &versionId = QString());
|
||||
// Мержит только присланные ключи: name, serverUrl, minecraftVersion,
|
||||
// loader, loaderVersion, resolvedVersionId.
|
||||
Q_INVOKABLE void updateCustomBuild(int index, const QVariantMap &fields);
|
||||
Q_INVOKABLE QVariantMap profileAt(int index) const;
|
||||
Q_INVOKABLE QVariantMap versionAt(int index) const;
|
||||
Q_INVOKABLE QVariantMap customBuildAt(int index) const;
|
||||
Q_INVOKABLE void removeProfile(int index);
|
||||
Q_INVOKABLE void removeVersion(int index);
|
||||
Q_INVOKABLE void removeCustomBuild(int index);
|
||||
|
||||
// Докачать то, чего не хватает выбранной сборке. Отдельной кнопкой, потому
|
||||
// что карточка сборки сохраняет правки по ходу редактирования.
|
||||
Q_INVOKABLE void installCustomBuild(int index);
|
||||
|
||||
// Главная кнопка. Проверяет выбор профиля и версии, комплектность .minecraft,
|
||||
// при необходимости авторизуется и стартует игру.
|
||||
Q_INVOKABLE void launchGame(int profileIndex, int versionIndex);
|
||||
Q_INVOKABLE void launchGame(int profileIndex, int buildIndex);
|
||||
Q_INVOKABLE void submitTwoFactorCode(const QString &code);
|
||||
Q_INVOKABLE void cancelPendingLaunch();
|
||||
Q_INVOKABLE void stopGame();
|
||||
|
||||
// Проверка без запуска — для подсказки в интерфейсе.
|
||||
Q_INVOKABLE QStringList checkInstallation(int versionIndex) const;
|
||||
Q_INVOKABLE QStringList checkInstallation(int buildIndex) const;
|
||||
|
||||
// Вызывается при открытии выпадающего списка версий: свежий кэш — без сети.
|
||||
Q_INVOKABLE void refreshVersionCatalog(bool force = false);
|
||||
@@ -99,6 +125,20 @@ public:
|
||||
Q_INVOKABLE void installVersion(const QString &versionId);
|
||||
Q_INVOKABLE void cancelDownload();
|
||||
|
||||
// Версии модлоадеров для выбранной версии игры. Возвращает список карт
|
||||
// {version, label, recommended, stable}; несовместимых строк в нём нет —
|
||||
// отбор заложен в сам источник данных.
|
||||
Q_INVOKABLE QVariantList loaderVersions(const QString &loaderKey,
|
||||
const QString &gameVersion) const;
|
||||
Q_INVOKABLE void refreshLoaderVersions(const QString &loaderKey,
|
||||
const QString &gameVersion,
|
||||
bool force = false);
|
||||
Q_INVOKABLE bool loaderVersionsLoading(const QString &loaderKey,
|
||||
const QString &gameVersion) const;
|
||||
// Ставит модлоадер, выбранный в сборке, и записывает получившийся профиль
|
||||
// в resolvedVersionId.
|
||||
Q_INVOKABLE void installLoaderForBuild(int index);
|
||||
|
||||
Q_INVOKABLE QVariantMap settings() const;
|
||||
Q_INVOKABLE void updateSettings(const QVariantMap &values);
|
||||
Q_INVOKABLE QStringList detectedJava() const;
|
||||
@@ -108,7 +148,10 @@ public:
|
||||
|
||||
signals:
|
||||
void profilesChanged();
|
||||
void versionsChanged();
|
||||
void customBuildsChanged();
|
||||
void activeBuildChanged();
|
||||
void switchChanged();
|
||||
void loaderVersionsChanged(const QString &loaderKey, const QString &gameVersion);
|
||||
void installedVersionsChanged();
|
||||
void settingsChanged();
|
||||
void gameRunningChanged();
|
||||
@@ -118,7 +161,7 @@ signals:
|
||||
void downloadChanged();
|
||||
|
||||
void launchProgress(const QString &message);
|
||||
void launched(const QString &profileName, const QString &versionName, const QString &serverUrl);
|
||||
void launched(const QString &profileName, const QString &buildName, const QString &serverUrl);
|
||||
void launchError(const QString &message);
|
||||
void twoFactorRequired(const QString &profileName);
|
||||
void gameOutput(const QString &line);
|
||||
@@ -132,17 +175,23 @@ private:
|
||||
QString authType = QStringLiteral("offline"); // offline | elyby
|
||||
QString clientToken, accessToken, uuid, resolvedName, userType;
|
||||
};
|
||||
struct Version
|
||||
// Пользовательская сборка: имя, сервер, версия Minecraft и, начиная со
|
||||
// второго этапа, выбранный модлоадер.
|
||||
struct CustomBuild
|
||||
{
|
||||
int id = 0;
|
||||
QString name, serverUrl, versionId;
|
||||
QString name, serverUrl;
|
||||
QString minecraftVersion; // 1.20.1
|
||||
QString loader; // "" | forge | fabric | neoforge | quilt
|
||||
QString loaderVersion; // 47.4.0 | 0.19.3
|
||||
QString resolvedVersionId; // versions/<id>, который реально запускается
|
||||
};
|
||||
|
||||
void loadData();
|
||||
void loadSettings();
|
||||
void ensureDataFiles();
|
||||
void saveProfiles();
|
||||
void saveVersions();
|
||||
void saveCustomBuilds();
|
||||
void saveSettings();
|
||||
|
||||
// Чтение файлов лаунчера. Отсутствие файла — норма (первый запуск), а вот
|
||||
@@ -155,7 +204,13 @@ private:
|
||||
bool writeJsonFile(const QString &path, const QJsonDocument &document);
|
||||
|
||||
QString gameDir() const;
|
||||
QString versionIdOf(const Version &version) const;
|
||||
// id профиля в <gameDir>/versions, который запускает эта сборка.
|
||||
QString launchVersionIdOf(const CustomBuild &build) const;
|
||||
int indexOfBuildId(int buildId) const;
|
||||
|
||||
// Перекладывает <root>/versions.json в customBuilds.json при первом запуске
|
||||
// после переименования. true — миграция прошла, читать нужно новый файл.
|
||||
bool migrateLegacyBuildsFile();
|
||||
|
||||
void invalidateCatalog();
|
||||
void rebuildCatalog() const;
|
||||
@@ -168,18 +223,25 @@ private:
|
||||
void continueLaunch(const AuthResult &auth);
|
||||
|
||||
QList<Profile> m_profiles;
|
||||
QList<Version> m_versions;
|
||||
QList<CustomBuild> m_builds;
|
||||
QVariantMap m_settings;
|
||||
// Проблемы хранилища, замеченные на старте: показываются одним сообщением,
|
||||
// когда интерфейс уже подключился к сигналам.
|
||||
QStringList m_storageIssues;
|
||||
int m_nextProfileId = 1;
|
||||
int m_nextVersionId = 1;
|
||||
int m_nextBuildId = 1;
|
||||
|
||||
AuthService *m_auth;
|
||||
GameLauncher *m_launcher;
|
||||
VersionManifestService *m_manifest;
|
||||
VersionInstaller *m_installer;
|
||||
ModLoaderVersionService *m_loaderMeta;
|
||||
ModLoaderInstaller *m_loaderInstaller;
|
||||
BuildSwitcher *m_switcher;
|
||||
|
||||
// Сборка, для которой сейчас ставится модлоадер: по её id находим запись,
|
||||
// когда установщик отчитается.
|
||||
int m_loaderInstallBuildId = -1;
|
||||
|
||||
// Каталог версий пересобирается только по изменениям: QML читает свойство
|
||||
// помногу раз за кадр, пока открыт список.
|
||||
@@ -190,7 +252,7 @@ private:
|
||||
|
||||
// Состояние запуска, начатого до асинхронной авторизации.
|
||||
int m_pendingProfile = -1;
|
||||
int m_pendingVersion = -1;
|
||||
int m_pendingBuild = -1;
|
||||
MinecraftVersion m_pendingVersionData;
|
||||
QString m_pendingInjectorPath;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user