166 lines
13 KiB
Markdown
166 lines
13 KiB
Markdown
# Minecraft Launcher — справочник по исходному коду
|
||
|
||
Десктопный лаунчер Minecraft на Qt 6. Интерфейс написан на QML, вся работа — авторизация,
|
||
скачивание версий, установка модлоадеров и Java, запуск игры — лежит в C++.
|
||
|
||
Документация разделена на две части: [QML-компоненты](#qml-компоненты) и
|
||
[C++-классы](#c-классы).
|
||
|
||
## Как устроено приложение
|
||
|
||
Слоёв четыре, и каждый общается только с соседними:
|
||
|
||
1. **QML.** [Main](qml/Main.md) — единственное настоящее окно и точка входа. Оно держит
|
||
единственный экземпляр `LauncherBackend` и раздаёт его вложенным диалогам через свойство
|
||
`backend`. Ни один QML-файл не обращается к сервисам напрямую.
|
||
2. **Фасад.** [LauncherBackend](cpp/LauncherBackend.md) — главный класс, видимый из QML.
|
||
Хранит профили, сборки и настройки, владеет двенадцатью сервисами и сводит их состояние к
|
||
свойствам, которые читает интерфейс. Каталоги он отдаёт уже сведёнными с локальным состоянием,
|
||
поэтому окна показывают статус, не считая ничего сами.
|
||
3. **Сервисы.** Каталоги (версий, модлоадеров, Java, сезонных сборок), установщики, службы
|
||
авторизации, переключатель сборок и запуск игры. Каждый занят одним делом и ничего не знает об
|
||
интерфейсе.
|
||
Особняком стоит [Localization](cpp/Localization.md) — второй и последний тип, видимый из QML.
|
||
Это синглтон `Loc`, через который проходят все тексты интерфейса: `Loc.t.домен.вид.имя` в QML и
|
||
`Loc::text("домен.вид.имя")` в C++. Он ни от чего не зависит и доступен всем слоям сразу.
|
||
|
||
4. **Внешний мир.** Сеть (Mojang, Ely.by, Microsoft, Adoptium, файловый сервер сборок), файловая
|
||
система (`.minecraft` и папка лаунчера) и дочерние процессы (java, установщики модлоадеров,
|
||
`tar`).
|
||
|
||
Почти весь код работает в потоке GUI: параллелизм даёт асинхронная сеть, а не потоки. Единственное
|
||
исключение — операции над содержимым `.minecraft` (гигабайты модов и миров), вынесенные в
|
||
отдельный поток к [BuildArchiveWorker](cpp/BuildArchiveWorker.md).
|
||
|
||
## QML-компоненты
|
||
|
||
| Компонент | Описание |
|
||
|-----------|----------|
|
||
| [Main](qml/Main.md) | Главное окно и точка входа: экран запуска, профили, плашка сообщений, панели прогресса и внутренние диалоги |
|
||
| [BuildsDialog](qml/BuildsDialog.md) | Пользовательские сборки: список слева, карточка редактирования справа |
|
||
| [VersionPickerDialog](qml/VersionPickerDialog.md) | Выбор версии Minecraft: категории, поиск, удаление скачанных версий |
|
||
| [JavaPickerDialog](qml/JavaPickerDialog.md) | Выбор сборки Java; подтверждение при необходимости сразу начинает загрузку |
|
||
| [SeasonalBuildsDialog](qml/SeasonalBuildsDialog.md) | Каталог готовых сезонных сборок таблицей и установка одной кнопкой |
|
||
| [MicrosoftLoginDialog](qml/MicrosoftLoginDialog.md) | Окно входа в аккаунт Microsoft; собирается только с Qt WebEngine |
|
||
| [LoaderRow](qml/LoaderRow.md) | Одна строка модлоадера в карточке сборки: чекбокс и список версий |
|
||
| [ProgressPanel](qml/ProgressPanel.md) | Плашка хода долгой операции в левом нижнем углу |
|
||
| [DarkCombo](qml/DarkCombo.md) | Выпадающий список в тёмном стиле окна |
|
||
| [LabelledField](qml/LabelledField.md) | Подпись и поле ввода одной колонкой |
|
||
|
||
## C++-классы
|
||
|
||
### Точка входа
|
||
|
||
| Файл | Описание |
|
||
|------|----------|
|
||
| [main.cpp](cpp/main.md) | Инициализация WebEngine, объект приложения, каталог переводов, стиль `Basic`, загрузка QML-модуля |
|
||
|
||
### Фасад
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [Localization](cpp/Localization.md) | Синглтон `Loc`: все тексты интерфейса в одном файле `i18n/translations.json`, переключение языка на лету |
|
||
| [LauncherBackend](cpp/LauncherBackend.md) | Единственный тип, видимый из QML: 26 свойств, 42 вызываемых метода, состояние лаунчера и порядок работы всех сервисов |
|
||
|
||
### Авторизация и запуск
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [AuthService](cpp/AuthService.md) | Вход через Ely.by и офлайн-режим; структура `AuthResult` |
|
||
| [MsaAuthService](cpp/MsaAuthService.md) | Вход через аккаунт Microsoft: OAuth2 → Xbox Live → XSTS → Minecraft Services |
|
||
| [GameLauncher](cpp/GameLauncher.md) | Сборка командной строки, распаковка нативных библиотек и запуск JVM |
|
||
|
||
### Версии игры
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [VersionManifestService](cpp/VersionManifestService.md) | Каталог версий Mojang с кэшем в папке лаунчера |
|
||
| [VersionInstaller](cpp/VersionInstaller.md) | Фоновая установка версии: jar, библиотеки, индекс ресурсов и сами ресурсы |
|
||
|
||
### Модлоадеры
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [ModLoaderVersionService](cpp/ModLoaderVersionService.md) | Списки версий Forge, Fabric, NeoForge и Quilt; совместимость заложена в структуру данных |
|
||
| [ModLoaderInstaller](cpp/ModLoaderInstaller.md) | Два пути установки под одним фасадом: готовое описание версии либо запуск `installer.jar` |
|
||
|
||
### Java
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [JavaRuntimeService](cpp/JavaRuntimeService.md) | Каталог сборок Mojang и Eclipse Temurin под текущую платформу |
|
||
| [JavaInstaller](cpp/JavaInstaller.md) | Установка сборки Java: архив Temurin либо дерево файлов Mojang |
|
||
|
||
### Сборки и их содержимое
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [BuildSwitcher](cpp/BuildSwitcher.md) | Порядок шагов смены активной сборки и восстановление после прерванной операции |
|
||
| [BuildArchiveWorker](cpp/BuildArchiveWorker.md) | Упаковка, очистка, распаковка и раскатка пака в отдельном потоке |
|
||
|
||
### Сезонные сборки
|
||
|
||
| Класс | Описание |
|
||
|-------|----------|
|
||
| [SeasonalBuildService](cpp/SeasonalBuildService.md) | Каталог готовых сборок с файлового сервера |
|
||
| [SeasonalPackDownloader](cpp/SeasonalPackDownloader.md) | Загрузка архива сборки потоком с проверкой sha256 |
|
||
|
||
### Общие типы и утилиты
|
||
|
||
| Файл | Описание |
|
||
|------|----------|
|
||
| [minecraftversion.h](cpp/minecraftversion.md) | Структуры версии и библиотеки, чтение и разворачивание цепочки `inheritsFrom` |
|
||
| [javaruntime.h](cpp/javaruntime.md) | Виды сборок Java, папка `<root>/java` и таблица требований версий игры |
|
||
| [modloader.h](cpp/modloader.md) | Перечисление модлоадеров, запись версии и перевод ключей |
|
||
| [launcherpaths.h](cpp/launcherpaths.md) | Все пути к данным лаунчера в одном месте |
|
||
| [javalocator.h](cpp/javalocator.md) | Поиск установленной в системе Java и выбор подходящей версии |
|
||
| [zlibreference.h](cpp/zlibreference.md) | Подмена zlib-ng эталонным zlib для установщиков Forge и NeoForge |
|
||
|
||
## Сборка
|
||
|
||
Требуется Qt 6.8 или новее. Обязательные модули: `Quick`, `QuickControls2`, `Core`, `CorePrivate`,
|
||
`Gui`, `Network`. `CorePrivate` нужен ради `QZipReader` и `QZipWriter` — ими распаковываются
|
||
нативные библиотеки LWJGL и архивы сборок; привязка к версии Qt из-за приватного модуля —
|
||
осознанный выбор, и предупреждение о ней в `CMakeLists.txt` отключено.
|
||
|
||
`Qt6::WebEngineQuick` необязателен, и это принципиально: модуль ставится отдельной галочкой в
|
||
установщике Qt и тянет за собой WebChannel с Positioning, которых в типовой установке нет. Если
|
||
сделать его обязательным, у любого, кто их не поставил, проект перестанет конфигурироваться
|
||
целиком — вместе с офлайном и Ely.by. Когда модуль найден, определяется макрос
|
||
`LAUNCHER_HAS_WEBENGINE`, а [MicrosoftLoginDialog.qml](qml/MicrosoftLoginDialog.md) добавляется в
|
||
QML-модуль; без модуля лаунчер собирается и работает как обычно, только вход через Microsoft
|
||
сообщает, что эта сборка его не умеет. В QML различие видно через свойство
|
||
`backend.microsoftAvailable`.
|
||
|
||
QML-модуль объявлен как `qt_add_qml_module` с URI `Minecraft_launcher`; точка входа —
|
||
`engine.loadFromModule("Minecraft_launcher", "Main")`. Туда же, в список `RESOURCES`, попадает
|
||
каталог переводов `i18n/translations.json`.
|
||
|
||
### Тексты интерфейса
|
||
|
||
Все подписи, сообщения и ошибки лежат в одном файле `i18n/translations.json` и достаются через
|
||
синглтон `Loc` — подробности, правила именования ключей и порядок добавления языка описаны в
|
||
[Localization](cpp/Localization.md). Штатные `.ts`/`.qm` не используются, `lupdate` и `lrelease`
|
||
в сборке не участвуют. Целостность каталога проверяет `python3 tools/check_translations.py`.
|
||
|
||
### Каталог `zlib/`
|
||
|
||
В репозитории лежат исходники обычного zlib версии 1.3.1 — это чужой upstream-код, и
|
||
документацией он не покрыт. Он нужен вот зачем.
|
||
|
||
Установщики Forge и NeoForge сверяют sha1 каждого jar, который сами же и собирают, с эталоном из
|
||
`install_profile.json`. Эталон посчитан на обычном zlib, а дистрибутивы вроде CachyOS и Fedora
|
||
подставляют вместо него zlib-ng: сжатие корректное, но побайтово другое, поэтому установка падает
|
||
на любой версии игры сообщением «Processor failed, invalid outputs». Сменить Java не выйдет —
|
||
сборки OpenJDK под Linux берут `libz.so.1` из системы.
|
||
|
||
Поэтому на Linux собирается цель `launcher_zlib_reference` из этих исходников, и готовая
|
||
библиотека подсовывается через `LD_PRELOAD` только процессу установщика — см.
|
||
[zlibreference.h](cpp/zlibreference.md). Сам лаунчер с ней не линкуется, системный zlib-ng
|
||
остаётся на месте. Исходники хранятся в репозитории, чтобы сборка не зависела от сети, а версия
|
||
была зафиксирована: от неё зависит побайтовый результат сжатия.
|
||
|
||
---
|
||
|
||
При создании этого документа использовался ИИ.
|