Большой мир целиком не помещается в память. Обычно его режут на локации, а стык прячут за загрузочным экраном. В онлайн-игре это особенно неудобно: локации живут на разных машинах, и на границе между ними мир должен остаться единым — со взрывом, который задевает существ по обе стороны.

Как обычно решают
Открытый мир нелинеен: идёшь куда хочешь, по дороге цепляешь побочные задания. Плата за это — ресурсы: мир не загрузить целиком. Отсюда деление на локации с загрузкой на переходе.

Бесшовный мир устроен иначе: в память подгружаются соседние локации, когда игрок приближается к их границам, а дальние выгружаются — в 3D-играх это часто прикрывают туманом.



Как это сделано у меня
Мир изначально задумывался открытым и масштабируемым — каждая локация может стоять на отдельной машине. Оставалось сделать его бесшовным.

Первой мыслью было подключать игрока сразу к нескольким серверам-локациям. От неё пришлось отказаться: знать о соседях нужно не только клиенту, но и самому серверу — иначе взрыв на границе не заденет тех, кто стоит на соседней локации. В итоге сервер-локация сам соединяется с соседями и становится для них клиентом.
Сразу вылезли две проблемы. Локация поднимается только когда на ней кто-то играет — понадобилось внутреннее API, которым серверы проверяют, запускают и останавливают друг друга. И согласованность: соседи одновременно хотят соединиться со мной, а я с ними. Пока развязка простая — инициирует тот, у кого сумма цифр в адресе больше, а при нескольких локациях на одной машине сравнивается ещё и порт.


Дальше сервер получает от соседей пакеты о происходящем у них, ретранслирует их своим игрокам и в ответ рассылает соседям то, что творится у него.

Переход через границу
Остался сам переход между серверами. Он собран так:
Игрок отправляет на сервер команду на выход
Сервер сохраняет игрока в бд
Сервер убирает из массива существ находящихся на нем игрока, рассылаем всем команду что игрок удаляется с сервера
Клиенты получают команду что игрок отключается, ждут пару секунд и убирают со сцены данный «прафаб» (в Unity игровые сущности называются префабами)
Если за те пару секунд что клиенты ждут удаление префаба он появился в другой сервер локации — мы анимируем плавный переход границы
В клиенте это выглядит как две группы слоёв: графика текущей и соседней локации отдельно, существа — отдельно.


Первые опыты дали переход не очень плавным. Как выглядело тогда:
Что было дальше
Переход довели: сейчас границы карт стыкуются в один открытый мир, игрок пересекает их без загрузочного экрана, а сервер обсчитывает только то, что реально видно игрокам. На этих же стыках работают порталы между картами и переносы внутри локации.
Как это выглядит в игре, показываю на канале проекта: youtube.com/@mmogick_ru.
Если вы делали бесшовный мир — расскажите, как решали согласованность между узлами.
История:
Выбор технологий, протокола и архитектурный шаблон Entity Component System
Открытый бесшовный мир в 2D игре
FPS, Ping, паузы между командами, интерполяция и экстраполяция
Event-driven паттерн, JSON-RPC и почему не сервисная (SOA) архитектура
Сетевая карта и задержка кадра (Latency frame) по RFC 2544 (1242)
Конвейер контента для MMO: импорт анимации, экипировка и обновление игры без патчей

