Update documentation to enhance clarity on native language and skill generation
ci / server (push) Failing after 3m37s
ci / client (push) Successful in 14s

- Revised `AGENTS.md` to specify that the same seed, map, name set, and native language must produce the same roster in tests.
- Updated `protocol.md` to clarify that everyone in the school is generated with the selected native language, and related languages may appear at a low skill.
- Enhanced `ai.md` to explain skill growth mechanics based on state and the introduction of minimum ranges for skills not yet acquired.
- Improved `people.md` to detail the generation of skills and traits, emphasizing that not every person receives every skill and the implications of body attributes on skill acquisition.
- Adjusted `projects.md` to reflect the inclusion of native language in roster generation, ensuring comprehensive documentation of project components.
This commit is contained in:
Leonid Pershin
2026-08-19 22:27:20 +03:00
parent 5a00ad7746
commit a441ed9763
5 changed files with 51 additions and 23 deletions
+2 -2
View File
@@ -108,8 +108,8 @@ say so explicitly in the change description.
- Simulation changes need a `GameClock` or `SchoolRegistry` test. They are fast and need no host.
Putting a roster into `World` and ticking needs belongs there too.
- People generation belongs in `tests/HSchool.People.Tests`. Same seed, map and name set must
produce the same roster; the suite does not boot a host.
- People generation belongs in `tests/HSchool.People.Tests`. Same seed, map, name set and
native language must produce the same roster; the suite does not boot a host.
- Timetable planning belongs in `tests/HSchool.Schedule.Tests`. Same staff, map and locks must
produce the same table; the suite does not boot a host.
- Walking and day plans belong in `tests/HSchool.Ai.Tests`. Same seed and map must produce the
+2 -1
View File
@@ -186,7 +186,8 @@
Осознанно мало:
- **Навык растёт на уроке** — от предмета, с поправкой на черты и на то, в каком человек
состоянии. Голодный учится хуже.
состоянии. Голодный учится хуже. Если ключа ещё нет (химия в восьмом), рост начинается с
`Range.Min`, а не с нуля «как будто навык был всегда».
- **Опоздание и прогул видны.** В кабинете 5Б на математике не двадцать три человека, а
двадцать один, и карточка каждого говорит, где он.
+37 -16
View File
@@ -138,7 +138,9 @@
Пять новых видов. Ссылки — строками `defName`, как везде.
1. **SkillDef** — навык. Диапазон, распределение при генерации, зависимость от возраста,
ограничения со стороны тела (см. ниже).
ограничения со стороны тела (см. ниже). Не каждый человек получает каждый навык:
`always` — у всех, предметы — по параллели ученика, `work` — только взрослым,
`adultChance` — шанс у взрослого поверх родного языка.
2. **TraitDef** — черта. Вес (частота), список несовместимых черт, ограничения по роли и возрасту,
модификаторы навыков.
3. **BodyAttributeDef** — свойство тела. Либо число с распределением (рост, вес), либо выбор из
@@ -153,14 +155,15 @@
| Вид | Ванильное содержание |
| --- | --- |
| Навыки | Школьные предметы (математика, русский, литература, физика, история, физкультура…) и физические (ловкость, сила, выносливость) |
| Навыки | Школьные предметы, языки набора имён, общение, физические (ловкость, сила, выносливость) и рабочие (педагогика, медицина, кухня…) |
| Черты | Около десяти для начала: усидчивый, рассеянный, задира, тихоня, лидер, лентяй, любопытный, вспыльчивый, добрый, аккуратный |
| Тело | Рост, вес, цвет волос, цвет глаз |
| Нужды | Сон, голод, туалет, общение |
Слои одинаковы у всех ролей. У неработающего родителя те же навыки и черты, что у ученика: урезать
их дешевле по памяти и дороже в коде — иначе каждое место, читающее навык, начинается с вопроса
«а есть ли он у этого человека».
Слои одинаковы у всех ролей: у родителя те же *виды* данных, что у ученика. Набор ключей
навыков — нет. Нет ключа — нет навыка, а не ноль: карточка его не показывает, урок, если
предмет всё же начался, стартует с `Range.Min`. Иначе первоклассник носил бы химию «для
полноты», а код всё равно спрашивал бы, есть ли она.
### Как тело ограничивает навыки
@@ -181,9 +184,14 @@
}
```
Генератор сначала бросает тело, потом навык, потом применяет ограничения как зажим. Порядок важен
и фиксируется: **тело первично**, навык подстраивается. Иначе один и тот же сид даст разных людей
в зависимости от порядка перебора.
Генератор сначала бросает тело, потом те навыки, которые человеку положены, потом применяет
ограничения как зажим. Порядок важен и фиксируется: **тело первично**, навык подстраивается.
Иначе один и тот же сид даст разных людей в зависимости от порядка перебора.
Выдача навыков тоже фиксирована: `always` → родной язык школы → предметы параллели (ученик) →
лишние академические, рабочие и `adultChance` (взрослый) → черты и зажим тела → родственные
языки набора. Годовой набор добавляет только новые ключи предметов; уже выданные значения не
перебрасываются.
Ограничения — не только вниз: «атлет не может быть совсем неловким» так же осмысленно, поэтому
`min` есть наравне с `max`.
@@ -208,6 +216,13 @@
**Один набор на школу.** Выбирается в диалоге создания рядом с модами и сохраняется в файле школы.
Смеси с весами («80% славянских, 20% прочих») — не в этом срезе: они требуют UI для весов.
Набор несёт список языков, на которых здесь говорят (`nativeLanguages`). Школа выбирает **один**
при создании — это родной язык всех людей. Остальные языки списка часто появляются на низком
уровне (`relatedLanguageChance` и соседние поля на том же def): русскоязычный может понимать
белорусский. Уже выданный ключ — родной или предмет школы — не перезаписывается, поэтому
белорусский ученик сохраняет школьный русский, а не обрезанный «чуть-чуть». Шанс `0` оставляет
родственников выключенными (одноязычный пакет).
Набор имён **не связан с языком интерфейса**. Английский UI не превращает Иванову в Ivanova:
язык интерфейса — про подписи кнопок, набор имён — про то, кто учится в школе.
@@ -240,13 +255,15 @@ Protocol ← Server → Simulation → People → Content
- **Не** зависит от Arch, ASP.NET и сокетов — как `Content` сейчас.
- Отдаёт простые записи. Превращает их в сущности `World` уже `HSchool.Simulation`.
Так генератор тестируется без мира и без хоста: «этот сид + эта карта + этот набор имён → ровно
эти люди». Это единственный способ поймать регрессию в генераторе — глазами такое не проверяется.
Так генератор тестируется без мира и без хоста: «этот сид + эта карта + этот набор имён + этот
родной язык → ровно эти люди». Это единственный способ поймать регрессию в генераторе — глазами
такое не проверяется.
### Детерминизм
Генерация детерминирована от **сида**, сид лежит в файле школы. Один сид + одна карта + один набор
имён = одна и та же школа, всегда.
имён + один родной язык = одна и та же школа, всегда. Если родной язык при создании не указан,
его выбирает тот же сид — повтор без поля даёт тот же язык.
Сид у каждой семьи свой, выведенный из школьного: добавление тринадцатой семьи не должно менять
первые двенадцать. Иначе тест на генератор ломается от любой правки порядка.
@@ -268,7 +285,8 @@ Protocol ← Server → Simulation → People → Content
Школа создаётся посреди учебного года (по умолчанию 3 апреля), поэтому при создании классы уже
сформированы и возраст ученика соответствует его параллели: в N-й класс ходят те, кому
исполнилось N+6 до 1 сентября.
исполнилось N+6 до 1 сентября. Переход в следующую параллель **добавляет** навыки новых
предметов (английский с пятого, химия с восьмого) и не перебрасывает уже выданные.
## Просмотр
@@ -285,7 +303,8 @@ Protocol ← Server → Simulation → People → Content
- **Сортировки**: фамилия, возраст, параллель, должность.
- **Пейджинг** обязателен: тысяча учеников — это три тысячи человек с семьями.
- **Строка списка** — только лёгкое: ФИО, роль, класс или должность, возраст, пол.
- **Карточка** одного человека — тело, навыки, черты, нужды, семья со ссылками на родных.
- **Карточка** одного человека — тело, навыки (только те, что есть), черты, нужды, семья со
ссылками на родных.
## Масштаб
@@ -357,16 +376,18 @@ Protocol ← Server → Simulation → People → Content
| Телосложение | Производное от роста и веса, не def |
| Тело и навыки | `SkillDef.bodyLimits` зажимают навык; тело бросается первым |
| Влияние характеристик | Никакого; только просмотр |
| Навыки в `core` | Школьные предметы + физические |
| Навыки в `core` | Предметы, языки, общение, физические, рабочие |
| Выдача навыков | Не полный каталог: always, родной, предметы года, взрослые лишние, родственные языки |
| Черты в `core` | Около десяти |
| Нужды в `core` | Сон, голод, туалет, общение |
| Нужды | Машинерия есть, скорость убывания в `core` — ноль |
| Слои по ролям | Одинаковые у всех; родителей не урезаем |
| Слои по ролям | Одинаковые виды данных; ключи навыков зависят от роли и возраста |
| Набор имён | Один на школу, выбор в create, в `core` славянский; прочие — моды |
| Родной язык | Один из `nativeLanguages` набора, выбор в create; остальные языки списка — часто низкий навык |
| Падежи | Правило по умолчанию (код), явная таблица как исключение (данные) |
| Имена и язык UI | Независимы |
| Библиотека | `HSchool.People`: зависит от Content, не знает Arch и ASP.NET |
| Детерминизм | Сид в сейве, свой сид на семью |
| Детерминизм | Сид в сейве, свой сид на семью; родной язык — часть входа |
| Просмотр | Панель в оболочке менеджера, нижний ряд; не отдельный экран |
| Список | Фильтры, сортировки, пейджинг; в строке — только лёгкие поля |
| Транспорт списка | HTTP по опубликованному снимку ростера |
+1 -1
View File
@@ -23,7 +23,7 @@ Client — своя сторона Protocol (TS) + HTTP
| Проект | Да | Нет |
| --- | --- | --- |
| **HSchool.Content** | Типы def, JSONC-загрузчик, наследование, патчи, слияние локалей, граф карты, валидация связности | Arch, часы, HTTP, потоки, пути `mods/` с диска хоста |
| **HSchool.People** | Генерация ростера: семьи, классы, тело/навыки/черты из каталога и сида | Arch, ASP.NET, сокеты, `DateTime.Now`, файлы сейва |
| **HSchool.People** | Генерация ростера: семьи, классы, тело/навыки/черты из каталога, сида и родного языка школы | Arch, ASP.NET, сокеты, `DateTime.Now`, файлы сейва |
| **HSchool.Schedule** | Раскладка учебного плана в таблицу уроков вокруг закреплённых правок | Arch, ASP.NET, сокеты, `DateTime.Now`, файлы сейва |
| **HSchool.Ai** | Маршруты по графу карты, план дня человека, выбор цели и действия, продвижение плана во времени | Arch, ASP.NET, сокеты, `DateTime.Now`, файлы сейва |
| **HSchool.Simulation** | `School`, `GameClock`, Arch `World`, тик, применение раскладки к миру, адаптер к `Ai` | Kestrel, сокеты, `Directory.Enumerate`, сейв-файлы |
+9 -3
View File
@@ -80,7 +80,10 @@ total is computed on the server.
`nameSets` is the list of placeable name packs (`defName` + label + `nativeLanguages`). Each
`nativeLanguages` entry is a skill (`defName` + label). The create dialog picks a name set and a
native language; the language list comes from that set (vanilla Slavic: Russian, Belarusian,
Ukrainian). It is independent of the UI language.
Ukrainian). It is independent of the UI language. Everyone in the school is generated with that
native. Other languages of the same set often appear at a low skill — a Russian speaker who
understands Belarusian. Those rolls live on the `NameSetDef` (`relatedLanguageChance` and
neighbours), not on this catalog payload.
`subjects` is the list of placeable subjects (`defName`, label, `gradeMin`/`gradeMax`,
`hoursPerWeek`, `skills` with shares, and optional `room`). `room` is the RoomDef the lesson
@@ -227,6 +230,9 @@ grid fetches `GET .../timetable?classId=` with it.
`activity` is the ActionDef name currently in progress, or `null` when idle. `activityLabel`
is that def in the request locale. HTTP JSON is additive — no protocol version bump.
`skills` lists only keys the person has, not every `SkillDef` in the catalog. A first-year has
no Chemistry; a related tongue from the name set may sit beside the native at a low value.
```json
{
"id": "f0.c0",
@@ -329,8 +335,8 @@ those lessons will not happen.
Applicants here are the same people as in `saves/{id}.people.json`. A parent keeps the same
id on the roster; hiring them sets `isStaff` on that person and does not create a second
entity. Generated candidates (`aN.p0`) join the roster only when hired. `skills` on an
applicant are the three strongest, for the management list; the full set is on the person
card. `positions` and `subjects` are the school's catalog, so the hire and assign pickers
applicant are the three strongest, for the management list; the card lists every skill they
have, not the three strongest. `positions` and `subjects` are the school's catalog, so the hire and assign pickers
do not need a second request.
`GET /api/schools/{id}/people/{personId}` also opens a card for someone who is only in the