Как организовать синхронизацию игрового мира между клиентом и сервером?

Решил написать сетевую игру и встретил малоизвестную мне область - синхронизация клиента с сервером.
Важные данные:
  • Игра происходит в реальном времени, поэтому скорость имеет значение.
  • Игровой мир состоит из неизменного во время игры числа двумерных карт (состоят из клеток). Каждая карта - 512x512 клеток.
  • Клетка состоит из (в порядке отрисовки):
    В скобках - значимые для игрока данные.
    1. "Земля" (картинка, неуникальное имя, уникальный id) - 1 шт.
    2. "Подвижные" объекты (картинка, не уникальное имя, уникальный id) - 0:30 шт.
    3. Эффект земли (картинка) - 1 шт.
    Все изображения есть у клиента, передача их по сети не нужна.
  • "Подвижный" объект - объект способный перемещаться на неопределенное число клеток.
  • Каждый игрок имеет ограниченную зону видимости (20x20), данные об объектах вне зоны видимости не должны быть известны игроку. Игрок может перемещаться по карте, как смещением на одну клетку, так и прыжком на неизвестное число клеток (это происходит редко).
  • Предполагается, что все расчеты происходят на сервере, клиент - только отрисовка и передача действий игрока на сервер.

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

UPD1:
Пара уточнений:
  • В среднем будет 30 игроков.
  • Самая главная часть вопроса: организация передачи данных во время игры.
    С инициализацией и завершением все ясно.
  • Здесь и сечас существуе взаимодействие между игроками и только. Никоких ботов, мобов и прочего.
  • Вопрос задан
  • 4015 просмотров
Решения вопроса 1
lexxpavlov
@lexxpavlov
Программист, преподаватель
Посмотрите вопрос https://toster.ru/q/142555, в нём есть некоторые моменты, которые вам пригодятся. Я там привожу несколько ссылок "на почитать".

А решение вашей задачи будет очень сильно зависеть от количества игроков в одной локации. Если их мало (скажем, меньше пары десятков), то каждая такая локация, скорее всего, будет независимой от других, и задача синхронизации станет сильно проще - меньше объектов будут требовать синхронизации. И на одном сервере поместится несколько таких локаций.

Если игроков много (сотня и больше), то архитектура очень сильно усложнится. Настолько, что начинать учиться на таком проекте нет никакого смысла. Почитайте про это тот вопрос, что я привёл выше.

Какая планируется технология на сервере и на клиенте? (язык программирования, платформа)
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
uvelichitel
@uvelichitel
habrahabr.ru/users/uvelichitel
Очень широкая тема. Про это книги пишут. Вот пара общих советов
  • Делайте клиента в браузере, меньше хлопот, шире аудитория. Такой выбор ограничивает транспорт до websocket и формат данных до JSON(ну еще msgpack).
  • Синхронизируя распределенное состояние сверяйте не весь массив, а только его пошаговые изменения как делают git и rsync (по возможности используйте не shared state , а message passing) Весь массив можно иногда проверять на консистентность его hash суммой.
  • Накапливайте состояние на сервере, как последовательность изменений адресованное hash суммой, как и делает git.(тут гуглить content addressable store)
  • При поиске консенсуса используйте не 'кто первый', а 'он знает, что я знаю'. (тут гуглить protocol consensus)
  • Определитесь, какая степень дублирования данных на сервере и клиентах достаточна для консистентности игры и приемлема по цене ресурсов. (тут гуглить sharding replication)
Ответ написан
Комментировать
@mamkaololosha
Нахрена их синхронизировать?
TCP для квест принял-квест отдал и для юнит трям побежал сям.
UDP если захотите устраивать бомбардировку пакетами.
Кеширование для "горячих" вещей, бд для "тёплых" и более-менее статических. Вам же не карту рендерить на сервере. Почитайте про толстый-тонкий клиент.
Ответ написан
SilenceOfWinter
@SilenceOfWinter
та еще зажигалка...
1. Клиент запрашивает обновление у сервера только когда он активен (не свернут, не открыто модальное окно с настройками).
2. Для авторизации запрос к серверу содержит идентификатор сессии созданный при входе в игру.
3. Сервер возвращает инфу только о видимых клетках и самом игроке. Не доверять пользовательским данным - не стоит передавать в запросе текущее положение игрока, оно должно храниться в базе (также это требуется для реализации 1 пункта).
4. Рассчитывать передвижение мобов только для тех локаций где находятся (или находились недавно) игроки, генерировать карты только при переходе игрока в данную локацию.

В общем стараться не просчитывать лишние данные на сервере, не запрашивать данные клиентом когда это не нужно и не передавать клиенту данные сверх тех что необходимы.
Ответ написан
Комментировать
xmoonlight
@xmoonlight
https://sitecoder.blogspot.com
Все тут просто:
1. Опрос событий от клиентов по кругу ("раунд-робин")
2. Порядок: пакет->проверка->установка значений в стэке (или отбрасывание)->переход к следующему событию (и т.д. пока не будет достигнут лимит по задержке)->отправка итогового результата "мира" всем, кто отправил событие -> следующая порция и т.д.
Таким образом достигается правило: "все знают обо всех синхронизировано и без задержек, а так же проходят проверку на сервере".
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы