Этот раздел описывает полный рабочий цикл игровой сборки: от каталога с готовым клиентом до обновления, которое увидит лаунчер. Он рассчитан на текущую схему Wraithbound с wraithbound-publisher, launcher-server, S3 и CDN.

Главное за минуту

У каждой сборки есть постоянный buildId, а у каждого её состояния — отдельный неизменяемый releaseId. Публикация состоит из двух независимых действий:
  1. Publisher загружает новый неизменяемый релиз в S3 и устанавливает его подписанный manifest в launcher-server.
  2. Администратор проверяет результат и нажимает «Опубликовать». Только после этого launcher-server переключает активный релиз.
Не меняйте файлы уже опубликованного releaseId. Любое изменение клиента, профиля, Java или assets выпускается с новым releaseId и увеличенным generation.

Термины

Где лежат исходники

На production-машине launcher-server используется следующая раскладка:
Имя TOML-файла всегда равно buildId. Запрос из админки содержит только этот ID; launcher-server сам находит разрешённый /etc/wraithbound/builds/4.toml. Передать произвольный путь из браузера невозможно. В репозитории есть готовый пример:
Для локальной публикации с Windows используется аналогичная конфигурация:

Подготовка новой сборки

1. Создайте сервер на сайте

Создайте запись игрового сервера в административной панели сайта и запомните её числовой ID. Этот ID используется во всей цепочке как serverId и buildId. Например, если сервер получил ID 4, должны совпасть:
Не используйте название сервера вместо ID. Название можно менять, числовой ID сборки должен оставаться стабильным.

2. Подготовьте чистый клиент

Скопируйте в clients/<Название> только то, что должен получить пользователь:
  • Minecraft JAR и библиотеки;
  • Forge/loader и необходимые bootstrap-библиотеки;
  • моды;
  • natives для поддерживаемой платформы;
  • начальные конфигурации, если ими должен управлять лаунчер;
  • ресурсы сборки.
Перед публикацией удалите временные данные: logs, crash-reports, saves, скриншоты, кэши, дампы и локальные настройки разработчика.
Каталог assets хранится отдельно и не должен дублироваться внутри каждой сборки. Java также хранится отдельным runtime и повторно используется разными сборками.

3. Создайте profile.json

Минимальный рабочий профиль Architechnica выглядит так:
JSON не поддерживает комментарии. Для нового профиля создайте новый UUID и не переиспользуйте UUID другой сборки.

Поля профиля

Селекторы в update, updateVerify и updateExclusions — не glob-шаблоны. mods означает каталог и всё его содержимое. Нельзя использовать .., обратные слеши, абсолютные пути или *.

Как выбрать файловую политику

  • Добавляйте в updateVerify то, что обязано точно совпадать с релизом: библиотеки, JAR, моды и natives.
  • Добавляйте в update файлы, которые могут меняться во время игры, но должны восстанавливаться перед следующим запуском.
  • Добавляйте в updateExclusions только пользовательские настройки, которые действительно нужно сохранить.
  • Если весь config исключён, обновление не сможет доставлять изменения конфигов. Если весь config проверяется, пользовательские изменения будут восстановлены до опубликованного состояния.
Лаунчер дополнительно сохраняет logs, crash-reports, screenshots, saves, resourcepacks, shaderpacks и options.txt по умолчанию.

4. Подготовьте assets

Структура должна соответствовать обычным Minecraft assets:
Если в TOML указано download_from_mojang = true, publisher скачает отсутствующий официальный index и его objects. Уже проверенные объекты будут переиспользованы. Кастомные ресурсы, отсутствующие в официальном asset index, держите в каталоге клиента или добавляйте в собственный корректный index; случайные файлы из общего каталога assets в manifest не попадут.

5. Подготовьте Java runtime

Runtime должен быть распакованным каталогом, а не ZIP-файлом:
Publisher умеет скачать ZIP по HTTPS, проверить его SHA-256 и распаковать при отсутствии runtime. Значение sha256 берётся у конкретного дистрибутива Java; не копируйте hash от другой версии архива.

