В прошлых статьях мы рассказывали про архитектуру ГИГАХРУЩА — браузерного survival horror с процедурной генерацией, WebGL-рейкастером и полноценным симулируемым миром (A-Life, Самосбор, физика) без использования готовых движков вроде Unity или Godot. Проект работает полностью локально, загружаясь в браузер за секунды.

Но что, если мы хотим добавить мультиплеер, где игроки смогут вместе ходить по одним и тем же бесконечным бетонным коридорам, встречать друг друга, отстреливаться от монстров и прятаться от гермодверей во время Самосбора?

Обычно для таких задач пишут выделенный headless-сервер на Node.js или C++, который крутится 24/7. Но у нас жесткое правило: мы делаем независимый проект с инфраструктурным бюджетом в $10/month. Мы не можем держать десяток мощных серверов, постоянно просчитывающих сотни процедурных этажей для пустого мира.

Вот как мы решили эту архитектурную задачу. Спойлер: браузер одного из игроков работает как полноценный сервер симуляции, а Cloudflare Durable Objects используются только как легковесный релей.

Отказ от античита (Relaxed Trust)

Главное продуктовое решение, которое развязало нам руки: мы официально отказываемся от античита.

ГИГАХРУЩ — это не соревновательная киберспортивная игра. У нас нет доната, выкачивания прибыли из игроков, реальных ставок или рейтингового ладдера. Это PvE-ориентированный кооп-хоррор. Если кто-то хочет читерить или использовать моды в совместной игре — это социальный риск, а не технический блокер. Наша задача сделать так, чтобы игра работала, была атмосферной и дешевой в поддержке, а не строить неприступную крепость.

Сместив фокус с authority is a fairness requirement на authority is a consistency/cost choice, мы смогли полностью пересмотреть архитектуру мультиплеера.

Архитектура Host-Browser Relay

Вместо того чтобы портировать наш тяжелый монолит симуляции (сотни NPC, поиск путей, перестройка геометрии) в облако, мы используем тот факт, что локальная копия игры уже отлично со всем этим справляется.

Как это работает:

  1. Первый зашедший игрок на конкретный этаж (route identity: {runSeed, floorKey, z, rulesetVersion}) становится хостом.

  2. Браузер хоста запускает полную честную симуляцию активного этажа размером 1024x1024. Он просчитывает AI всех монстров, последствия Самосбора, баллистику пуль и мутацию мира.

  3. В роли бэкенда выступает Cloudflare Worker + Durable Objects. Но они не считают игровую логику. Durable Object — это просто легковесная “комната” (room relay), которая хранит список участников, держит WebSocket соединения, организует порядок событий и служит буфером переподключения.

  4. Остальные игроки (peers) отправляют свои действия (input) через Durable Object к хосту. Браузер хоста применяет их действия к “удаленным акторам” в своей симуляции.

  5. Хост регулярно отправляет через DO снапшоты состояния (AOI — Area of Interest) обратно клиентам.

Таким образом, для игроков это выглядит как полноценный онлайн, но для нас стоимость сервера сводится к простой ретрансляции JSON-сообщений через Cloudflare.

AOI: Как не сжечь канал связи

Даже если сервер не считает физику, пересылать состояние всего этажа 1024х1024 каждый кадр — смерть для любого браузера.

Мы реализовали динамическую фильтрацию по Area of Interest (AOI). Каждый peer получает не весь мир, а только то, что происходит в его радиусе видимости (например, 48 клеток) плюс связанные события:

  • Состояние дверей, которые он открывает.

  • Монстров, которые вступили с ним в бой (даже если они за пределами жесткого радиуса).

  • Близлежащий лут.

  • Положение других игроков.

Хост собирает эти “обрезанные” куски мира и отправляет как lossy-снапшоты (которые можно терять) вместе с reliable-событиями (выстрел, поднятие предмета, урон).

При этом для клиента всё выглядит прозрачно. Его локальный браузер всё так же генерирует базовую геометрию уровня (ведь сид генерации один на всех), отрисовывает WebGL-сцену и предсказывает базовые движения локального персонажа, чтобы не было инпут-лага, а затем мягко синхронизируется с сервером (хостом).

Что если хост отключится?

Главная слабость архитектуры player-host — хост может закрыть вкладку, у него может отвалиться интернет или браузер просто уснет.

