К содержимому
Под капотом

Под капотом

Здесь без маркетинга: как эта штука устроена и почему именно так.

Сервер

C++20, один процесс на мир. Всё игровое состояние живёт в одном потоке — без мьютексов, потому что владелец один. Второй поток занимается только сокетами: опрашивает их, читает и пишет, а прикладной код не трогает.

Между потоками две очереди: входящая будит логику, исходящая — ввод-вывод через self-pipe. Пока логика ждёт базу, сокеты продолжают жить на другом ядре.

Тик — 20 раз в секунду. Клиент присылает намерение, сервер решает.

Хранилище

PostgreSQL. Важное свойство: ревизии мира дописываются и никогда не меняются. Триггеры в схеме физически запрещают UPDATE и DELETE на них — не «мы так договорились», а «база не даст».

Переход A→B живёт по правилам, знакомым всем, кто писал распределённые вещи:

  • аренда на переход — чтобы два процесса не двигали один мир;
  • токен ограждения растёт монотонно — опоздавший писатель отсекается;
  • CAS на голове — коммит проходит, только если голова там же, где была;
  • исходящий ящик пишется той же транзакцией, что и ревизия.

Отсюда следует то самое проверяемое свойство: переход переживает рестарт сервера на полпути. Не «обычно переживает» — это в регрессионных тестах.

Горячий путь

Сутки становления — это 20 тиков в секунду, и каждый из них когда-то ходил в базу. Сейчас на горячем пути записей в базу нет:

  • базовая ревизия декодируется один раз и лежит в кэше — она неизменяемая;
  • аренда продлевается не каждый тик, а когда истекла треть срока;
  • часы мира пишутся не каждый тик, а когда набежала секунда.

При падении мир доигрывает не больше секунды назад — детерминированно и идемпотентно.

Крипта

Своя, без TLS: X25519 для рукопожатия, ChaCha20-Poly1305 для кадров, HKDF-SHA256 для ключей. Ключ сервера закреплён в клиенте — сертификаты и удостоверяющие центры не нужны.

Это проверено между тремя реализациями: C++ на сервере, CryptoKit в клиенте на Swift и Python в тестах. Все три договариваются об одних и тех же ключах.

Клиент

macOS, Swift и Metal. Клиент держит каркас кадра — проходы, тени, HDR. Форма мира приходит с сервера, клиент её не выдумывает: пока не пришёл WorldSpec, строить нечего.

Рельеф считается по одному и тому же алгоритму на C++, Swift и Python и сверен бит-в-бит. Иначе игрок и сервер видели бы разные горы.

Сборка и выкладка

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

После выкладки идёт проба: настоящее шифрованное рукопожатие и вход. Если она не прошла — бинарь откатывается на предыдущий, автоматически.

Чего здесь нет

Ни трекеров, ни куки, ни аналитики, ни внешних запросов. Этот сайт не знает, что ты его читаешь.