95 lines
5.5 KiB
Markdown
95 lines
5.5 KiB
Markdown
# SeasonalBuildService
|
||
|
||
`seasonalbuildservice.h`, `seasonalbuildservice.cpp`
|
||
|
||
Каталог сезонных сборок, то есть готовых паков, которые команда публикует на своём файловом
|
||
сервере. Сервис читает `<baseUrl>/index.json`, хранит копию в
|
||
`<root>/cache/seasonal_builds.json` и отвечает из неё 15 минут.
|
||
|
||
Экземпляр держит [LauncherBackend](LauncherBackend.md). Он же сводит строки каталога с
|
||
установленными сборками и ставит выбранную.
|
||
|
||
## Адрес сервера
|
||
|
||
По умолчанию `https://launcher-builds.galeonworx.com`. Переопределяется ключом `seasonalBaseUrl` в
|
||
`settings.json`, например чтобы проверить установку на локальном HTTP-сервере. Бэкенд передаёт
|
||
адрес через `setBaseUrl()` при старте и перед каждым `refreshSeasonalCatalog()`.
|
||
|
||
Если адрес сменился, накопленные данные сбрасываются, а кэш с другим `baseUrl` не читается: ссылки
|
||
в нём ведут на старый сервер. Пустой адрес или адрес без хоста — сразу ошибка.
|
||
|
||
## Формат index.json
|
||
|
||
Это контракт с теми, кто публикует сборки.
|
||
|
||
```json
|
||
{
|
||
"formatVersion": 1,
|
||
"builds": [
|
||
{
|
||
"id": "season-5",
|
||
"name": "Сезон 5: Пустоши",
|
||
"revision": 3,
|
||
"minecraftVersion": "1.20.1",
|
||
"loader": "forge",
|
||
"loaderVersion": "47.4.0",
|
||
"modCount": 142,
|
||
"seasonStart": "2026-09-01",
|
||
"seasonEnd": "",
|
||
"serverUrl": "play.example.com:25565",
|
||
"javaMajor": 17,
|
||
"description": "…",
|
||
"archive": {
|
||
"url": "https://launcher-builds.galeonworx.com/season-5/r3.zip",
|
||
"size": 734003200,
|
||
"sha256": "…64 hex…"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
| Поле | Обязательно | Правила |
|
||
|------|-------------|---------|
|
||
| `formatVersion` | да | только `1`. Другое значение — весь каталог отклоняется с понятным текстом (если версия больше, пользователю предложат обновить лаунчер) |
|
||
| `id` | да | `[a-z0-9][a-z0-9._-]{0,63}`. По нему лаунчер узнаёт уже установленную сборку, менять его нельзя |
|
||
| `name` | да | |
|
||
| `revision` | да | > 0. Увеличивается при каждой публикации. Если у игрока ревизия меньше, ему покажут «доступно обновление» |
|
||
| `minecraftVersion` | да | без `/`, `\`, `:`, не длиннее 128 символов |
|
||
| `loader` | нет | пусто (ваниль) или `forge`, `fabric`, `neoforge`, `quilt` |
|
||
| `loaderVersion` | если есть `loader` | |
|
||
| `modCount` | нет | для таблицы |
|
||
| `seasonStart`, `seasonEnd` | нет | ISO-даты. Пустой `seasonEnd` значит, что сезон идёт |
|
||
| `serverUrl` | нет | адрес игрового сервера для автоподключения |
|
||
| `javaMajor` | нет | 0 или нет поля — определить по версии игры |
|
||
| `description` | нет | показывается под таблицей |
|
||
| `archive.url` | да | `http` или `https`, **та же схема, хост и порт, что у `baseUrl`** |
|
||
| `archive.size` | да | ≥ 0 |
|
||
| `archive.sha256` | да | 64 hex-символа |
|
||
|
||
Записи, которые не проходят проверку, молча пропускаются. Если не осталось ни одной, это считается
|
||
испорченным ответом, и хороший кэш не затирается.
|
||
|
||
Требование «тот же хост» не даёт подложить в каталог ссылку на чужой сервер. Пак распаковывается
|
||
прямо в `.minecraft`, поэтому качать его откуда попало нельзя.
|
||
|
||
Пак — это zip, содержимое которого раскладывается в корень `.minecraft` (`mods/`, `config/` и т. п.).
|
||
Файлы в `versions/`, `libraries/`, `assets/`, `runtime/` и `launcher_profiles.json` запрещены, пак
|
||
с ними не установится. Подробнее — [BuildArchiveWorker](BuildArchiveWorker.md).
|
||
|
||
Порядок в каталоге: сначала идущие сезоны, потом по дате начала (новые сверху), потом по имени.
|
||
|
||
## Интерфейс
|
||
|
||
- `ensureLoaded(callback, forceRefresh)` — как у
|
||
[VersionManifestService](VersionManifestService.md), только кэш живёт 15 минут.
|
||
- `builds()`, `find(id)`, `hasData()`, `isRefreshing()`.
|
||
- `lastError()` — текст последней ошибки сервера или пустая строка. Окно сезонных сборок
|
||
показывает его на месте таблицы.
|
||
- Сигналы `buildsChanged()` (в том числе после неудачного запроса, чтобы обновился `lastError`) и
|
||
`refreshingChanged()`.
|
||
|
||
---
|
||
|
||
При создании этого документа использовался ИИ.
|