6. Создайте publisher TOML

Bucket можно задать через storage.bucket, WB_PUBLISHER_S3_BUCKET или WRAITHBOUND_S3_BUCKET. В production предпочтительно передавать bucket и все секреты через окружение/deployment, а не копировать их в разные TOML-файлы.
Не записывайте в TOML и Git S3 secret key, admin token или приватный Ed25519 ключ. CDN URL, S3 endpoint, region, prefix и bucket name секретами не являются.

7. Выставьте права на сервере

Процесс wraithbound должен читать исходники, профиль, assets, runtime и TOML. Запись нужна в каталоги, куда publisher докачивает assets/runtime, и во временный рабочий каталог.

Предварительная проверка

Соберите publisher один раз:
Проверьте конфигурацию без обращения к S3:
Затем постройте полный план без загрузки:
--dry-run должен вывести профиль, количество объектов и общий размер. Для диагностики точных S3 keys можно временно добавить --list-objects, но такой вывод содержит локальные пути и получается очень большим.

Что делает кнопка «Подготовить»

На странице /admin/launcher/builds кнопка «Подготовить» ставит buildId в ограниченную очередь launcher-server. Worker выполняет:
Эта операция:
  • проверяет TOML, профиль и локальные каталоги;
  • получает недостающие Minecraft assets;
  • получает и проверяет Java runtime;
  • показывает этапы в разделе «Операции».
Она не загружает релиз в S3, не устанавливает signed envelope и не меняет активный релиз. Поэтому после «Подготовить» пользователи ещё ничего не увидят.

Публикация первого релиза

1. Подготовьте секреты в текущей консоли

Admin endpoint должен быть доступен только publisher/CI через VPN, приватную сеть или SSH tunnel. Публичный launcher API не должен проксировать admin RPC.

2. Проверьте релиз

3. Загрузите и установите релиз

Команда выполняет порядок metadata-last:
  1. подготавливает assets и runtime;
  2. строит manifests и считает SHA-256;
  3. загружает игровые файлы, assets и runtime;
  4. загружает profile.json и manifests;
  5. подписывает protobuf envelope;
  6. устанавливает envelope в launcher-server через InstallBuildRelease.
Если S3-загрузка завершилась ошибкой, control plane не переключается. Если объект с тем же key уже существует, publisher сверяет metadata sha256 и переиспользует только точное совпадение.

4. Активируйте релиз

Откройте /admin/launcher/builds, найдите сборку, нажмите «Опубликовать» и выберите установленный релиз. Launcher-server ещё раз проверит подпись и атомарно переключит active release. После активации проверьте один реальный лаунчер: получение профиля, загрузку с CDN, scanner, Java, Guardian и запуск Minecraft.

Как выпустить обновление сборки

Для каждого обновления используйте один и тот же безопасный порядок.
  1. Сделайте резервную копию или Git-снимок исходного каталога сборки.
  2. Добавьте/замените моды, конфиги, библиотеки и другие файлы.
  3. При необходимости измените profile.json.
  4. Задайте новый release.id.
  5. Увеличьте release.generation относительно всех предыдущих релизов.
  6. Выполните check.
  7. Выполните publish --dry-run и проверьте размер/число объектов.
  8. Выполните настоящий publish.
  9. Убедитесь, что операция установки завершилась и релиз появился в админке.
  10. Активируйте его кнопкой «Опубликовать».
  11. Проверьте обновление на тестовом лаунчере.
Пример без редактирования TOML — release ID и generation передаются командой:
Хорошая схема releaseId: YYYY.MM.DD.N, где N — номер выпуска за день. generation при этом остаётся отдельным возрастающим числом для этой сборки.

Что произойдёт у пользователя

После активации launcher-server возвращает новый signed release. Лаунчер:
  1. сравнивает локальные файлы с новым manifest;
  2. скачивает только отсутствующие и изменённые объекты;
  3. сохраняет исключённые пользовательские данные;
  4. повторно проверяет клиент и Java;
  5. формирует актуальную Guardian policy;
  6. запускает Minecraft.
