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

14 KiB

BuildsDialog

Обзор компонента

Minecraft_launcher — десктопный лаунчер Minecraft на Qt Quick. Сборка в нём — это именованный набор «версия игры + модлоадер + адрес сервера» вместе с собственным содержимым .minecraft: модами, конфигами и мирами. Активная сборка одна, её содержимое лежит в .minecraft, остальные хранятся в архивах и разворачиваются при переключении.

BuildsDialog — окно управления этими сборками: слева список со сменой активной, справа карточка выбранной — имя, сервер, версия Minecraft и модлоадеры. Отсюда же сборка ставится (скачивание версии игры и модлоадера) и удаляется.

Карточка сохраняет правки по ходу редактирования, отдельной кнопки «Сохранить» нет: иначе появляется неочевидное несохранённое состояние, пока пользователь переключается между сборками в левом списке.

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

В начале файла объявлена pragma ComponentBehavior: Bound. Импортирует QtQuick, QtQuick.Controls 2.15 и QtQuick.Layouts 2.15.

Использует три компонента из того же QML-модуля:

  • LabelledField — поля названия сборки и адреса сервера;
  • LoaderRow — по одной строке на каждый из четырёх модлоадеров;
  • VersionPickerDialog — вложенное окно выбора версии Minecraft.

Работает с C++-типом LauncherBackend (launcherbackend.h, QML_ELEMENT в модуле Minecraft_launcher) через свойство backend. Читает свойства customBuildNames, activeBuildIndex, switching и busy; вызывает customBuildAt(), addCustomBuild(), updateCustomBuild(), customBuildRemovalInfo(), removeCustomBuild(), checkInstallation(), installCustomBuild() и refreshVersionCatalog(); слушает сигнал installedVersionsChanged.

Объявлен в QML_FILES модуля (CMakeLists.txt); использует ресурс images/Trash.svg. Инстанцируется в Main.

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

Корневой тип — Dialog: модальный, 880×600 px, нулевой внутренний отступ, тёмный фон со скруглением и акцентной рамкой. Пока идёт смена активной сборки (backend.switching), окно закрывается только кнопкой: архивация и распаковка .minecraft не должны прерываться случайным щелчком мимо.

Содержимое — RowLayout из двух частей:

  • Слева (260 px) список сборок и строка «+ Новая сборка» под ним. Строка списка показывает имя, пометку «активна» у активной сборки и корзину, появляющуюся при наведении. Вся колонка выключается на время смены активной сборки.
  • Справа карточка выбранной сборки внутри Flickable — она может не поместиться по высоте. Карточка выключается и приглушается, когда сборка не выбрана или идёт переключение.

Карточка сверху вниз: название, адрес сервера, поле версии Minecraft, панель модлоадеров и строка состояния комплектности. Поле версии — не выпадающий список, а прямоугольник, который только показывает выбор и открывает отдельное окно: версий около тысячи, и разбираться в них удобнее в окне с категориями.

Отдельно объявлен вложенный Dialog подтверждения удаления шириной 420 px с красной рамкой, привязанный к тому же родителю, что и само окно.

Подвал несёт три кнопки: «Установить», «Сделать активной» и «Закрыть».

Свойства

Свойство Тип По умолчанию Обязательное Описание
backend var Да Экземпляр LauncherBackend — хранилище сборок и исполнитель установки, удаления и переключения.
editIndex int -1 Нет Индекс сборки, открытой в карточке справа. Значение -1 означает, что карточка пуста и выключена. С активной сборкой не связан: активную меняет отдельная кнопка, чтобы случайный клик по списку не запускал архивацию .minecraft.
loading bool false Нет Признак того, что карточка сейчас заполняется данными сборки. Пока он выставлен, обработчики полей не должны писать обратно — иначе открытие сборки немедленно перезаписывало бы её.

Внутренняя панель модлоадеров

Панель loaderPanel — это Column с четырьмя строками LoaderRow и собственным маленьким API. Лоадеры несовместимы между собой: игра запускается ровно с одним профилем versions/<id>, поэтому отметка одного снимает остальные, а «ничего не отмечено» — это чистая ваниль.

