Files
minecraft-launcher/doc/cpp/JavaRuntimeService.md
T
2026-09-03 09:16:56 +03:00

9.0 KiB
Raw Blame History

JavaRuntimeService

Обзор класса

JavaRuntimeService — каталог сборок Java, которые лаунчер умеет скачать: качает, кэширует в папке лаунчера и отдаёт из кэша, пока тот не устарел. Устроен так же, как VersionManifestService.

Источников два, и они дополняют друг друга. Mojang (категория «Java») — ровно тот рантайм, которым запускает игру официальный лаунчер: версий немного, зато они заведомо совместимы. Eclipse Temurin (категории JDK и JRE) — свежие сборки всех мажорных версий, включая те, до которых Mojang ещё не дошёл.

Отдаются только сборки под текущие операционную систему и архитектуру: выбрать заведомо неработающую нечем. Исключение — macOS на Apple Silicon, где под Java 8 и 16 сборок aarch64 нет вовсе и приходится брать x64, который работает через Rosetta.

Место в проекте и зависимости

Подключает javaruntime.h: перечисление JavaRuntimeKind и структура JavaRuntimeEntry приходят оттуда.

Экземпляр создаётся и принадлежит LauncherBackend. Записями каталога пользуется JavaInstaller.

Путь к файлу кэша даёт LauncherPaths::javaCatalogFile() из launcherpaths.h.

Требования сборки: Qt6::Core (QDateTime, QHash, QSet) и Qt6::Network (QNetworkAccessManager).

Иерархия и роль

Наследует QObject: мета-объектная система, два сигнала и владение по родителю. Виртуальных методов базового класса не переопределяет.

Псевдонимы типов

JavaRuntimeService::Callbackstd::function<void(bool ok, const QString &warning)>. Как и в остальных каталогах лаунчера, ok == true с непустым warning означает данные из устаревшего кэша.

Публичные методы

explicit JavaRuntimeService(QObject *parent = nullptr)

Создаёт сервис и его QNetworkAccessManager. Кэш читается лениво. Конструктор помечен explicit.

void ensureLoaded(Callback callback, bool forceRefresh = false)

Единственная точка входа. Свежий кэш означает отложенный вызов колбэка без сети; иначе запускается обновление. Параметр forceRefresh обходит проверку свежести — так работает кнопка обновления каталога.

Одно обновление складывается из нескольких запросов сразу к обоим источникам. Ответы приходят вразнобой, поэтому они накапливаются, и каталог подменяется целиком только когда пришли все.

QList<JavaRuntimeEntry> entries(JavaRuntimeKind kind) const

Сборки одной категории: Mojang, Jdk или Jre. Новые версии идут первыми.

std::optional<JavaRuntimeEntry> find(const QString &id) const

Запись по идентификатору сборки; std::nullopt, если такой нет. Поиск идёт по внутреннему указателю.

std::optional<JavaRuntimeEntry> bestFor(int major) const

Что скачать, если для версии игры нужна Java указанной мажорной версии, а подходящей в системе нет.

Правила выбора: точное совпадение мажорной версии предпочтительнее более новой, а JDK предпочтительнее JRE — установщики Forge и NeoForge иногда требуют инструментов из полного комплекта. std::nullopt означает, что предложить нечего.

bool isRefreshing() const

Идут ли сейчас запросы. Признак остаётся истинным, пока не завершится последний из них.

bool hasData() const

Есть ли в каталоге хоть что-то — из сети или из кэша.

Сигналы

catalogChanged()

Каталог заменён новыми данными. Испускается один раз за обновление, когда пришли ответы от всех источников, а не по каждому из них.

Обработчик перечитывает entries() для нужных категорий и обновляет интерфейс.

refreshingChanged()

Изменился признак обновления. Обработчик показывает или убирает индикатор загрузки.

Владение и время жизни

Класс наследует QObject и принимает parent — родитель его и удалит. QNetworkAccessManager создаётся в конструкторе с сервисом в роли родителя.

Отложенные колбэки хранятся до завершения текущего обновления. Уничтожение сервиса с незавершёнными запросами обрывает их вместе с менеджером сети, и колбэки не вызываются.

Потокобезопасность

Только поток GUI. Чтение и запись кэша выполняются синхронно в вызывающем потоке.

Взаимодействие с другими классами

LauncherBackend вызывает ensureLoaded() при открытии окна выбора Java и по кнопке обновления, а сигналы переправляет в свойства, которые читает QML. Перед отдачей в интерфейс он сводит записи каталога с уже установленными сборками из JavaRuntimeStore — окно выбора показывает статус, не считая ничего само.

JavaInstaller получает запись каталога и по ней скачивает и распаковывает сборку. bestFor() используется, когда для запуска не хватает Java и лаунчер должен сам предложить, что поставить.

Требования версий игры к Java берутся из пространства имён JavaRequirement в javaruntime.h.

Внешнее взаимодействие

Сеть, исходящие запросы. Класс обращается к двум внешним каталогам: API Adoptium (сборки Temurin) и списку рантаймов Mojang. Формат обоих — JSON поверх HTTPS, разбор разделён на две функции.

Запросов на одно обновление несколько: список сборок Temurin запрашивается по мажорным версиям, и на macOS с Apple Silicon неудачный запрос сборки aarch64 может быть переспрошен для x64 — это и есть тот самый случай Java 8 и 16.

Общий счётчик незавершённых запросов сводит их воедино: пока он не обнулился, каталог не подменяется, а предупреждения от отдельных источников накапливаются.

Все сигналы и колбэки приходят в поток GUI.

Пример использования

auto *javaCatalog = new JavaRuntimeService(this);
connect(javaCatalog, &JavaRuntimeService::catalogChanged, this, &Backend::rebuildJavaCatalog);

javaCatalog->ensureLoaded([this, javaCatalog](bool ok, const QString &warning) {
    if (!ok) {
        emit javaCatalogError(warning);
        return;
    }
    const auto best = javaCatalog->bestFor(version.javaMajor);
    if (best)
        emit suggestJavaInstall(best->id, best->version);
});

При создании этого документа использовался ИИ.