Неизменившиеся S3/CDN-объекты не скачиваются повторно, даже если они входят в новый release manifest.

Откат

Откат не требует повторной загрузки старой сборки:
  1. Откройте /admin/launcher/builds.
  2. Нажмите «Откатить» у нужной сборки.
  3. Выберите ранее установленный релиз.
  4. Подтвердите действие.
  5. Проверьте активный release ID и запуск тестового клиента.
Launcher-server переключает active pointer на ранее проверенный signed envelope. Старые файлы должны оставаться в S3, поэтому publisher намеренно не выполняет remote prune.
Не удаляйте старый release-каталог из S3 сразу после обновления. Иначе откат переключит manifest, но CDN не сможет отдать соответствующие файлы.

Блокировка сборки и обслуживание

Блокировка сборки применяется к одному buildId. Используйте её, когда конкретный клиент повреждён или запуск нужно временно остановить. В админке обязательно укажите понятную оператору причину; там же блокировка снимается. Режим обслуживания применяется шире:
  • install-disabled — запрещает подготовку/установку затронутых сборок;
  • launch-disabled — запрещает запуск Minecraft;
  • full — полностью блокирует пользовательский сценарий и показывает обязательное окно обслуживания.
Перед включением обслуживания проверьте, какие buildId затронуты. После работ отключите режим отдельным действием в том же разделе админки.

S3 и CDN

В текущей production-схеме разделены два namespace:
Публичное зеркало для лаунчера:
Лаунчер получает только подписанные HTTPS URL. S3 access key, secret key, admin token и приватный ключ подписи не передаются в Electron renderer и не включаются в launcher.config.json. Для publisher выдайте отдельную S3 identity с доступом только на content prefix. Launcher-server использует свою identity для control-plane prefix. Не запускайте два пишущих launcher-server на одном prefix: распределённой блокировки между репликами пока нет.

Публикация через GitHub Actions

Workflow находится в:
Он запускается вручную и принимает:
  • config_path — отслеживаемый Git TOML для сборки;
  • release_id — новый неизменяемый ID;
  • generation — новый номер поколения;
  • dry_run — только проверить план или выполнить публикацию.
Для self-hosted Windows runner настройте secrets:
И repository variable:
Сначала запускайте workflow с dry_run = true. После проверки повторите с теми же release_id/generation и dry_run = false. Активация всё равно остаётся ручным действием в админке.

Проверка после публикации

Минимальный production-чеклист:
  • launcher-server имеет состояние active (running);
  • /health/live и /health/ready возвращают успех;
  • в журнале launcher-server нет S3/signature ошибок;
  • новый релиз отображается в админке как установленный;
  • active release ID изменился только после ручной активации;
  • signed envelope читается публичным launcher API;
  • CDN отдаёт один файл релиза без авторизации и без redirect на S3 console;
  • чистая установка клиента завершается;
  • повторный запуск не скачивает неизменившиеся файлы;
  • Minecraft стартует нужным mainClass и подключается к нужному серверу;
  • откат на предыдущий релиз работает.
Команды для launcher-server:
Для локальной проверки контрактов без production S3:

Частые ошибки

Чего нельзя делать

  • Не публикуйте поверх существующего releaseId.
  • Не уменьшайте и не переиспользуйте generation.
  • Не активируйте релиз до успешной загрузки всех объектов.
  • Не удаляйте прошлый релиз до истечения периода безопасного отката.
  • Не храните credentials или signing seed в Git, TOML сборки и Electron config.
  • Не указывайте S3 origin вместо CDN первым production mirror без осознанной причины.
  • Не добавляйте весь изменяемый пользовательский каталог в updateVerify.
  • Не считайте кнопку «Подготовить» публикацией.

Рекомендуемый рабочий регламент

Для обычного обновления достаточно запомнить короткую последовательность:
Связанные разделы: