Перейти к содержимому

Ячейки и путь к многим узлам

WIP: пока не реализовано или реализовано частично. Следите: #181, #351

Цель - десять тысяч игроков в одном измерении

Заголовок раздела «Цель - десять тысяч игроков в одном измерении»

Цель - десять тысяч игроков в одном измерении с немодифицированным ванильным клиентом.12 Столько взаимодействующих игроков в одном непрерывном пространстве никто не публиковал, поэтому это цель, а не обещание.

Упирается это число не в тик. Главный предел - сколько игроков видят друг друга, потому что движущийся игрок стоит каждому наблюдателю примерно 200-250 байт в секунду до сжатия. К тому же при переносе клиент сбрасывает свой мир. Поэтому план такой: распределить игроков по одному измерению и ограничить число тех, кого видит каждый клиент.

Дизайн держится на четырех идеях, и каждая лежит в небольшом крейте семейства mcrs_engine_*.

Часть Крейт Что делает
Ячейка (cell) mcrs_engine_cell Владеет прямоугольным участком горячего пространства. Чанки в этом участке меняет только владелец.
Link mcrs_engine_link Связывает две части. Сообщения входят и выходят, и ни одна часть не читает состояние другой.
Muxer mcrs_engine_muxer Шлюз для клиентов. Он владеет соединениями, решает, что получит каждый клиент, и кодирует изменение один раз для всех, кто видит тайл.
Слой данных mcrs_engine_store Хранит версионируемые чанки холодного пространства.

У ячейки есть еще halo, то есть копия колонок соседей в пределах двух колонок. Благодаря halo ячейка никогда не меняет колонку, которой не владеет. То, где работает дальний конец link, называется его размещением, и размещение бывает Inline, Thread или Remote.

Не путайте ячейку с шардом. Ячейка - единица размещения, шард - единица причинности, описанная в заметке о шардировании, и в одной ячейке много шардов.

Тик параллелен не благодаря ячейкам: внутри одной ячейки каждая область и так использует все ядра, это показано на странице Как тик работает параллельно. Ячейки нужны для балансировки и размещения, потому что ячейку можно перенести в другой поток, процесс или на другую машину.

Список составлен по разделу 11 заметки docs/cells.md (“Где код сегодня”) и сверен с тестом tick_determinism.rs.

  • У мира одна ячейка или статическое деление на несколько. Ячейки всех миров тикают синхронно, либо inline, либо каждая в своем потоке. Это выбирают настройки сервера worlds, cells и muxer в crates/mcrs_minecraft_server_settings/src/server_settings.rs.
  • Стадия muxer работает на link от хоста. Хост общается с каждым измерением по link, с одним входом и одним выходом на тик.
  • Слой данных в памяти отдает холодные колонки, а стадии генерации и освещения работают в потоке.
  • Игрок переходит в другую ячейку в конце того тика, в котором он стоит в колонке этой ячейки. Гистерезиса пока нет, и никакие сущности, кроме игрока, границу не пересекают.
  • Диска под слоем данных нет, потому что сервер пока не пишет чанки на диск.3
  • Разделение и слияние ячеек по стоимости. По дизайну это k-d деление по X и Z, а перенос происходит на границе тика с гистерезисом около 8 блоков.
  • Placement::Remote, то есть ячейка в другом процессе, и вместе с ней граница (edge) в виде отдельного процесса, который держит все соединения. Эта часть разбита на отдельные задачи: шарды, которые выполняются параллельно, и шаги распределения от связи между процессами до координатора.1456
  • Уровни репликации сущностей из docs/replication.md. Это тоже заметка о дизайне.

Все это необязательно. Дизайн требует, чтобы пользователь мог отказаться от ячеек, muxer и слоя данных и написать сервер в одном потоке, где игровая логика зависит только от ядер и трейта представления мира. Что такое ядро, объясняет страница Слои и крейты.

Между таким сервером и полной раскладкой есть средний режим: полный движок с одной ячейкой на мир и всеми link в режиме inline. Он детерминирован, и именно в нем работают тесты.

Дальше: Дорожная карта.

  1. В работе#181 Направление: одно измерение на многих узлах для тысяч игроков. ↩ ↩2 ↩3

  2. Частично#351 Решение о том, что десять тысяч игроков распределены по одному измерению. ↩

  3. В работе#78 Отслеживает запись измененных чанков обратно в файлы регионов. ↩

  4. В работе#160 Шарды образуются, сливаются, делятся и выполняются параллельно. ↩

  5. В работе#162 Первая задача распределения: подключаемая группа плагинов за трейтом связи. ↩

  6. В работе#167 Последняя задача распределения: координатор с картой владения и балансировкой нагрузки. ↩

Источники и проверка

Проверено: 26.4-snapshot-7, 51d45c26a, 2026-11-09

Переведено с версии 51d45c26a

Следить: #181, #351