Remove off-queue.md and add new design documentation files including README.md, defs.md, near-term.md, projects.md, runtime.md, people.md, staffing.md, and schedule.md to outline the structure and agreements for the game's design phases.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
Договорённость на ближайшее планирование, не текущий код.
|
||||
Экран игрока: [`near-term.md`](near-term.md). Потоки: [`runtime.md`](runtime.md).
|
||||
Проекты: [`projects.md`](projects.md). Как устроен хост сейчас: [`../architecture.md`](../architecture.md).
|
||||
Проекты: [`projects.md`](projects.md). Как устроен хост сейчас: [`../architecture.md`](../../architecture.md).
|
||||
|
||||
Идея как у RimWorld: **ядро — код систем**, содержание игры — **данные (defs)**. Новый стул, кабинет
|
||||
или действие, которое уже умеет код, появляются без пересборки `HSchool.Simulation`. Сборка нужна,
|
||||
@@ -1,7 +1,7 @@
|
||||
# Ближайший горизонт: что видит игрок
|
||||
|
||||
Это не текущее состояние кода, а договорённости на ближайшее планирование.
|
||||
Как устроено сейчас — в [`architecture.md`](../architecture.md).
|
||||
Как устроено сейчас — в [`architecture.md`](../../architecture.md).
|
||||
|
||||
## Решение: не PixiJS, а менеджер на DOM
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Люди: генерация, характеристики, просмотр
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Типы и карта: [`defs.md`](defs.md). Экран игрока: [`near-term.md`](near-term.md).
|
||||
Потоки: [`runtime.md`](runtime.md). Проекты: [`projects.md`](projects.md).
|
||||
Типы и карта: [`defs.md`](../01-shell/defs.md). Экран игрока: [`near-term.md`](../01-shell/near-term.md).
|
||||
Потоки: [`runtime.md`](../01-shell/runtime.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
|
||||
Школа перестаёт быть пустой коробкой. Появляются ученики, работники и родители: у каждого имя,
|
||||
тело, навыки, черты и нужды. **Ничего из этого пока ни на что не влияет** — люди не ходят, не
|
||||
@@ -209,7 +209,7 @@
|
||||
Скорость — данные, не код. Когда появится еда и сон, цифра меняется в JSONC, а не в C#.
|
||||
|
||||
Отменено срезом 5: в `core` ненулевой `decayPerHour`, сон и голод восстанавливаются вне школы,
|
||||
см. [`ai.md`](ai.md).
|
||||
см. [`ai.md`](../05-ai/ai.md).
|
||||
|
||||
## Имена
|
||||
|
||||
@@ -343,16 +343,16 @@ Protocol ← Server → Simulation → People → Content
|
||||
- Не отправлять черты и навыки в списке — только в карточке. Список читают глазами, карточку
|
||||
открывают по одному человеку.
|
||||
- Сид на семью, а не один на школу: иначе любая правка генератора переставит всех.
|
||||
- Ненулевую скорость нужд не включать, пока нечем их восполнять — сделано срезом 5, см. [`ai.md`](ai.md).
|
||||
- Ненулевую скорость нужд не включать, пока нечем их восполнять — сделано срезом 5, см. [`ai.md`](../05-ai/ai.md).
|
||||
|
||||
## Заведомо не сейчас
|
||||
|
||||
Срез 2 закрыт. Строки, которые отменили следующие срезы, помечены.
|
||||
|
||||
- Поведение: расписание, уроки, перемещение по карте — отменено срезами 4–5, см. [`schedule.md`](schedule.md), [`ai.md`](ai.md).
|
||||
- Поведение: расписание, уроки, перемещение по карте — отменено срезами 4–5, см. [`schedule.md`](../04-schedule/schedule.md), [`ai.md`](../05-ai/ai.md).
|
||||
- Влияние характеристик на что-либо. Черты и навыки в этом срезе — текст в карточке — отменено срезом 5 (маршрут, обучение).
|
||||
- Вызов родителя в школу. Задел есть (родитель — сущность), реализации нет.
|
||||
- Наём и увольнение вручную. Должности закрываются генератором — отменено срезом 3, см. [`staffing.md`](staffing.md). Школа открывается без штата.
|
||||
- Наём и увольнение вручную. Должности закрываются генератором — отменено срезом 3, см. [`staffing.md`](../03-staffing/staffing.md). Школа открывается без штата.
|
||||
- Смеси наборов имён с весами.
|
||||
- Новые роли из модов: ученик, работник, родитель — код, не данные.
|
||||
- Портреты и любой арт.
|
||||
@@ -391,7 +391,7 @@ Protocol ← Server → Simulation → People → Content
|
||||
| Выдача навыков | Не полный каталог: always, родной, предметы года, взрослые лишние, родственные языки |
|
||||
| Черты в `core` | Около десяти |
|
||||
| Нужды в `core` | Сон, голод, туалет, общение |
|
||||
| Нужды | Машинерия есть; убывание в `core` — срез 5, не ноль, см. [`ai.md`](ai.md) |
|
||||
| Нужды | Машинерия есть; убывание в `core` — срез 5, не ноль, см. [`ai.md`](../05-ai/ai.md) |
|
||||
| Слои по ролям | Одинаковые виды данных; ключи навыков зависят от роли и возраста |
|
||||
| Набор имён | Один на школу, выбор в create, в `core` славянский; прочие — моды |
|
||||
| Родной язык | Один из `nativeLanguages` набора, выбор в create; остальные языки списка — часто низкий навык |
|
||||
@@ -1,8 +1,8 @@
|
||||
# Наём, предметы и бюджет
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md).
|
||||
Экран игрока: [`near-term.md`](near-term.md). Проекты: [`projects.md`](projects.md).
|
||||
Люди: [`people.md`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md).
|
||||
Экран игрока: [`near-term.md`](../01-shell/near-term.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
|
||||
Первый срез, где игрок **что-то решает**. До сих пор школа собиралась сама: генератор закрывал
|
||||
все должности, игрок смотрел. Теперь школа открывается пустой — без единого учителя, — и её
|
||||
@@ -49,7 +49,7 @@
|
||||
- **сколько часов в неделю** в каждой из них — учебный план.
|
||||
|
||||
Часы здесь не задел на расписание, а рабочая величина уже этого среза: из них считается нагрузка
|
||||
учителя, а из нагрузки — зарплата. Расписание ([`schedule.md`](schedule.md)) только расставит эти
|
||||
учителя, а из нагрузки — зарплата. Расписание ([`schedule.md`](../04-schedule/schedule.md)) только расставит эти
|
||||
часы по дням; сколько их — решает учебный план.
|
||||
|
||||
Так «начальные классы» получаются естественно: один предмет, который развивает всё понемногу и
|
||||
@@ -89,7 +89,7 @@
|
||||
на каждый предмет, преподаваемый в существующих параллелях, нужен хотя бы один учитель.
|
||||
|
||||
Нетренерские должности — директор, секретарь, медсестра, библиотекарь, повар — по-прежнему рождаются
|
||||
из комнат, как описано в [`defs.md`](defs.md). Их игрок тоже нанимает, но предметов им не назначают.
|
||||
из комнат, как описано в [`defs.md`](../01-shell/defs.md). Их игрок тоже нанимает, но предметов им не назначают.
|
||||
|
||||
## Соискатели
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
## Заведомо не сейчас
|
||||
|
||||
- Само расписание: когда именно идут эти часы. Следующий срез, [`schedule.md`](schedule.md).
|
||||
- Само расписание: когда именно идут эти часы. Следующий срез, [`schedule.md`](../04-schedule/schedule.md).
|
||||
Здесь предмет — нагрузка в часах, а не событие в кабинете.
|
||||
- Уроки, звонки, оценки, посещаемость.
|
||||
- Классное руководство: класс закреплён за кабинетом, но не за учителем.
|
||||
@@ -1,8 +1,8 @@
|
||||
# Расписание
|
||||
|
||||
Договорённость на срез после штата, не текущий код.
|
||||
Штат и предметы: [`staffing.md`](staffing.md). Люди: [`people.md`](people.md).
|
||||
Типы и карта: [`defs.md`](defs.md). Экран: [`near-term.md`](near-term.md).
|
||||
Штат и предметы: [`staffing.md`](../03-staffing/staffing.md). Люди: [`people.md`](../02-people/people.md).
|
||||
Типы и карта: [`defs.md`](../01-shell/defs.md). Экран: [`near-term.md`](../01-shell/near-term.md).
|
||||
|
||||
Часы из учебного плана раскладываются по дням и кабинетам. Школа впервые начинает **жить по
|
||||
времени**: в 10:15 у 5Б математика в кабинете 204, и это видно на карте.
|
||||
@@ -140,9 +140,9 @@
|
||||
| Место урока | Кабинет класса, если у предмета нет требования к типу помещения |
|
||||
| Нет учителя | Урок не ставится; предмет числится непокрытым |
|
||||
| Карта | В дереве рядом с комнатой — что и у кого там сейчас |
|
||||
| Панель локации | «Сейчас» и «Персонажи» заполняются из расписания — с срезом 5 из присутствия, см. [`ai.md`](ai.md) |
|
||||
| Панель локации | «Сейчас» и «Персонажи» заполняются из расписания — с срезом 5 из присутствия, см. [`ai.md`](../05-ai/ai.md) |
|
||||
| Расписание класса | В разделе «Управление», сетка «день × урок» |
|
||||
| Расписание учителя | В его карточке, там же где навыки и семья |
|
||||
| Общая сетка школы | Не делаем: её читает только тот, кто раскладывает вручную |
|
||||
| Где живёт код | Отдельная библиотека рядом с `HSchool.People` |
|
||||
| Люди и место | Находятся по расписанию; ходьбы нет — отменено срезом 5, присутствие стало состоянием ([`ai.md`](ai.md)) |
|
||||
| Люди и место | Находятся по расписанию; ходьбы нет — отменено срезом 5, присутствие стало состоянием ([`ai.md`](../05-ai/ai.md)) |
|
||||
@@ -1,8 +1,8 @@
|
||||
# Жизнь школы
|
||||
|
||||
Договорённость на срез после расписания, не текущий код.
|
||||
Расписание: [`schedule.md`](schedule.md). Штат: [`staffing.md`](staffing.md).
|
||||
Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md). Экран: [`near-term.md`](near-term.md).
|
||||
Расписание: [`schedule.md`](../04-schedule/schedule.md). Штат: [`staffing.md`](../03-staffing/staffing.md).
|
||||
Люди: [`people.md`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md). Экран: [`near-term.md`](../01-shell/near-term.md).
|
||||
|
||||
Люди начинают **ходить и решать**. До сих пор человек находился там, где его застало расписание;
|
||||
теперь он приходит утром, идёт коридором в кабинет, может уйти с урока в туалет и вернуться —
|
||||
@@ -129,7 +129,7 @@
|
||||
не сидят вдвоём. Это связывает мебель на карте с поведением, а не только с вместимостью класса.
|
||||
|
||||
Так мод добавляет поведение, не написав ни строчки кода, — ровно как обещано в
|
||||
[`defs.md`](defs.md).
|
||||
[`defs.md`](../01-shell/defs.md).
|
||||
|
||||
**Обязанности из каталога действий не выбирают.** Урок приходит из расписания, работа по
|
||||
должности — из `RoomDef.works`, который уже проставлен в `core` (`TeachLesson` у кабинета,
|
||||
@@ -1,8 +1,8 @@
|
||||
# Одежда, вещи и климат
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md). Жизнь школы: [`ai.md`](ai.md).
|
||||
Экран: [`near-term.md`](near-term.md). Проекты: [`projects.md`](projects.md).
|
||||
Люди: [`people.md`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md). Жизнь школы: [`ai.md`](../05-ai/ai.md).
|
||||
Экран: [`near-term.md`](../01-shell/near-term.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
|
||||
У человека появляется то, что на нём надето и что он несёт. Школа получает климат и правила
|
||||
одежды. Игрок это **смотрит** и выбирает правила; надевает не он — система сама приводит гардероб
|
||||
@@ -1,8 +1,8 @@
|
||||
# Сессия и темп
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Оболочка: [`near-term.md`](near-term.md). Рантайм: [`runtime.md`](runtime.md).
|
||||
Протокол: [`../protocol.md`](../protocol.md).
|
||||
Оболочка: [`near-term.md`](../01-shell/near-term.md). Рантайм: [`runtime.md`](../01-shell/runtime.md).
|
||||
Протокол: [`../protocol.md`](../../protocol.md).
|
||||
|
||||
Один процесс сервера, несколько браузеров в локальной сети. Это не аккаунты и не интернет:
|
||||
общий пароль альфы пускает к двери, имя отличает игроков. Школу по-прежнему тикает её работник,
|
||||
@@ -1,8 +1,8 @@
|
||||
# Общение, отношения и романтический пак
|
||||
|
||||
Договорённость на срез после сессии/темпа, не текущий код.
|
||||
Люди: [`people.md`](people.md). ИИ: [`ai.md`](ai.md). Одежда (уместность как образец):
|
||||
[`inventory.md`](inventory.md). Моды: [`defs.md`](defs.md), [`foundation.md`](foundation.md).
|
||||
Люди: [`people.md`](../02-people/people.md). ИИ: [`ai.md`](../05-ai/ai.md). Одежда (уместность как образец):
|
||||
[`inventory.md`](../07-inventory/inventory.md). Моды: [`defs.md`](../01-shell/defs.md), [`foundation.md`](../06-foundation/foundation.md).
|
||||
|
||||
У человека появляется, **с кем** он говорит и **что** о нём думают другие. Нужда «общение» уже
|
||||
есть, действие `Chat` уже есть — но это соло в коридоре. Срез делает разговор кружком, тему —
|
||||
@@ -1,8 +1,8 @@
|
||||
# Ремесло: слои, страховка тестов, горячие точки
|
||||
|
||||
Договорённость на срез после одежды, сессии и склейки урока, не текущий код.
|
||||
Фундамент: [`foundation.md`](foundation.md). Проекты: [`projects.md`](projects.md).
|
||||
Вне очереди: [`off-queue.md`](off-queue.md). Общение (не ждём 44/46): [`social.md`](social.md).
|
||||
Фундамент: [`foundation.md`](../06-foundation/foundation.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
Вне очереди: [`off-queue.md`](../off-queue/README.md). Общение (не ждём 44/46): [`social.md`](../09-social/social.md).
|
||||
|
||||
Игра уже живая: люди ходят, одеваются, учатся, болтают. Рядом лежат четыре копии одного
|
||||
запрета на ссылки, `npm test` зелёный при красном `tsc`, работник школы на тысячу строк и
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
## На какие вопросы отвечает
|
||||
|
||||
- Слои из [`projects.md`](projects.md) и инвариант 4 — тест в одном месте, не четыре копипасты.
|
||||
- Слои из [`projects.md`](../01-shell/projects.md) и инвариант 4 — тест в одном месте, не четыре копипасты.
|
||||
- `npm test` клиента = typecheck + vitest; дубликат в `strings.ts` красный без `npm run build`.
|
||||
- `SchoolWorker` и сборка карточки режутся по швам, поведение то же.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
- Новых экранов, полей сейва, байтов сокета.
|
||||
- Фаз 44 и 46, портретов/SwarmUI как фичи, `GET /api/catalog.lunchBreaks`.
|
||||
- Багов сессии (второе имя при живой куке, ключи DataProtection) — [`../bugs/README.md`](../bugs/README.md).
|
||||
- Багов сессии (второе имя при живой куке, ключи DataProtection) — [`../bugs/README.md`](../../bugs/README.md).
|
||||
- Инверсии Game → Api DTO и «пройти SOLID по всему дереву».
|
||||
|
||||
## Что меняется в уже принятом
|
||||
@@ -50,7 +50,7 @@
|
||||
`GetReferencedAssemblies` и чтение `*.cs`. Копии `Assembly_DoesNotReference*` и `Sources_DoNotUseWallClock`
|
||||
из People/Ai/Schedule/Simulation уезжают сюда.
|
||||
|
||||
Список (как [`projects.md`](projects.md)):
|
||||
Список (как [`projects.md`](../01-shell/projects.md)):
|
||||
|
||||
| Сборка | Не ссылается | Не содержит в исходниках |
|
||||
| --- | --- | --- |
|
||||
@@ -0,0 +1,17 @@
|
||||
# Дизайн
|
||||
|
||||
Договорённости срезов. Не читать целиком: открой папку среза.
|
||||
|
||||
| Срез | Папка |
|
||||
| --- | --- |
|
||||
| 1. Оболочка и карта | [01-shell](01-shell/) |
|
||||
| 2. Люди | [02-people](02-people/people.md) |
|
||||
| 3. Штат | [03-staffing](03-staffing/staffing.md) |
|
||||
| 4. Расписание | [04-schedule](04-schedule/schedule.md) |
|
||||
| 5. Жизнь школы | [05-ai](05-ai/ai.md) |
|
||||
| 6. Фундамент | [06-foundation](06-foundation/foundation.md) |
|
||||
| 7. Одежда, вещи и климат | [07-inventory](07-inventory/inventory.md) |
|
||||
| 8. Сессия и темп | [08-session](08-session/session.md) |
|
||||
| 9. Общение и романтический пак | [09-social](09-social/social.md) |
|
||||
| 10. Ремесло | [10-craft](10-craft/craft.md) |
|
||||
| Вне очереди | [off-queue](off-queue/) |
|
||||
@@ -1,178 +0,0 @@
|
||||
# Вне очереди
|
||||
|
||||
Задачи, которых нет в нумерованных срезах. Срез 10 — ремесло
|
||||
([`craft.md`](craft.md)), не сюда. Сюда — склейка уже живых систем и мелкий DX. После любой
|
||||
фазы школа целая.
|
||||
|
||||
Люди: [`people.md`](people.md). Штат: [`staffing.md`](staffing.md). Расписание:
|
||||
[`schedule.md`](schedule.md). Присутствие: [`ai.md`](ai.md). Одежда и климат:
|
||||
[`inventory.md`](inventory.md).
|
||||
|
||||
## Связность урока
|
||||
|
||||
Урок уже растёт навык, если ученик стоит в кабинете и не голоден. Рядом лежат числа, которые
|
||||
игрок видит и которые на этот рост не влияют: учитель в туалете, навык учителя, тепло,
|
||||
учебник в сумке, снег на дороге.
|
||||
|
||||
Этот кусок отвечает на вопрос «почему нанимать сильного, чинить тепло и класть учебник в
|
||||
сумку». Оценок, посещаемости как журнала и приказов нет.
|
||||
|
||||
### Что меняется в уже принятом
|
||||
|
||||
| Было | Стало | Почему |
|
||||
| --- | --- | --- |
|
||||
| Ученик в кабинете качает навык, учитель может быть где угодно | Рост только если назначенный учитель стоит в том же узле и не идёт | Зазор «обязанность / место» уже есть; урок его не смотрел |
|
||||
| Зарплата зависит от навыков, урок — нет | Навык учителя по предмету масштабирует `Gain` | Иначе «математика 78» в пуле — только цена |
|
||||
| Голод режет урок, тепло — нет | Та же `NeedFactor` на тепло | Полоска уже живая; [`inventory.md`](inventory.md) откладывал штраф |
|
||||
| Учебники сегодняшних предметов едут в сумке | Нет в сумке на этом уроке — половинный рост | Переноска и шкафчик иначе остаются двумя числами |
|
||||
| Погода одевает, на приход не влияет | Дождь и снег добавляют минуты к запасу на дорогу | Часы уже показывают осадки; ленивый уже опаздывает от черты |
|
||||
|
||||
### Формула
|
||||
|
||||
`HSchool.Ai.LessonLearning.Gain` по-прежнему чистое число. Множители:
|
||||
|
||||
- **нужды** — `NeedFactor(голод) × NeedFactor(тепло)`; нет нужды в каталоге — множитель 1;
|
||||
- **черты ученика** — как сейчас;
|
||||
- **учитель** — `NeedFactor(навык / 100)`, навык — среднее по `SubjectDef.skills` у учителя,
|
||||
нет ключа — `Range.Min` этого навыка; учителя нет в комнате — множитель 0, рост не пишется;
|
||||
- **учебник** — 1, если в сумке есть экземпляр с `subject` этого урока; иначе
|
||||
`BehaviorDef.lessonNoTextbookFactor` (ваниль 0.5).
|
||||
|
||||
Учитель «стоит в комнате»: `NodeId` = кабинет урока, путь пуст, остаток минут 0. Действие
|
||||
учителя не отменяет урок (дежурство — не `ActionDef`). Нет человека с этим id — учителя нет.
|
||||
|
||||
Дорога: к нынешнему `SlackMinutes` (черты + бросок) прибавляются минуты из
|
||||
`BehaviorDef.commuteRainMinutes` / `commuteSnowMinutes`, если в момент сборки плана дня на
|
||||
улице дождь или снег. `HSchool.Ai` осадки не знает — симуляция передаёт уже посчитанные минуты.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
Числа на карточке. Плюс строка в сегодняшней истории, **один раз на ключ в сутки**, не каждый
|
||||
тик:
|
||||
|
||||
| Тип | Когда | `thingDef` |
|
||||
| --- | --- | --- |
|
||||
| `lesson-no-teacher` | Урок шёл, учителя не было в кабинете | предмет |
|
||||
| `lesson-cold` | На уроке, который иначе учил, тепло ниже `needThreshold` | предмет |
|
||||
| `lesson-no-textbook` | На уроке нет учебника этого предмета в сумке | предмет |
|
||||
|
||||
Опоздание из-за снега в лог не пишем: весь состав получил бы одну и ту же строку, а место
|
||||
человека и так видно.
|
||||
|
||||
Клиент по-прежнему рисует `label` с сервера. Сокет и сейв не меняются. Версию протокола не
|
||||
бампить.
|
||||
|
||||
### Где живёт код
|
||||
|
||||
Нового проекта нет. Формула и план дня — `HSchool.Ai`. Присутствие учителя, тепло, сумка,
|
||||
погода на входе в план — `HSchool.Simulation`. Подписи лога — каталог. Список типов —
|
||||
`docs/protocol.md` (HTTP лога).
|
||||
|
||||
### Заведомо не сейчас
|
||||
|
||||
- Оценки, журнал посещаемости, выговор за прогул.
|
||||
- Перегруз замедляет ходьбу.
|
||||
- Насмешки над формой и мнения — срез 9.
|
||||
- Вызов родителей, деньги за одежду, болезнь от промокания.
|
||||
- Клиент сам считает «учится хуже».
|
||||
|
||||
### Зафиксировано этим разговором
|
||||
|
||||
| Тема | Решение |
|
||||
| --- | --- |
|
||||
| Нарезка | Пять фаз во «Вне очереди», не срез 10 |
|
||||
| Стоп | После каждой фазы школа целая |
|
||||
| Протокол | Не бампить; новые `type` только в HTTP лога |
|
||||
| Сейв | Не трогать |
|
||||
| Учитель на уроке | Тот же узел, не идёт; нет id — нет роста |
|
||||
| Навык учителя | Среднее по скиллам предмета, та же кривая что у нужды |
|
||||
| Тепло | Рядом с голодом, произведение двух `NeedFactor` |
|
||||
| Учебник | Только сумка, не шкафчик и не дом; ваниль ×0.5 |
|
||||
| Погода на дорогу | Минуты в `BehaviorDef`; лога нет |
|
||||
|
||||
## Пропуск сборки при запуске
|
||||
|
||||
### Зачем
|
||||
|
||||
`run-aspire.cmd` каждый раз вызывает `dotnet run`, а тот — MSBuild графа Aspire, даже когда
|
||||
исходники не менялись. Повторный запуск после Ctrl+C стоит десятки секунд впустую: SDK
|
||||
пересчитывает хост, хотя dll на месте.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Скрипт всегда `dotnet run --project src/HSchool.AppHost`. Аргументы проходили насквозь.
|
||||
|
||||
**Стало.** Если `HSchool.AppHost.dll` и `HSchool.Server.dll` новее входов (C#, csproj, props,
|
||||
`global.json`), скрипт делает `dotnet run --no-build`. Иначе — `dotnet build`, потом `--no-build`.
|
||||
`--rebuild` собирает всегда. Конфигурация (`-c` / `--configuration`) выбирает, какие dll сравнивать;
|
||||
по умолчанию Debug, как у `dotnet run`.
|
||||
|
||||
**Почему.** Инкрементальный MSBuild всё равно оценивает Aspire SDK. `--no-build` это пропускает.
|
||||
Клиентский TypeScript и JSONC модов не входы: Vite и каталог читают диск (`ContentRoot`), а не
|
||||
`bin`. Тестовые проекты AppHost не ссылается — их правки запуск не пересобирают.
|
||||
|
||||
Правила «устарел ли билд» живут в `tools/apphost-uptodate.ps1` (то, что вызывает `run-aspire.ps1`) и в
|
||||
`LaunchBuildStamp` (то, что проверяют тесты). Менять надо оба.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Голый `dotnet run --project src/HSchool.AppHost` по-прежнему собирает — так удобнее агентам с
|
||||
грязным деревом. Linux-обёртки нет: точка входа Windows — `.cmd`. Протокол, HTTP и сейв не
|
||||
трогаем.
|
||||
|
||||
## Что нового после входа
|
||||
|
||||
### Зачем
|
||||
|
||||
Альфа обновляется часто. Игрок не смотрит git: если с прошлого захода в этот браузер накатили
|
||||
другую сборку Server, один раз показать, что вошло в неё.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Нет версии сборки на экране. Сессионная кука HttpOnly и про вход.
|
||||
|
||||
**Стало.** Сборка Server вшивает `HEAD` и `git log --first-parent`. `GET /api/changelog?since=`
|
||||
отдаёт текущий SHA и коммиты после якоря. Клиент держит `hschool.seen-rev` (год, `Path=/`,
|
||||
`SameSite=Lax`, не HttpOnly). Первый заход без куки окно не показывает — только запоминает
|
||||
текущий SHA. Окно — после входа, не при возврате из школы.
|
||||
|
||||
**Почему.** «Накатанный» — то, что в dll, а не грязный HEAD при `--no-build`. First-parent после
|
||||
`--no-ff` — это слитые фазы, не внутренняя нарезка ветки. `Mark phase N` оставляем в цепочке
|
||||
якорем, в список не рисуем: иначе кука на таком HEAD потеряла бы следующее слияние.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Ручной `CHANGELOG.md`. Запись на пользователе в `users.json`. Вызов git из бегущего процесса.
|
||||
Бамп версии сокета. Окно внутри открытой школы.
|
||||
|
||||
## Состояние экрана
|
||||
|
||||
### Зачем
|
||||
|
||||
Менеджер — списки с фильтрами. Сейчас они живут только в RAM: F5 всегда меню, повторный вход
|
||||
сбрасывает вкладки и запросы. Игрок сравнивает людей и соискателей; потерять «ученики 5А» на
|
||||
обновлении — дырка в уже живых экранах, не новая фича.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** SPA без адреса. `GameScreen.show` и `PeoplePanel.show` обнуляют вкладки, фильтры и
|
||||
выбор. Язык уже в `localStorage`; игровые часы — на сервере.
|
||||
|
||||
**Стало.** Query URL держит *где я*: школа, обзор/управление, карта/люди, выбранные комната и
|
||||
человек. `sessionStorage` по `schoolId` держит фильтры, поиски, сорт, страницу, вкладку карточки
|
||||
и класс сетки — и последний маршрут, чтобы вход с меню поднял то же место. F5 с `?school=`
|
||||
шлёт тот же `OpenSchool`, что карточка. Вход/выход — `pushState`; смена вкладки и фильтра —
|
||||
`replaceState`, чтобы «назад» не листал каждый клик.
|
||||
|
||||
**Почему.** Сервер не знает про вкладки; класть их в сейв — лишний HTTP. `localStorage` как у
|
||||
языка держал бы «5А» через месяц. URL без фильтров остаётся коротким и копируемым.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
F5 внутри школы — та же школа, те же вкладки и фильтры. Назад — меню. Снова открыть ту же
|
||||
школу — не сброс на карту. Гость не входит в управление по ссылке. Скорость часов, пауза,
|
||||
открытый пул соискателей и мастер создания не вспоминаются.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Поиск по имени в списках, где его нет. Роутер-библиотека. Состояние на сервере. Бамп протокола.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Вне очереди
|
||||
|
||||
Склейка уже живых систем и мелкий DX. Именованный срез — не сюда.
|
||||
После любой фазы школа целая. Не читать все темы: открой файл задачи.
|
||||
|
||||
| Тема | Фазы |
|
||||
| --- | --- |
|
||||
| [Связность урока](lesson-consequences.md) | 48, 50–53 |
|
||||
| [Пропуск сборки](skip-stale-build.md) | 49 |
|
||||
| [Что нового](whats-new.md) | 54 |
|
||||
| [Состояние экрана](view-state.md) | 55 |
|
||||
|
||||
Люди: [`../02-people/people.md`](../02-people/people.md). Штат: [`../03-staffing/staffing.md`](../03-staffing/staffing.md).
|
||||
Расписание: [`../04-schedule/schedule.md`](../04-schedule/schedule.md). Присутствие: [`../05-ai/ai.md`](../05-ai/ai.md).
|
||||
Одежда: [`../07-inventory/inventory.md`](../07-inventory/inventory.md). Ремесло: [`../10-craft/craft.md`](../10-craft/craft.md).
|
||||
@@ -0,0 +1,83 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Связность урока
|
||||
|
||||
Урок уже растёт навык, если ученик стоит в кабинете и не голоден. Рядом лежат числа, которые
|
||||
игрок видит и которые на этот рост не влияют: учитель в туалете, навык учителя, тепло,
|
||||
учебник в сумке, снег на дороге.
|
||||
|
||||
Этот кусок отвечает на вопрос «почему нанимать сильного, чинить тепло и класть учебник в
|
||||
сумку». Оценок, посещаемости как журнала и приказов нет.
|
||||
|
||||
### Что меняется в уже принятом
|
||||
|
||||
| Было | Стало | Почему |
|
||||
| --- | --- | --- |
|
||||
| Ученик в кабинете качает навык, учитель может быть где угодно | Рост только если назначенный учитель стоит в том же узле и не идёт | Зазор «обязанность / место» уже есть; урок его не смотрел |
|
||||
| Зарплата зависит от навыков, урок — нет | Навык учителя по предмету масштабирует `Gain` | Иначе «математика 78» в пуле — только цена |
|
||||
| Голод режет урок, тепло — нет | Та же `NeedFactor` на тепло | Полоска уже живая; [`inventory.md`](../07-inventory/inventory.md) откладывал штраф |
|
||||
| Учебники сегодняшних предметов едут в сумке | Нет в сумке на этом уроке — половинный рост | Переноска и шкафчик иначе остаются двумя числами |
|
||||
| Погода одевает, на приход не влияет | Дождь и снег добавляют минуты к запасу на дорогу | Часы уже показывают осадки; ленивый уже опаздывает от черты |
|
||||
|
||||
### Формула
|
||||
|
||||
`HSchool.Ai.LessonLearning.Gain` по-прежнему чистое число. Множители:
|
||||
|
||||
- **нужды** — `NeedFactor(голод) × NeedFactor(тепло)`; нет нужды в каталоге — множитель 1;
|
||||
- **черты ученика** — как сейчас;
|
||||
- **учитель** — `NeedFactor(навык / 100)`, навык — среднее по `SubjectDef.skills` у учителя,
|
||||
нет ключа — `Range.Min` этого навыка; учителя нет в комнате — множитель 0, рост не пишется;
|
||||
- **учебник** — 1, если в сумке есть экземпляр с `subject` этого урока; иначе
|
||||
`BehaviorDef.lessonNoTextbookFactor` (ваниль 0.5).
|
||||
|
||||
Учитель «стоит в комнате»: `NodeId` = кабинет урока, путь пуст, остаток минут 0. Действие
|
||||
учителя не отменяет урок (дежурство — не `ActionDef`). Нет человека с этим id — учителя нет.
|
||||
|
||||
Дорога: к нынешнему `SlackMinutes` (черты + бросок) прибавляются минуты из
|
||||
`BehaviorDef.commuteRainMinutes` / `commuteSnowMinutes`, если в момент сборки плана дня на
|
||||
улице дождь или снег. `HSchool.Ai` осадки не знает — симуляция передаёт уже посчитанные минуты.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
Числа на карточке. Плюс строка в сегодняшней истории, **один раз на ключ в сутки**, не каждый
|
||||
тик:
|
||||
|
||||
| Тип | Когда | `thingDef` |
|
||||
| --- | --- | --- |
|
||||
| `lesson-no-teacher` | Урок шёл, учителя не было в кабинете | предмет |
|
||||
| `lesson-cold` | На уроке, который иначе учил, тепло ниже `needThreshold` | предмет |
|
||||
| `lesson-no-textbook` | На уроке нет учебника этого предмета в сумке | предмет |
|
||||
|
||||
Опоздание из-за снега в лог не пишем: весь состав получил бы одну и ту же строку, а место
|
||||
человека и так видно.
|
||||
|
||||
Клиент по-прежнему рисует `label` с сервера. Сокет и сейв не меняются. Версию протокола не
|
||||
бампить.
|
||||
|
||||
### Где живёт код
|
||||
|
||||
Нового проекта нет. Формула и план дня — `HSchool.Ai`. Присутствие учителя, тепло, сумка,
|
||||
погода на входе в план — `HSchool.Simulation`. Подписи лога — каталог. Список типов —
|
||||
`docs/protocol.md` (HTTP лога).
|
||||
|
||||
### Заведомо не сейчас
|
||||
|
||||
- Оценки, журнал посещаемости, выговор за прогул.
|
||||
- Перегруз замедляет ходьбу.
|
||||
- Насмешки над формой и мнения — срез 9.
|
||||
- Вызов родителей, деньги за одежду, болезнь от промокания.
|
||||
- Клиент сам считает «учится хуже».
|
||||
|
||||
### Зафиксировано этим разговором
|
||||
|
||||
| Тема | Решение |
|
||||
| --- | --- |
|
||||
| Нарезка | Пять фаз во «Вне очереди», не срез 10 |
|
||||
| Стоп | После каждой фазы школа целая |
|
||||
| Протокол | Не бампить; новые `type` только в HTTP лога |
|
||||
| Сейв | Не трогать |
|
||||
| Учитель на уроке | Тот же узел, не идёт; нет id — нет роста |
|
||||
| Навык учителя | Среднее по скиллам предмета, та же кривая что у нужды |
|
||||
| Тепло | Рядом с голодом, произведение двух `NeedFactor` |
|
||||
| Учебник | Только сумка, не шкафчик и не дом; ваниль ×0.5 |
|
||||
| Погода на дорогу | Минуты в `BehaviorDef`; лога нет |
|
||||
@@ -0,0 +1,31 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Пропуск сборки при запуске
|
||||
|
||||
### Зачем
|
||||
|
||||
`run-aspire.cmd` каждый раз вызывает `dotnet run`, а тот — MSBuild графа Aspire, даже когда
|
||||
исходники не менялись. Повторный запуск после Ctrl+C стоит десятки секунд впустую: SDK
|
||||
пересчитывает хост, хотя dll на месте.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Скрипт всегда `dotnet run --project src/HSchool.AppHost`. Аргументы проходили насквозь.
|
||||
|
||||
**Стало.** Если `HSchool.AppHost.dll` и `HSchool.Server.dll` новее входов (C#, csproj, props,
|
||||
`global.json`), скрипт делает `dotnet run --no-build`. Иначе — `dotnet build`, потом `--no-build`.
|
||||
`--rebuild` собирает всегда. Конфигурация (`-c` / `--configuration`) выбирает, какие dll сравнивать;
|
||||
по умолчанию Debug, как у `dotnet run`.
|
||||
|
||||
**Почему.** Инкрементальный MSBuild всё равно оценивает Aspire SDK. `--no-build` это пропускает.
|
||||
Клиентский TypeScript и JSONC модов не входы: Vite и каталог читают диск (`ContentRoot`), а не
|
||||
`bin`. Тестовые проекты AppHost не ссылается — их правки запуск не пересобирают.
|
||||
|
||||
Правила «устарел ли билд» живут в `tools/apphost-uptodate.ps1` (то, что вызывает `run-aspire.ps1`) и в
|
||||
`LaunchBuildStamp` (то, что проверяют тесты). Менять надо оба.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Голый `dotnet run --project src/HSchool.AppHost` по-прежнему собирает — так удобнее агентам с
|
||||
грязным деревом. Linux-обёртки нет: точка входа Windows — `.cmd`. Протокол, HTTP и сейв не
|
||||
трогаем.
|
||||
@@ -0,0 +1,33 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Состояние экрана
|
||||
|
||||
### Зачем
|
||||
|
||||
Менеджер — списки с фильтрами. Сейчас они живут только в RAM: F5 всегда меню, повторный вход
|
||||
сбрасывает вкладки и запросы. Игрок сравнивает людей и соискателей; потерять «ученики 5А» на
|
||||
обновлении — дырка в уже живых экранах, не новая фича.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** SPA без адреса. `GameScreen.show` и `PeoplePanel.show` обнуляют вкладки, фильтры и
|
||||
выбор. Язык уже в `localStorage`; игровые часы — на сервере.
|
||||
|
||||
**Стало.** Query URL держит *где я*: школа, обзор/управление, карта/люди, выбранные комната и
|
||||
человек. `sessionStorage` по `schoolId` держит фильтры, поиски, сорт, страницу, вкладку карточки
|
||||
и класс сетки — и последний маршрут, чтобы вход с меню поднял то же место. F5 с `?school=`
|
||||
шлёт тот же `OpenSchool`, что карточка. Вход/выход — `pushState`; смена вкладки и фильтра —
|
||||
`replaceState`, чтобы «назад» не листал каждый клик.
|
||||
|
||||
**Почему.** Сервер не знает про вкладки; класть их в сейв — лишний HTTP. `localStorage` как у
|
||||
языка держал бы «5А» через месяц. URL без фильтров остаётся коротким и копируемым.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
F5 внутри школы — та же школа, те же вкладки и фильтры. Назад — меню. Снова открыть ту же
|
||||
школу — не сброс на карту. Гость не входит в управление по ссылке. Скорость часов, пауза,
|
||||
открытый пул соискателей и мастер создания не вспоминаются.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Поиск по имени в списках, где его нет. Роутер-библиотека. Состояние на сервере. Бамп протокола.
|
||||
@@ -0,0 +1,26 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Что нового после входа
|
||||
|
||||
### Зачем
|
||||
|
||||
Альфа обновляется часто. Игрок не смотрит git: если с прошлого захода в этот браузер накатили
|
||||
другую сборку Server, один раз показать, что вошло в неё.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Нет версии сборки на экране. Сессионная кука HttpOnly и про вход.
|
||||
|
||||
**Стало.** Сборка Server вшивает `HEAD` и `git log --first-parent`. `GET /api/changelog?since=`
|
||||
отдаёт текущий SHA и коммиты после якоря. Клиент держит `hschool.seen-rev` (год, `Path=/`,
|
||||
`SameSite=Lax`, не HttpOnly). Первый заход без куки окно не показывает — только запоминает
|
||||
текущий SHA. Окно — после входа, не при возврате из школы.
|
||||
|
||||
**Почему.** «Накатанный» — то, что в dll, а не грязный HEAD при `--no-build`. First-parent после
|
||||
`--no-ff` — это слитые фазы, не внутренняя нарезка ветки. `Mark phase N` оставляем в цепочке
|
||||
якорем, в список не рисуем: иначе кука на таком HEAD потеряла бы следующее слияние.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Ручной `CHANGELOG.md`. Запись на пользователе в `users.json`. Вызов git из бегущего процесса.
|
||||
Бамп версии сокета. Окно внутри открытой школы.
|
||||
Reference in New Issue
Block a user