13 KiB
GameLauncher
Обзор класса
GameLauncher — то, ради чего существует весь остальной лаунчер: он готовит и запускает JVM с
Minecraft. К моменту его вызова уже известно всё — версия разобрана, файлы скачаны, пользователь
авторизован, — и класс превращает это в командную строку и дочерний процесс.
Кроме самого запуска класс умеет проверять комплектность .minecraft и распаковывать нативные
библиотеки, без которых игра не стартует.
Один экземпляр — одна игра одновременно.
Место в проекте и зависимости
Подключает minecraftversion.h: разобранная версия — половина входных данных
запуска, вторая половина приходит структурой LaunchOptions из этого же заголовка.
Экземпляр создаётся и принадлежит LauncherBackend, который заполняет
LaunchOptions из настроек, выбранной сборки и результата авторизации.
Требования сборки: Qt6::Core (QProcess, QStringList) и Qt6::CorePrivate — последний нужен
ради QZipReader, которым распаковываются нативные библиотеки LWJGL. Зависимость от приватного
модуля привязывает проект к конкретной версии Qt; в CMakeLists.txt это осознанный выбор, и
предупреждение о нём отключено.
Иерархия и роль
Наследует QObject: мета-объектная система, четыре сигнала и владение по родителю. Виртуальных
методов базового класса не переопределяет.
Публичные структуры
LaunchOptions
Всё, что лаунчер знает к моменту нажатия кнопки запуска.
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
gameDir |
QString |
— | Папка .minecraft |
versionId |
QString |
— | Папка в versions, которую запускаем |
playerName |
QString |
— | Ник игрока из результата авторизации |
uuid |
QString |
— | UUID игрока |
accessToken |
QString |
— | Токен доступа |
userType |
QString |
— | Тип учётной записи: legacy, msa или ELYBY |
clientToken |
QString |
— | Токен клиента |
xuid |
QString |
— | Идентификатор Xbox; пустое значение заменяется на 0, как в офлайне |
javaPath |
QString |
— | Путь к java; пустое значение означает «искать самим» |
minMemoryMb |
int |
512 |
Значение -Xms |
maxMemoryMb |
int |
4096 |
Значение -Xmx |
extraJvmArgs |
QStringList |
— | Дополнительные аргументы JVM из настроек |
windowWidth |
int |
0 |
Ширина окна игры; 0 — не передавать --width и --height |
windowHeight |
int |
0 |
Высота окна игры |
fullscreen |
bool |
false |
Запускать в полноэкранном режиме |
serverAddress |
QString |
— | host[:port] для автоматического захода на сервер |
authlibInjectorPath |
QString |
— | Путь к authlib-injector; пустое значение — не подключать |
authlibInjectorApi |
QString |
ely.by |
Сервер авторизации, на который перенаправляется игра |
launcherName |
QString |
KishkaLauncher |
Имя лаунчера, которое видит игра |
launcherVersion |
QString |
1.0 |
Версия лаунчера |
Публичные методы
explicit GameLauncher(QObject *parent = nullptr)
Создаёт объект. Процесс игры при этом не запускается. Конструктор помечен explicit.
bool isRunning() const
Идёт ли сейчас игра. От этого зависит доступность кнопки запуска в интерфейсе.
static QStringList missingFiles(const LaunchOptions &options, const MinecraftVersion &version, int limit = 12)
Проверяет .minecraft на комплектность и возвращает описания недостающих файлов. Пустой список
означает, что всё на месте и сборку можно запускать.
Параметр limit ограничивает длину списка: перечислять все отсутствующие файлы у неустановленной
версии бессмысленно, важен сам факт и пара примеров.
Метод статический, ничего не меняет и вызывается интерфейсом для строки состояния сборки.
static QStringList buildArguments(const LaunchOptions &options, const MinecraftVersion &version, const QString &nativesDir)
Собирает аргументы ровно в том порядке, в котором их ждёт JVM: сначала аргументы JVM, затем главный
класс, затем аргументы игры. Подстановки вида ${...} из версии заменяются значениями из
параметров запуска.
Метод статический и не имеет побочных эффектов, поэтому годится и для показа собранной командной строки без запуска.
static bool extractNatives(const LaunchOptions &options, const MinecraftVersion &version, const QString &nativesDir, QString *error)
Распаковывает файлы .dll, .so и .dylib из нативных библиотек в <версия>/natives. Учитывает
поле extractExclude каждой библиотеки — перечисленные там префиксы не распаковываются.
Возвращает false и заполняет error при неудаче. Без этого шага игра не стартует: LWJGL ищет
нативные библиотеки именно в этой папке.
bool launch(const LaunchOptions &options, const MinecraftVersion &version, QString *error)
Полный цикл запуска: проверка комплектности, распаковка нативных библиотек, поиск java, старт процесса.
Возвращает false и заполняет error, если что-то из перечисленного не удалось; true означает,
что процесс запущен — дальнейшая судьба игры приходит сигналами.
Путь к java берётся из options.javaPath, а при пустом значении ищется через
JavaLocator с учётом требования версии.
void terminate()
Завершает процесс игры. Если игра не запущена, ничего не делает.
Сигналы
progress(const QString &message)
Описание текущего шага подготовки: проверка файлов, распаковка нативных библиотек, поиск java. Обработчик показывает сообщение пользователю — подготовка занимает заметное время.
output(const QString &line)
Одна строка вывода процесса игры. Обработчик пишет её в журнал; в лаунчере это вывод в консоль.
gameStarted(const QString &commandLine)
Процесс запущен; в параметре — собранная командная строка целиком. Удобно для диагностики: по ней видно, с какими аргументами и какой java стартовала игра.
gameFinished(int exitCode, bool crashed)
Игра завершилась. exitCode — код выхода процесса, crashed отличает аварийное завершение от
обычного.
Обработчик снимает признак «игра идёт», возвращает доступность кнопки запуска и сообщает
пользователю итог: ненулевой код или выставленный crashed показываются как ошибка.
Владение и время жизни
Класс наследует QObject и принимает parent — родитель его и удалит.
Процесс игры хранится в поле m_process и создаётся при запуске. Один экземпляр рассчитан ровно
на одну игру одновременно: повторный вызов launch() при работающем процессе не предусмотрен, и
вызывающий код обязан проверять isRunning().
Дочерний процесс переживает уничтожение объекта не сам по себе — завершать игру перед выходом
должен вызывающий код через terminate().
Потокобезопасность
Только поток GUI. QProcess привязан к потоку, в котором создан, и все сигналы приходят туда же.
Статические методы (missingFiles(), buildArguments(), extractNatives()) состояния не имеют,
но выполняют файловый ввод-вывод и на большой версии могут заметно задержать вызывающий поток.
Взаимодействие с другими классами
LauncherBackend собирает LaunchOptions из трёх источников: настроек лаунчера, описания
выбранной сборки и AuthResult от AuthService или
MsaAuthService. Разобранную версию он получает через
VersionLoader::load() из minecraftversion.h.
Все четыре сигнала бэкенд переправляет в QML: progress и gameFinished попадают в плашку
сообщений главного окна, output — в консоль, а gameStarted меняет признак gameRunning.
Статический missingFiles() вызывается отдельно от запуска — из метода проверки комплектности
сборки, результат которого показывает BuildsDialog.
Внешнее взаимодействие
Дочерний процесс. Класс запускает java через QProcess. Аргументы собираются
buildArguments(); для профилей Ely.by в них добавляется -javaagent с путём к
authlib-injector. Стандартный вывод процесса читается построчно и отдаётся сигналом output,
завершение — сигналом gameFinished. Направление обмена одностороннее: лаунчер запускает процесс
и читает его вывод, ничего не передавая обратно после старта.
Все сигналы процесса приходят в поток GUI.
Пример использования
auto *launcher = new GameLauncher(this);
connect(launcher, &GameLauncher::progress, this, &Backend::showStatus);
connect(launcher, &GameLauncher::gameFinished, this, &Backend::onGameFinished);
LaunchOptions options;
options.gameDir = settings.resolvedGameDir;
options.versionId = build.resolvedVersionId;
options.playerName = auth.playerName;
options.uuid = auth.uuid;
options.accessToken = auth.accessToken;
options.userType = auth.userType;
options.maxMemoryMb = settings.maxMemoryMb;
QString error;
if (!launcher->launch(options, version, &error))
emit launchError(error);
При создании этого документа использовался ИИ.