Merge phase 23 example pack.
ci / server (push) Failing after 3m32s
ci / client (push) Failing after 12s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 01:12:47 +03:00
co-authored by Cursor
21 changed files with 406 additions and 15 deletions
+6 -1
View File
@@ -218,6 +218,10 @@ create раскладка замораживается вместе с набо
Моды — подпапки на диске сервера, например `mods/<id>/`. Ядро — мод `core`: тот же формат папки,
но **всегда включён**, в UI создания его нельзя снять. Остальные папки — чекбоксы.
Живой образец — [`../../src/HSchool.Server/mods/example/`](../../src/HSchool.Server/mods/example/):
`pack.jsonc`, две черты, набор имён, патч, last-wins и одна комната. Пока его не выбрали, ваниль
не меняется. README внутри папки — как добавить своё.
```
mods/
core/
@@ -227,7 +231,7 @@ mods/
en.jsonc
maps/
default.jsonc # ванильная раскладка
furniture-pack/
example/ # образец, не контент; выключается в create
defs/
patches/ # правки чужих def, не копии
localizations/
@@ -284,6 +288,7 @@ mods/
| Пустая комната | Можно; граф связный, двор всегда в графе |
| Действия | Заготовки в def, без исполнения и без приказов |
| Моды | `mods/<id>/`; `core` всегда первый и не снимается; остальные — UI create |
| Образец пака | `mods/example/`: настоящая папка рядом с `core`, не контент |
| Коллизии имён | Последний пакет победил (defs и локали), warning в лог |
| Наследование | `parent`, `abstract`; поле ребёнка заменяет, не мержит массивы |
| Патчи | `patches/` после наследования; ops: add / replace / remove; неизвестный op — ошибка |
+4 -3
View File
@@ -12,8 +12,9 @@
**Моды существуют на бумаге — остался проверяемый путь.** Удостоверение пака уже есть:
`pack.jsonc` (версия и `requires`), название в локалях по id, `GET /api/mods?lang=` отдаёт
подпись, создание отказывает во внятном коде, если зависимости нет или они замкнуты в цикл.
Порядок загрузки сервер выстраивает сам и кладёт в сейв. В `mods/` по-прежнему лежит один
`core`: last-wins, патчи и дорога «игрок выбрал мод» ждут настоящую папку — это фаза 23.
Порядок загрузки сервер выстраивает сам и кладёт в сейв. Рядом с `core` лежит `mods/example`
маленький скучный пак на диске, чтобы last-wins, патчи и дорога «игрок выбрал мод» проверялись
настоящей папкой, а не документами в памяти.
**Числа поведения живут в коде вопреки [`ai.md`](ai.md).** Там записано: «Числа поведения —
отдельный деф правил, как `StaffingDef` у штата». В `BehaviorDef` уехали порог нужды, скорость
@@ -66,7 +67,7 @@
проверена ни разу.
Пак должен быть виден из тестов хоста, то есть лежать рядом с `core` в `mods/` и ехать в вывод
сборки теми же правилами.
сборки теми же правилами. Живая папка — `src/HSchool.Server/mods/example/`.
## Числа поведения — в `BehaviorDef`
+10 -10
View File
@@ -12,21 +12,21 @@
## Задачи
- [ ] Пак `mods/example` рядом с `core`: `pack.jsonc`, свои локали, пара черт, набор имён,
- [x] Пак `mods/example` рядом с `core`: `pack.jsonc`, свои локали, пара черт, набор имён,
патч чужого def и одна комната
- [ ] Пак нарочно скучный: он образец и фикстура, а не контент. Ванильную игру он не меняет,
- [x] Пак нарочно скучный: он образец и фикстура, а не контент. Ванильную игру он не меняет,
пока не выбран
- [ ] Пак едет в вывод сборки тестов теми же правилами, что и `core`
- [ ] Короткий `README.md` внутри пака: что где лежит и как добавить своё
- [ ] Ориентир в [`../design/defs.md`](../design/defs.md) показывает на него как на образец
- [x] Пак едет в вывод сборки тестов теми же правилами, что и `core`
- [x] Короткий `README.md` внутри пака: что где лежит и как добавить своё
- [x] Ориентир в [`../design/defs.md`](../design/defs.md) показывает на него как на образец
## Тесты, без которых фаза не закрыта
- [ ] `GET /api/catalog?mods=example` отдаёт типы и подписи пака поверх `core`
- [ ] Школа создаётся с паком и поднимается с ним после перезапуска
- [ ] Патч пака виден в каталоге школы, а без пака его нет
- [ ] Одинаковый `defName` в `core` и в паке — побеждает пак, в логе предупреждение
- [ ] Карта пака проходит валидацию и годится для создания школы
- [x] `GET /api/catalog?mods=example` отдаёт типы и подписи пака поверх `core`
- [x] Школа создаётся с паком и поднимается с ним после перезапуска
- [x] Патч пака виден в каталоге школы, а без пака его нет
- [x] Одинаковый `defName` в `core` и в паке — побеждает пак, в логе предупреждение
- [x] Карта пака проходит валидацию и годится для создания школы
## Критерий готовности
+1 -1
View File
@@ -107,7 +107,7 @@
| Фаза | Статус | Зачем |
| --- | --- | --- |
| [22. Удостоверение пака](22-mod-identity.md) | ✅ | Название, версия, зависимости и порядок загрузки |
| [23. Пример мода](23-example-pack.md) | 🔄 | Настоящая папка вместо документов в памяти |
| [23. Пример мода](23-example-pack.md) | | Настоящая папка вместо документов в памяти |
| [24. Числа поведения](24-behavior-numbers.md) | ✅ | Веса целей в `BehaviorDef`, а не в коде |
| [25. Золотые файлы](25-golden-fixtures.md) | ✅ | Отпечаток ростера, старый сейв, кривая голода, нехватка учителей |
| [26. Свой сид](26-school-seed.md) | ✅ | Состав школы перестаёт зависеть от порядка создания |
+3
View File
@@ -69,6 +69,9 @@ still a pack: the id stands in for the name, `version` is empty, `requires` is e
{ "mods": [{ "id": "core", "required": true, "label": "Базовая игра", "version": "1.0", "requires": [] }] }
```
The repo also ships `example` next to `core` — a sample pack, not required. It appears in this
list with `required: false` and `requires: ["core"]`. Vanilla create omits it.
### `GET /api/catalog?lang=ru|en&mods=addon1,addon2`
Placeable (non-abstract) types plus labels in `lang`, and the last-wins `maps/default.jsonc` for