RTS Game Protocol

18

Я думал о многопользовательской игре RTS. Часть, которую я не могу обойти, - это синхронизация движения юнита. Если я переместу блок A, чтобы определить XY, я должен передать это обратно на сервер, который передает другому клиенту.

Мне интересно, как будут выглядеть сообщения. Не могли бы вы сообщить серверу, что я перемещаю блок A в XY из JZ? Может быть, вам нужно вместо этого сообщить координаты движения по координатам? Какова наиболее эффективная методология передачи движения единиц от одного клиента к другому?

РЕДАКТИРОВАТЬ

Это заданный вопрос из stackoverflow . Я обнаружил, что этот сайт, вероятно, был лучшим местом для вопроса.

Один из лучших ответов из этого поста:

Я предполагаю, что вы собираетесь использовать сетевую парадигму клиент-сервер? В этом случае вы не можете доверять клиентам обработку фактического расположения блоков, вы должны делегировать эту задачу на сервер. Затем вы берете список команд от каждого клиента за такт и вычисляете движение каждого подразделения, как только это будет выполнено, на следующем тике вы передаете положение каждого подразделения, относящегося к каждому клиенту (либо на основе всей карты, либо на основе просмотра) и запустите процесс заново.

Darthg8r
источник
2
Ответ действительно зависит от того, какой метод вы хотите использовать. Клиент - клиент или клиент - сервер. Клиент-сервер проще, но требует надежного сервера
Cem Kalyoncu

Ответы:

25

Вы не хотите синхронизировать позиции всех юнитов от сервера до каждого клиента; что займет путь больше пропускной способности , чем вам нужно. Вам также придется иметь дело с интерполяцией / экстраполяцией позиций юнитов и т. Д. Практически ни один профессиональный RTS не использует клиент / сервер!

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

Недостатком является то, что каждый игрок работает так же медленно, как и самый медленный игрок - если кто-то отстает в рассылке команд, все должны замедлиться и ждать, пока он не догонит (в Starcraft 2 это «XXX замедляет игру» " диалог".


На самом деле, обычно делается еще одна вещь: полностью исключить сервер . Пусть каждый клиент отправит свои команды каждому другому клиенту. Это уменьшает лаг (вместо команды, идущей от вас -> сервер -> противник, она просто идет от вас -> противник) и упрощает кодирование, поскольку вам больше не нужно кодировать отдельный сервер. Такая архитектура называется одноранговой (P2P).

Недостатком является то, что теперь вам нужен способ разрешения конфликтов, но, поскольку команды игроков независимы друг от друга в большинстве RTS, это обычно не составляет большой проблемы. Кроме того, он плохо масштабируется - каждый раз, когда вы добавляете нового игрока, каждый игрок должен отправить ему свои команды. Вы не собираетесь делать MMO RTS, используя P2P.


Эта настройка (отправка только команд с использованием P2P) - это то, как работает большинство RTS, включая Starcraft, C & C и AoE, и это единственный способ, которым AoE может поддерживать 1500 устройств при соединении со скоростью 28,8 Кбит / с .

(изображение сети в AoE)

Вот еще несколько советов по написанию P2P RTS:

  • По понятным причинам эта настройка может работать, только если ваша игра использует фиксированный шаг - вы не хотите, чтобы результаты вычислений зависели от частоты кадров! С фиксированным шагом легче работать для большинства вещей, поэтому это не должно быть проблемой.
  • Чтобы это работало, результаты каждой команды должны быть полностью детерминированными .
    • Обычно это довольно просто, если вы ограничиваетесь одной системой (например, 32-битной Windows) и заставляете всех клиентов использовать один и тот же исполняемый файл: убедитесь, что все генераторы случайных чисел имеют одинаковое начальное число и всегда вызываются в одном и том же порядке; будьте предельно осторожны при переборе неупорядоченных коллекций ; и т.п.
    • Это чрезвычайно сложно, если вы планируете сделать игру доступной на разных платформах или (как это часто бывает в Linux) позволить клиентам самим компилировать код. Мало того, что разные системные библиотеки в значительной степени гарантируют использование различных реализаций rand()и cos()т. Д., Но почти все математические операции с плавающей точкой исключены (см. Здесь , здесь и здесь ) ! В этом случае вам лучше использовать клиент-сервер.
  • Вы будете хотеть посылать все позиции юнитов время от времени, по крайней мере во время отладки, для обнаружения ошибок рассинхронизации (которые, поверьте мне, у вас будут ). Держите ли вы это в финальной игре, зависит от вас - я бы синхронизировал хотя бы несколько юнитов (или использовал какую-то контрольную сумму), чтобы обнаружить попытки взлома.
BlueRaja - Дэнни Пфлугхофт
источник
Хороший пост. Небольшая вещь, которую нужно добавить, даже оптимизация тех же компиляторов, отладка / выпуск и другие флаги могут изменить результат. Быть осторожен!
Питер Олстед
14

Я создал протокол RTS с сетью TCP, в котором я передавал сами команды, а не результаты команд . Например, игрок отдает приказ на ход. Если заказ на перемещение действителен в соответствии с этим клиентом, он отправляется на сервер. Затем сервер отправляет его обратно всем клиентам, которые проверяют и выполняют его.

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

Сервер также посылает номер «тика», под которым нужно выполнить команду, что на несколько тиков впереди «текущего» тика. Таким образом, все команды могут быть выполнены в одно и то же время на всех машинах.

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

Проверка команды на стороне клиента перед отправкой на сервер не обязательна, но теоретически она экономит сетевой трафик. Я использовал тот же код проверки, чтобы сообщить пользовательскому интерфейсу, что переезд возможен, поэтому он не требует написания дополнительного кода.

Что касается того, как сообщения могут выглядеть. Я не был обеспокоен ультра эффективностью, так как это была моя первая сетевая игра. Я передал команды в виде строк. Команды будут отформатированы так:"<player_id>:<command>:<parameters>"

Для надуманного примера, команда перемещения может выглядеть следующим образом : "3:move:522:100:200". Это означает, что игрок 3хочет moveприсоединиться 522к ( 100, 200).

Сервер передает команду на всех клиентов, в том числе тот , кто послал его с номером клеща прилагается так: "153238:3:move:522:100:200".

Тогда все клиенты будут выполнять эту команду при выполнении отметки 153238.

Филипп
источник
Я добавил немного больше информации к вопросу. Ответ SO кажется противоречащим тому, что вы сказали, и я хотел бы обсудить более мелкие детали.
Darthg8r
Да, это еще один способ сделать это, но мне кажется, что было бы больше работы, чтобы передать большую часть игрового состояния, а не только команды. Моя игра была достаточно простой, чтобы все это могло работать на каждом клиентском компьютере. Для MMO или для чего-то вроде Minecraft у вас не работает весь симулятор на стороне клиента, поэтому вы передаете только информацию, относящуюся к каждому клиенту в отдельности.
Филипп