Работа со скоростью игрока в онлайн-игре - PullRequest
0 голосов
/ 18 ноября 2018

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

Клиент

/**** [game/client] movePlayer ***/


boolean playerCanMove = Date.now() - player.lastMove > 1000;

if(playerCanMove){

    player.lastMove = Date.now();
    player.move(RIGHT);
    client.send(new PacketMove(RIGHT));
}

Сервер:

/**** [server] handle a move packet ****/
/** The only data received from the client is the direction(RIGHT) **/
/** the server has its own player.lastMove **/

let playerCanMove  = Date.now() - player.lastMove > 1000; 

if(playerCanMove){
    player.lastMove = Date.now();
    player.move(RIGHT);  
}
else{
   error = "Player is moving too fast"; 
}

Проблема в том, чтосервер player.lastMove не будет одинаковым на клиенте / сервере из-за времени, которое требуется для доставки пакета.

Так что, если клиент отправит 2 пакета перемещения, первый с временем прохождения100ms, а второй сервер с временем прохождения 99ms будет думать, что игрок движется слишком быстро. Если проблема не в этом, проблема в том, что время в пути меняется, и сервер экономит player.lastMove с небольшим опозданием,предел погрешности в этом случае не звучит слишком хорошо.

enter image description here

Есть идеи?

РЕДАКТИРОВАТЬ:Единственные данные, которые отправляются на сервер, - это направление, в котором игрок хочет двигаться ради примера. Это только те же имена переменных.Сервер имеет собственную player.lastMove переменную

РЕШЕНИЕ Благодаря @Lev M.

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

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

enter image description here

добавление дополнительного && packet.timeStamp < server.clock

к

boolean isTimeStampValid = packet.timeStamp >= player.lastMove + 1000 && packet.timeStamp < server.clock

не может пойти не так, и атака # 1 isTimeStampValid будет помечена как ложная

Ответы [ 3 ]

0 голосов
/ 18 ноября 2018

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

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

Здесь есть замечательная статья, описывающая методы, используемые для создания игр такого типа:
http://www.gabrielgambetta.com/client-server-game-architecture.html

0 голосов
/ 18 ноября 2018

Вот идея, которую я считаю простой в реализации: не используйте Date.now() для вычисления времени между ходами.

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

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

Когда игрок делает ход, попросите клиента вставить временную метку, основанную на этих часах.в пакете вместе с данными о перемещении.

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

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

Вы также можете реализовать некоторую логику, которая остановит игру, если он обнаружит пакеты, прибывающие вместе или близко (100-200 мс), но с временными метками в 1000 мс илиБольше.Это будет простой способ поймать читеров.

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

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

Ваш сервер сможет затем проверить согласованность всей партии.

0 голосов
/ 18 ноября 2018

Ваша архитектура неверна.

клиентская сторона игры должна иметь нулевую логику , обрабатывающую пользовательский ввод ... пользовательский ввод должен быть отправлен на сервер как можно более сырым, а клиентская сторона KEEPS NO STATE

серверная сторона сохраняет все игровое состояние, получает пользовательский ввод от клиента, обрабатывает новое игровое состояние (проверяет, был ли правильный ход или нет), затем возвращает клиенту новое игровое состояние

клиент должен просто напечатать новое состояние на экране. сохранение минимальных локальных данных , насколько это возможно

ваше представление о клиенте " знать " последний ход имеет смысл только в том случае, если есть какой-то " отменить " последний ход

Во-вторых, если вы используете http для передачи данных между клиент-сервером, сервер не сможет получить move2 до перемещения1 ... http - это протокол tcp, и tcp гарантирует порядок доставки, поэтому ваше предположение о различных задержках, приводящих к неправильному порядку на стороне сервера, неверно

...