Синхронизация клиента с низким трафиком с сервером в MMO

22

Я реализую MMO, где игрок летит в космосе на своем звездолете, управляя им с помощью клавиш со стрелками и сотрудничая с другими игроками.

Я хочу реализовать это так, чтобы игрок мог уклоняться от своего корабля из ракеты или чего-то еще, поэтому я пытаюсь предсказать состояние всей игры на стороне клиента, используя тот же алгоритм моделирования мира, что и при использовании сервера. Этот игровой мир написан на C # и будет вызываться непосредственно в клиенте (он написан на Unity3D) и через CLR на сервере C ++ (под Linux). Соединение через UDP.

Проблема в том, как, например, поддерживать 1000 игроков на одной карте (исключая все другие игровые объекты, мобов ...): допустим, я буду:

  • синхронизировать сервер с клиентами 50 раз в секунду
  • отправлять каждому клиенту состояния только тех игровых объектов (и игроков), которые он способен видеть (в пределах некоторого радиуса)
  • необходимо отправить 100 объектов каждому игроку в радиусе его обзора
  • должен посылать в среднем 50 байт на игровой объект (это id, координаты x, y, вращение, состояние ...)

поэтому ему понадобится такая пропускная способность сети: 1000 (клиенты) * 50 (раз в секунду) * 100 (объекты для отправки каждому игроку) * 50 (байт на объект) = 250 000 000 байт в секунду! Это невозможно!

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

Во всяком случае, как такие игры запрограммированы обычным способом? Спасибо.

славянин
источник
1
Я посылаю только логическую информацию об объектах (положение в мире, текущее состояние (которое составляет один байт) и т. Д.) - без графики.
Славян
1
@Slav: Хорошо! Все эти сдвиги напоминают мне о моих днях программирования на ASM.
Рэндольф Ричардсон
1
Почему не "сегодня"? :) Когда я пишу на AS3, Java, Lua, C # и сталкиваюсь с такой низкой производительностью, я скучаю по C ++ и вспоминаю про ASM.
Славян
1
@Slav: Хехех, я не так много сделал в последнее время. Большинство вещей для меня сейчас на Java и Perl (в основном mod_perl2), но я действительно наслаждаюсь этими языками тоже.
Рэндольф Ричардсон,
2
@Slav, вы писали: «Когда я пишу на AS3, Java, Lua, C # и сталкиваюсь с такой низкой производительностью, я скучаю по C ++ и помню про ASM». Вы должны научиться правильно использовать Lua и C #, возможно, вы найдете производительность менее плачевной. Кроме того, жалобы на (якобы) самый быстрый язык сценариев из лучших в своем роде ... Это игра об анализе генома человека в реальном времени?
Рейн

Ответы:

20

Вам нужно всего около 30 обновлений (или даже меньше, может быть, 10 или 20) в секунду. интерполировать позиции движущихся объектов на стороне клиента. Как правило, вы должны отправлять данные только тогда, когда они действительно необходимы. В WoW вы можете получать больше обновлений от игроков, с которыми вы находитесь в группе, чем от игроков, которые находятся в том же месте. Кроме того, если другой игрок находится далеко от вас, вы не получаете столько обновлений в секунду о нем.

Затем отправляйте только один полный снимок каждому игроку, когда он подключается. После этого отправляйте только изменения игровых объектов. Если никаких изменений не произошло, не отправляйте их.

Затем интенсивно используйте BitVectors или как бы вы их ни называли, чтобы уменьшить количество ненужных данных! Пример: Вы также можете попытаться записать число с плавающей запятой, используя только один байт (в диапазоне от 0 до 1 или от -1 до 1), поэтому у вас есть только 256 или 128 различных значений. Но игрок не заметит никаких резких движений благодаря интерполяциям.

Посмотрите на это для примера с LidgrenLibrary о том, как сжимать данные: http://code.google.com/p/lidgren-network-gen3/wiki/Optimization

Далее: постарайтесь уменьшить радиус обзора игроков по мере их движения и передавать только важную информацию за это время. Затем, когда они перестают, снова увеличивают радиус обзора. Вы можете использовать систему пространственного хеширования или дерево bsp, чтобы уменьшить накладные расходы при поиске объектов, находящихся «в зоне действия». Это хорошая статья по теме: http://en.wikipedia.org/wiki/Collision_detection

Также сжимайте данные, СЕБЕ СЕБЯ знаете только о структуре данных и временной согласованности в данных (которые можно и нужно использовать). Общий алгоритм, такой как Bzip2, Deflate, как угодно, должен использоваться, но только как финальная стадия сжатия!

Кроме того, для информации, не важной для игры, вы также можете использовать дополнительные методы P2P. Пример: игрок воспроизводит анимацию «привет» (просто графический эффект). Игрок отправляет эту информацию на сервер, но сервер не передает информацию другим игрокам. Вместо этого этот некритический эффект посылается самим игроком другим клиентам в радиусе действия.

РЕДАКТИРОВАТЬ (из-за комментария):