Свойство панели Тип Описание
rows var Массив из четырёх строк лоадеров в порядке показа: Minecraft Forge (forge), Fabric Loader (fabric), NeoForge (neoforge), Quilt Loader (quilt).

Функции панели: applyBuild(loader, loaderVersion) раздаёт данные сборки всем строкам; selectedRow() возвращает отмеченную строку или null; keepOnly(row) очищает все строки, кроме переданной; commitSelection() сохраняет выбор в сборку, записывая ключ лоадера, его версию и пустой resolvedVersionId — профиль появится только после установки, а до неё сборка запускается на чистой ванили.

Сигналы

Собственных сигналов компонент не объявляет: все изменения уходят прямо в бэкенд, и о них остальной интерфейс узнаёт по его сигналам.

Методы

selectBuild(int index) : void

Открывает сборку с указанным индексом в карточке. Читает данные через customBuildAt(), выставляет loading на время заполнения полей, раздаёт лоадеры панели через applyBuild() и в конце обновляет строку состояния.

askRemove(int index) : void

Спрашивает подтверждение перед удалением: оно необратимо и уносит с собой архив сборки. Запрашивает customBuildRemovalInfo() и наполняет окно подтверждения именем сборки и тремя признаками — есть ли у неё архив, активна ли она сейчас и последняя ли она. Индекс запоминается в самом окне подтверждения, потому что к моменту ответа строка списка под курсором может быть уже другой.

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

performRemove(int index) : void

Удаляет сборку через бэкенд и восстанавливает состояние карточки: если сборок не осталось, сбрасывает editIndex в -1, иначе открывает соседнюю — ту же позицию или последнюю оставшуюся.

commit(var fields) : void

Сохраняет часть полей сборки: передаёт QVariantMap в updateCustomBuild() и обновляет строку состояния. Ничего не делает во время заполнения карточки (loading) и при пустом editIndex — это и есть защита от записи при открытии сборки.

Вызывается по завершении правки каждого поля: имени, адреса сервера, версии Minecraft и выбора модлоадера.

refreshStatus() : void

Пересчитывает строку комплектности под карточкой. Спрашивает у бэкенда checkInstallation() и показывает либо сообщение о готовности к запуску, либо число недостающих файлов вместе с первым из них. При пустом editIndex очищает строку.

newBuildName() : string

Придумывает имя для новой сборки: перебирает «Сборка 1», «Сборка 2» и так далее, пока не найдёт свободное среди существующих имён.

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

Со стороны родителя. Main задаёт backend и открывает окно. Начальное состояние окно выбирает само в обработчике onAboutToShow: просит обновить каталог версий и открывает активную сборку, а при пустом списке оставляет карточку выключенной.

Внутрь — к вложенным компонентам. Поля LabelledField сообщают о правке сигналом editingFinished, и карточка сразу вызывает commit() с обрезанным по краям значением. Поле версии открывает VersionPickerDialog вызовом openFor() и получает результат сигналом versionChosen; запись выбранной версии сама вызывает commit() через обработчик изменения. Строки LoaderRow получают gameVersion привязкой к выбранной версии игры, поэтому смена версии Minecraft автоматически перезапрашивает списки версий лоадеров.

Наружу — к бэкенду. Кнопка «Установить» вызывает installCustomBuild(), кнопка «Сделать активной» пишет в свойство activeBuildIndex. Обе выключены, пока лаунчер занят (busy), а кнопка активации — ещё и когда выбранная сборка уже активна. Ход установки и переключения показывает плашка ProgressPanel главного окна, а не это окно.

Обратная связь от бэкенда. Окно подписано на installedVersionsChanged через Connections: установка версии или модлоадера меняет комплектность сборки, и строка состояния должна это заметить, не дожидаясь переоткрытия окна.

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

BuildsDialog {
    id: buildsDialog
    parent: Overlay.overlay
    anchors.centerIn: parent
    backend: launcherBackend
}

Button {
    text: qsTr("Сборки")
    onClicked: buildsDialog.open()
}

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