Синхронизация состояния игры клиент-сервер - PullRequest
9 голосов
/ 17 апреля 2011

Я делаю клиент-серверную игру в стиле MMO.Пока у меня есть структура, настроенная так, чтобы сервер и клиенты взаимодействовали друг с другом, чтобы обеспечить обновления состояния.Сервер поддерживает игровое состояние и периодически вычисляет следующее состояние, а затем время от времени (каждые n миллисекунд) отправляет новое состояние всем клиентам.Это новое состояние может быть просмотрено и отреагировано пользователем на стороне клиента.Эти действия затем отправляются обратно на сервер для обработки и отправки для следующего обновления.

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

Чтобы бороться с этой проблемой, я пытался найти хорошее решение.Я посмотрел на следующее, и это помогло некоторым, но не полностью: Mutli Player Синхронизация игры .Я уже пришел к выводу, что вместо того, чтобы просто передавать текущее состояние игры, я могу передавать другую информацию, такую ​​как направление (или целевое положение для движения ИИ) и скорость.Исходя из этого, у меня есть часть того, что необходимо для того, чтобы «угадать» на стороне клиента, каково реальное состояние (как его видит сервер), развивая игровое состояние на n миллисекунд в будущее.

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

Любые предложения?

Повторить:

1) Чтосамый лучший способ вычислить количество времени между отправкой и получением?

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

РЕДАКТИРОВАТЬ: Что я до сих пор придумал

Поскольку у меня уже есть много пакетов, идущих туда-сюда между клиентами и серверомЯ не хочу добавлять в этот трафик, если мне нужно.В настоящее время клиенты отправляют пакеты обновления состояния (UDP) на сервер ~ 150 миллисекунд (только если что-то изменилось), а затем они принимаются и обрабатываются сервером.В настоящее время сервер не отправляет ответ на эти пакеты.

Для начала я сделаю так, чтобы клиенты попытались оценить время их задержки.Я установлю значение по умолчанию на 50-100 миллисекунд.Я предлагаю, чтобы примерно каждые 2 секунды (для каждого клиента) сервер немедленно отвечал на один из этих пакетов, отправляя обратно индекс пакета в специальном пакете обновления синхронизации.Если клиент получает пакет синхронизации, он будет использовать индекс для расчета того, как давно этот пакет был отправлен, а затем использовать время между пакетами в качестве нового времени задержки.

Это должно держать клиентов разумнодата в их лаге, без слишком большого избыточного сетевого трафика.

Звук приемлемый, или есть лучший способ?Это по-прежнему не отвечает на второй вопрос.

Ответы [ 3 ]

4 голосов
/ 20 апреля 2011

Во-первых, точно так же, как к вашему сведению, если вы беспокоитесь о задержках менее 1 секунды, вы начинаете выходить из области реалистичного лага для ММО. Способ, которым все крупные ММО справляются с этим, заключается в том, что две разные «игры» идут одновременно - есть основной игровой движок, который обрабатывает все математические состояния, состояния персонажей, применяет числовые изменения, а затем графический клиент.

Первая «игра», математика и вычисления, концептуально намного ближе к традиционной консольной игре (как старые MUD). Думайте с точки зрения сообщений, передаваемых туда и обратно, с очень высокой степенью изоляции ACID. Эти сообщения больше беспокоятся о точности, но вы должны предположить, что они могут занять 1-2 секунды (или больше) для обработки и обновления. Это «адвокат правил», который обеспечивает правильное вычисление очков жизни и т. Д.

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

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

2 голосов
/ 21 апреля 2011

Одним из способов решения этой проблемы является запуск симуляции игры на клиенте и на сервере.

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

Если они не совпадают (обман игрока, лаги), он отправляет вето клиенту, и действие не регистрируется как успешное на сервере.Это означает, что все остальные клиенты этого не замечают (сервер не перенаправляет действие другим клиентам).

Это должен быть довольно эффективный способ справиться с задержкой, особенно если у вас многоPvM-сражений (вместо PvP): поскольку монстр является симуляцией, не имеет значения, существует ли длительный лаг между клиентом и сервером.

При этом большинство сетей работают так быстро, чтоотставание должно быть в пределах нескольких миллисекунд.Это означает, что вы «просто» должны сделать сервер достаточно быстрым, чтобы он мог отвечать, скажем, <100 мс, и игроки не заметят. </p>

2 голосов
/ 20 апреля 2011

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

Предположим, что сервер отправляет состояние в момент времени T0, клиент видит его во время T1, игрок реагирует во время T2, а сервер получает свой ответ во время T3 и обрабатывает его мгновенно. Здесь задержка туда-обратно составляет T1-T0 + T3-T2. В идеальном мире T0 = T1 и T2 = T3, и единственной задержкой между временем наблюдения и обработкой действия игрока является время реакции игрока, то есть T2-T1. В реальном мире это T3-T0. Итак, чтобы смоделировать идеальный мир, вам нужно вычесть всю задержку туда и обратно:

T2-T1 = T3-T0 + (T1-T0 + T3-T2)

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

Есть проблема со всей процедурой: Вы экстраполируете в будущем, и это может привести к бессмысленным ситуациям. Некоторые из них, такие как погружение в стены, могут быть легко предотвращены, но те, которые зависят от взаимодействия игрока, не могут. 1

Может быть, вы могли бы перевернуть свою идею с ног на голову: Вместо прогнозирования, попробуйте оценить действия игрока в момент времени T3 - (T1-T0 + T3-T2). Если вы решите, что персонаж будет поражен таким образом, соответственно уменьшите его очки жизни. Это может быть проще и более реалистично, чем оригинальная идея, или может быть хуже, или вообще не применяться. Просто идея.


1 Представьте себе двух игроков, бегущих друг против друга. Согласно экстраполяции они проходят друг на друга с правой стороны. Фактически, один из них меняет свое направление, и в конце они переходят друг в друга с левой стороны.

...