# 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
остаётся на месте. Исходники хранятся в репозитории, чтобы сборка не зависела от сети, а версия
была зафиксирована: от неё зависит побайтовый результат сжатия.

---

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