Files
h-school/docs/design/runtime.md
T

4.6 KiB
Raw Blame History

Рантайм школы: поток и ECS

Договорённость на ближайшее планирование. Сейчас в коде не так: один GameLoopService тикает все школы на одном потоке, и это записано в AGENTS.md как инвариант. Ниже — целевая модель. Менять инвариант в рабочих соглашениях имеет смысл только вместе с кодом.

Экран и defs: near-term.md, defs.md.

Что уже почти есть

У каждой School уже свой Arch World. Это оставляем и делаем жёстким правилом: мир не разделяется между школами и не отдаётся чужому потоку. Arch не потокобезопасен.

Целевая модель

Каждая школа — актор: свой поток (или TaskCreationOptions.LongRunning, что для нас то же самое: выделенный поток, не пул тиков), свой World, свои часы, свой замороженный каталог def (набор модов, выбранный при создании).

Над ними — тонкий супервизор (сегодняшняя роль GameLoopService + SchoolRegistry):

  • создать / удалить школу, знать лимит;
  • держать ящики: id → очередь команд этой школы;
  • собирать снимки для GET /api/schools (работник публикует неизменяемое состояние, как сейчас цикл публикует SchoolsState);
  • маршрутизировать сокет: OpenSchool / SetRunning / кадры часов — только в ящик той школы.

Супервизор не вызывает World, не тикает часы, не читает defs инстанса. Работник не трогает чужой мир и не ходит в ASP.NET.

Тик по-прежнему фиксированный (SimulationOptions.FixedDeltaTime), у каждого работника свой таймер. Школы не синхронизируют календарь друг с другом — так и задумано.

Пока школ максимум шесть, шесть потоков — нормально. Не ставить тик симуляции на ThreadPool: под нагрузкой его заберут запросы и часы начнут плыть.

Зачем ломать текущий цикл

Один поток на все школы дешевле и проще (нет гонок между мирами). Отдельный поток нужен, когда школы перестанут быть «только часы»: моды, карта, ECS. Тогда одна тяжёлая школа не должна останавливать остальные, и набор модов у школы A не должен быть глобальным синглтоном процесса.

Каталог def на школу, не на процесс: при создании выбирают моды, работник грузит папки и больше их не перечитывает. Иначе правка JSON на диске внезапно меняет уже идущую школу.

Как это стыкуется с сокетом и меню

Как сейчас по смыслу, другое только «кто трогает School»:

  • входящее с HTTP/WS → команда в ящик школы (или супервизору, если это create/delete);
  • меню читает опубликованный снимок, без блокировки работника;
  • исходящие кадры часов — из работника в outbox соединения, не наоборот.

Инвариант вместо «только поток цикла трогает registry» становится: только работник школы трогает её School / World / каталог; супервизор трогает только таблицу ящиков.

Пока не делаем

  • Потоки на системы внутри одной школы (job system как у RimWorld) — рано.
  • Миграция живой школы на другой набор модов.
  • Правка AGENTS.md до тех пор, пока цикл в коде ещё общий.