Дополнительные методы для уменьшения среднего количества бит в секунду для каждого игрока:

  1. Вы написали, что отправляете «Объект не изменился». Нет причин делать это. Если вы беспокоитесь о потере пакета (и из-за этого не можете синхронизировать моделирование), учтите следующее: На каждом фиксированном временном шаге (например, 100, 200, 300, 400 ...) хешируйте состояние моделирования и отправляйте его на сервер. , сервер подтверждает или отправляет полный снимок всех данных обратно.

  2. Для таких вещей, как ракеты или даже игроки, вы можете использовать не только интерполяцию, но и экстраполяцию, чтобы сделать симуляцию более реалистичной. Пример «Ракета»: вместо обновления с такими сообщениями, как «Сейчас в позиции х», просто отправьте сообщение один раз, содержащее следующее: «Ракета порождена: позиция (вектор), время (на каком этапе моделирования порождается ракета), скорость ( вектор)". Таким образом, вам даже не нужно включать вращение, потому что наконечник всегда будет в направлении «скорости».

  3. Объедините несколько команд в одном сообщении и никогда не отправляйте сообщения размером менее 16-20 байт, потому что заголовок udp будет больше, чем само сообщение. Также не отправляйте пакеты, размер которых превышает MTU вашего протокола, потому что фрагментация замедлит скорость передачи.

Riki
источник
О, это хорошая идея, чтобы обновлять некоторые объекты чаще, чем другие, использовать P2P, снижать точность с плавающей запятой, отправлять только изменения (что для меня нетривиально, потому что я собирался периодически синхронизировать объекты, но «объект не изменился» - это информация слишком). Со всеми этими модификациями вся картина выглядит более реалистично!
Славян
1
Отправка уведомлений типа «объект не изменился» может быть полезной техникой для целей тестирования, когда вы хотите увидеть, как ваша игра работает, когда игроки находятся в напряженное время, потому что она может предъявлять требования как к обработке, так и к сети, но Есть еще лучшие решения, чем эта (например, создание автономного демона, который управляет настоящим игровым персонажем, затем многократный запуск этого демона с разных машин).
Рэндольф Ричардсон
5

Вот два подхода:

Во-первых:
переключитесь на детерминистическую физику, отправьте команды игрока, действия ai, объекты, появляющиеся в поле зрения, и все, что не может быть определено на стороне клиента клиентам. Это должно включать некоманды, подтверждение того, что до определенного момента времени применяются только команды, которые были отправлены и получены.

Клиент должен запустить два или три одновременных моделирования.
1: останавливает всякий раз, когда отсутствуют данные для следующего шага.
2: Продолжайте использовать данные догадки и укажите состояние, используемое для рендеринга. 3: Всякий раз, когда № 1 останавливается, это моделирование копирует состояние № 1, догоняет текущее время и заменяет его на № 2, который затем отбрасывается.

Если догоняющий достаточно быстрый, вы можете пропустить различия между № 2 и № 3 и сразу же отбросить старые данные.

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

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

И +1 для выполнения математики, слишком много людей не могут сделать простые оценки использования ресурсов.

AAAAAAAAAAAA
источник
2
Означает ли "детерминистская физика", что я не могу использовать значения с плавающей запятой или другие шаги моделирования? Мне интересно, что критическая десинхронизация может произойти, если, например, ракета пройдет мимо какой-то вражеской башни на клиенте, но ударит ее по серверу (из-за некоторой неточности с плавающей запятой), что заставит игрока продолжать сражаться с этой турелью до следующего пакета синхронизации следующего входящего сервера (несколько секунд).
Славян
3
Это означает целые числа и фиксированный временной шаг. Теоретически вы можете смоделировать плавающие точки, чтобы вести себя, но использование целых чисел намного проще. Вы поняли пример с отсутствующей ракетой: если вы используете недетерминированную физику, вероятно, лучше всего позволить серверу полностью справиться со смертью и быстро передавать случаи смерти / разрушения.
аааааааааааа
5

Сначала несколько вопросов.

«Ракеты или что-то еще» умны или глупы? Если они тупые, все, что вам нужно, это временная метка огня, источник и вектор, чтобы имитировать их путь. Если они умны, насколько они умны? Можете ли вы вычислить во время пожара, что они собираются ударить или пропустить? Если это так, вы можете смоделировать весь путь на клиенте. («В T13 ракета поразит корабль, потому что игра проиграла бросок уклонения / стрелок нанес критический удар».)

В целом, хотя в основном нет причин: A) иметь тактовую частоту 50 Гц, (большинству стрелков не хватает 15-20 и ММО меньше этого значения). B) отправлять полное состояние каждый кадр. (Имеет ли значение вращение ракеты в космосе? Или вы можете просто предположить, что ее «фронт» ориентирован вдоль вектора, по которому она движется?)

Потратьте время на прогнозирование и интерполяцию, и вы увидите, что ваша пропускная способность резко упала. Проект, над которым я работал, имел частоту обновления 10 Гц, и я думаю, что представление состояния объекта составляет 14 байтов. (Сжатие всего, что вы можете! Я считаю, что мы использовали 6 битов для определения поворота вокруг плоскости x, а затем еще 6 битов для наклона выше / ниже этой плоскости, это выглядело неотличимо от отправки фактической матрицы вращения / кватерниона.)

Еще одна вещь, которую вы можете сделать, это установить приоритетность объектов. Покажите, может быть, есть 100 объектов в соответствующем наборе, но знаете ли вы его взгляд на сервер? Если что-то не в его поле зрения, можете ли вы уменьшить частоту обновления на порядок?

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

Дуга-W
источник