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:
@@ -0,0 +1,65 @@
|
||||
# Рантайм школы: поток и ECS
|
||||
|
||||
Договорённость, которую код фазы 2 уже выполняет: каждая школа — свой работник, свой Arch
|
||||
`World`, свой файл. Инвариант в `AGENTS.md` совпадает с этим текстом.
|
||||
|
||||
Экран и defs: [`near-term.md`](near-term.md), [`defs.md`](defs.md).
|
||||
Куда класть код: [`projects.md`](projects.md).
|
||||
|
||||
Работник (поток, очередь, сейв-файл) живёт в **Server**. То, что он тикает — `School` в
|
||||
**Simulation**. Каталог, с которым школа создана — **Content**, замороженный у работника.
|
||||
|
||||
## Что уже почти есть
|
||||
|
||||
У каждой `School` уже свой Arch `World`. Это оставляем и делаем жёстким правилом: мир не
|
||||
разделяется между школами и не отдаётся чужому потоку. Arch не потокобезопасен.
|
||||
|
||||
## Целевая модель — в этом срезе
|
||||
|
||||
Каждая школа — **актор**: свой поток (`TaskCreationOptions.LongRunning` / выделенный поток, не
|
||||
пул тиков), свой `World`, свои часы, свой **замороженный** каталог def, свой файл на диске.
|
||||
|
||||
Над ними — тонкий супервизор (вместо сегодняшнего общего цикла):
|
||||
|
||||
- создать / удалить школу, знать лимит;
|
||||
- держать ящики: `id →` очередь команд этой школы;
|
||||
- собирать **снимки** для `GET /api/schools` (работник публикует неизменяемое состояние, как
|
||||
сейчас цикл публикует `SchoolsState`);
|
||||
- маршрутизировать сокет: `OpenSchool` / `SetRunning` / кадры часов — только в ящик той школы;
|
||||
- при старте процесса поднять школы с диска, при остановке — дождаться записи работников.
|
||||
|
||||
Супервизор **не** вызывает `World`, не тикает часы, не читает defs инстанса. Работник **не**
|
||||
трогает чужой мир и не ходит в ASP.NET. Файл школы пишет **работник** (create/delete через
|
||||
команду супервизору, снимок часов — редкий, shutdown — обязательный).
|
||||
|
||||
Тик по-прежнему фиксированный (`SimulationOptions.FixedDeltaTime`), у каждого работника свой
|
||||
таймер. Школы не синхронизируют календарь друг с другом — так и задумано.
|
||||
|
||||
Пока школ максимум шесть, шесть потоков — нормально. Не ставить тик симуляции на `ThreadPool`:
|
||||
под нагрузкой его заберут запросы и часы начнут плыть.
|
||||
|
||||
## Зачем ломать текущий цикл
|
||||
|
||||
Один поток на все школы дешевле и проще (нет гонок между мирами). Отдельный поток нужен, когда
|
||||
школы перестанут быть «только часы»: моды, карта, ECS. Тогда одна тяжёлая школа не должна
|
||||
останавливать остальные, и набор модов у школы A не должен быть глобальным синглтоном процесса.
|
||||
|
||||
Каталог def **на школу**, не на процесс: при создании выбирают моды, работник грузит папки и
|
||||
больше их не перечитывает. Иначе правка JSON на диске внезапно меняет уже идущую школу.
|
||||
|
||||
## Как это стыкуется с сокетом и меню
|
||||
|
||||
Как сейчас по смыслу, другое только «кто трогает School»:
|
||||
|
||||
- входящее с HTTP/WS → команда в ящик школы (или супервизору, если это create/delete);
|
||||
- меню читает опубликованный снимок, без блокировки работника;
|
||||
- исходящие кадры часов — из работника в outbox соединения, не наоборот.
|
||||
|
||||
Инвариант вместо «только поток цикла трогает registry» становится: **только работник школы
|
||||
трогает её `School` / `World` / каталог; супервизор трогает только таблицу ящиков.**
|
||||
|
||||
## Пока не делаем
|
||||
|
||||
- Потоки на системы внутри одной школы (job system как у RimWorld).
|
||||
- Миграция живой школы на другой набор модов.
|
||||
- Запись сейва на каждом тике.
|
||||
Reference in New Issue
Block a user