Верификация данных пользователей в онлайн приложениях

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

Хочу предупредить, что статья нацелена на новичков. Людей которые хотели бы написать свою первую многопользовательскую игру. Если вы хоть раз занимались сетевым взаимодействием в играх, ничего полезного здесь не найдёте.

Техническое отступление


И дабы не остаться теоретическим материалом была написана небольшая демка. Ее можно запустить, посмотреть какими данными обмениваются клиент и сервер. На чьём примере и будет рассмотрено клиент-серверное взаимодействие.

Приложение использует технологию canvas для графики и websockets для взаимодействия с сервером. Код не является предметом обсуждения, поэтому писался быстро (основная часть около 2–3 часов), без проектирования и рефакторинга. Я не рекомендую использовать его или его часть где бы то ни было.

Вы выбираете героя, сервер вас регистрирует, ищет игру. Ждёт пока не войдут достаточное кол-во игроков.

c6db40226470409e848fd8e5b71c3c8a.png

Поле схожее с тем что есть в пошаговых играх аля Heroes MM. Две команды, по четыре игрока за каждую. В начале игра строит случайную последовательность игроков, в дальнейшем ход передаётся циклично.

Каждый герой имеет свои характеристики атаки, защиты, дальности хода, запаса жизней.

Выбор героя осуществляется клавишами 1 — 4. Поиск игры с выбранным героем — Enter.

3f45a5fbd8184ba7b6e148121e68201a.png

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

Можно было и не так вырвиглазно нарисовать, но не суть.

Какие данные имеются?


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

По порядку:

  • Местоположение всех юнитов в игре;
  • Парамерты героев, выбранных игроками;
  • Принадлежность к команде;
  • Очерёдность хода.

Поговорим отдельно про каждый пункт.

1. Местоположение юнитов. Конечно на основе этой информации рисуются юниты на поле, но можем ли мы не хранить эти данные на сервере? Нет, и вот почему. Если эта информация не хранится, то и проверять то как передвигаются юниты мы не можем. А значит в независимости от скорости персонажа, он может хоть в другой конец карты, хоть на луну.

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

3. Очерёдность хода так же влияет на игру. Мы же не ходим чтобы кто-то ходил по пять раз за ход, оправдываясь что у него сработала инициатива.

4. Принадлежность

Теперь всё вышеперечисленное на примере запроса на атаку (unit1 атакует unit2):

ATTACK unit1_id unit2_id

Запрос в реальной игре, в зависимости от механики, может посылать дополнительные данные:
{"game_key":"...","private_key":"...","action":"attack","attacked":{"x":4,"y":2},"old_position":{"x":4,"y":3}}

Где attacked это положение атакуемого юнита, a old_position — положение откуда будет производиться атака.

На самом деле это всё, что нужно серверу. Ему остаётся провести следующие операции:

  1. Проверить что ход принадлежит unit1
  2. Проверить что запрос отправлен от пользователя которому принадлежит unit1
  3. Проверить может ли unit1 атаковать unit2

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

e3c44452298a4cae877f3b170854b45a.png

Как клиент обновляет своё состояние? Запрос сервера (да, именно запрос):

{"new_position": {"y": 2, "x": 2}, "request": "move"}

И этого достаточно. Ведь игра знает какому юниту принадлежит ход. И знает что информация проверена. А значит нужно просто перерисовать активного юнита по новым координатам.

Если вы только начинаете, не грех будет дать совет, дублируйте вообще всю информацию.

Как поступать с неверными данными?


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

Исходный код

Если найдётся достаточно пользователей можно потестить.

P.S. Ищу работу Python/Django разработчика. По всем вопросам в личные сообщения или на почту.

Комментарии (1)

  • 21 января 2017 в 12:00

    0

    А зачем клиент в команде атаки посылает координаты текущего положения? Эта информация должна уже быть на сервере, клиент только указывает направление атаки.

© Habrahabr.ru