В нашем первом Proof of Concept (до 8 игроков) это обрабатывается жестко: если хост пропадает больше чем на 15 секунд, сессия замораживается и отваливается. Мы жертвуем стабильностью ради обкатки геймплея. Но в будущем запланирован механизм Host Handoff:

  1. Если хост решает выйти легально (или мы перехватываем beforeunload), он быстро формирует компактный полный чекпоинт этажа (сжатый массив комнат, NPC, лута и состояния Самосбора).

  2. Этот чекпоинт улетает в Durable Object.

  3. DO назначает новым хостом другого игрока, передает ему чекпоинт.

  4. Новый хост “распаковывает” мир, перестраивает графы поиска путей и забирает власть над симуляцией на себя.

  5. Все остальные клиенты запрашивают у нового хоста свежие фреймы и игра продолжается. На экранах это выглядит как секундная загрузка.

Следующие шаги: от 2 к 100+ игрокам

Наша текущая цель — отладить эту схему на 2, 4 и 8 игроках в кооперативном режиме. Мы уже настроили Cloudflare D1 для сохранения постоянных профилей, логов инвентаря и статистики (НЕТ-СФЕРА).

Если же проект вырастет до необходимости собирать сотни игроков на одном этаже, Cloudflare Relay перестанет справляться (браузер хоста просто сгорит от количества расчетов и исходящего трафика). Для этого у нас спроектирован отдельный, строгий серверный трек (Server Scale Addendum).

В нем та же самая логика симуляции из main.ts отрывается от WebGL, Canvas и DOM, упаковывается в Cloudflare Containers или отдельный VPS и работает как Headless Room Server. Но к этому мы перейдем только тогда, когда упремся в лимиты бесплатного хост-роутинга и поймем, что аудитории это действительно нужно.

А пока мы продолжаем строить бесконечную хрущевку, где теперь хотя бы можно будет крикнуть соседу, чтобы он не открывал гермодверь.


Следить за проектом и поиграть в локальную версию прямо в браузере (без регистрации и СМС) можно тут:

Комментарии (5)


  1. Void-Cowboy
    02.07.2026 03:08

    по идее вы можете паразитировать на базе существующих TUN-серверов. Даже если это чисто ваш - один хрен сервер становится маршрутизатором и все, клиенты общаются меж собой, группировка по uid сида, по которому же и генерируется мир. То есть в теории можно даже на опенсорс отдать что бы люди сами к своим серверам привязывали если захотят поиграть без читеров и тд.

    Самое проблемное в онлайне это отсутствие доверия к клиенту. Если у вас этот вопрос "опускается" то сделайте открытый протокол, опубликуйте простую и надёжную как двери серверную релейку для связи меж игроками и будет вам счастье. И вам ваш сервер не будет жрать ресурсы и клиенты смогут хоть с телефона поднять и по локальной сети выживать в гигахруще.


  1. Teneviker
    02.07.2026 03:08

    Не хватает скринов в теле поста, больше нарративности, колега.


  1. Buldozza
    02.07.2026 03:08

    Круто. "Инженерный" подход.

    Пара замечаний:

    Если хотите свернёт боуз - у всех игроков может залипнуть игра. Это связано с системой энергосбережения.

    Если у игрока-хоста нестабильный интернет (например, 4G в поезде), сессия будет постоянно инициировать процедуру Host Handoff. При передаче чекпоинта новому хосту критически важно передать не просто состояние комнат, а точное процессуальное время (tick rate) и состояние генератора случайных чисел (PRNG state).

    Асимметрия пинга: Игрок, ставший хостом, получает нулевой пинг до симуляции (у него всё идеально плавно), в то время как остальные игроки зависят от цепочки Клиент -> Cloudflare DO -> Хост -> Cloudflare DO -> Клиент. Это может вызывать ощущение несправедливости в кооперативе (хост всегда реагирует быстрее).

    Данные замечания оказались в тему? Обсудим?


    1. Roman_Cherkasov
      02.07.2026 03:08

      Из забавного. На официальных соревах от Riot Games по League of Legends - умышленно добавляется пинг для всех игроков. Ибо по локальной сети - он близок к 1-2мс, но игроки привыкли играть на ~50-70. И в первые тесты - спортсмены очень сильно лажали из-за того, что играли с таким низким пингом.
      Кажется на хабре даже был перевод статьи из их блога, о том, как они это реализовали у себя.


      1. Buldozza
        02.07.2026 03:08

        Я думал они это сделали ради демпфирования потока. Такие умышленные замедления можно использовать для буферизации и синхронизации сессии между игроками.