В эти дни я пытаюсь разработать архитектуру новой мобильной игры MMORPG для моей компании. Эта игра похожа на Mafia Wars, iMobsters или RISK. Основная идея состоит в том, чтобы подготовить армию для сражения с противниками (онлайн-пользователями).
Хотя я ранее работал над несколькими мобильными приложениями, но это что-то новое для меня. После большой борьбы я придумал архитектуру, которая проиллюстрирована с помощью высокоуровневой блок-схемы:
Мы решили использовать модель клиент-сервер. На сервере будет централизованная база данных. Каждый клиент будет иметь свою собственную локальную базу данных, которая будет синхронизироваться с сервером. Эта база данных действует как кэш для хранения вещей, которые часто не меняются, например, карты, продукты, инвентарь и т. Д.
С этой моделью я не уверен, как решить следующие проблемы:
- Как лучше всего синхронизировать серверные и клиентские базы данных?
- Должно ли событие быть сохранено в локальной БД перед его обновлением на сервере? Что если приложение по какой-то причине завершает работу перед сохранением изменений в централизованной БД?
- Будут ли простые запросы HTTP служить цели синхронизации?
- Как узнать, какие пользователи в настоящее время вошли в систему? (Один из способов может заключаться в том, чтобы клиент продолжал отправлять запрос на сервер через каждые x минут, чтобы уведомить его о том, что он активен. В противном случае считается, что клиент неактивен).
- Достаточно ли валидации на стороне клиента? Если нет, как отменить действие, если сервер не проверяет что-то?
Я не уверен, является ли это эффективным решением и как оно будет масштабироваться. Я был бы очень признателен, если бы люди, которые уже работали над такими приложениями, могли поделиться своим опытом, который может помочь мне придумать что-то лучшее. Заранее спасибо.
Дополнительная информация:
Клиентская часть реализована в игровом движке C ++ под названием мармелад. Это кроссплатформенный игровой движок, который означает, что вы можете запускать свое приложение на всех основных мобильных ОС. Мы, конечно, можем добиться многопоточности, что также показано на моей блок-схеме. Я планирую использовать MySQL для сервера и SQLite для клиента.
Это не пошаговая игра, поэтому нет большого взаимодействия с другими игроками. Сервер предоставит список онлайн-игроков, и вы можете сразиться с ними, нажав кнопку боя, и после некоторой анимации результат будет объявлен.
Для синхронизации базы данных у меня есть два решения:
- Сохраните временную метку для каждой записи. Также следите за последним обновлением локальной БД. При синхронизации выбирайте только те строки, которые имеют большую временную метку, и отправляйте их в локальную БД. Сохраняйте флаг isDeleted для удаленных строк, чтобы каждое удаление просто действовало как обновление. Но у меня есть серьезные сомнения по поводу производительности, так как для каждого запроса на синхронизацию мы должны сканировать всю БД и искать обновленные строки.
- Другой метод может заключаться в ведении журнала каждой вставки или обновления, которые выполняются для пользователя. Когда клиентское приложение запрашивает синхронизацию, перейдите к этой таблице и выясните, какие строки какой таблицы были обновлены или вставлены. Как только эти строки успешно переданы клиенту, удалите этот журнал. Но потом я думаю о том, что произойдет, если пользователь использует другое устройство. Согласно таблице журналов все обновления были переданы для этого пользователя, но на самом деле это было сделано на другом устройстве. Таким образом, мы могли бы также отслеживать устройство. Реализация этого метода занимает больше времени, но не уверен, что он выполнил первый.
Ответы:
Если это не игра «в реальном времени» в том смысле, что игрокам не нужно видеть непосредственный результат действий другого игрока на игровой сцене, тогда вы должны быть в порядке с HTTP-запросами. Но имейте в виду, накладные расходы HTTP.
При этом использование HTTP не избавит вас от тщательной разработки протокола связи. Но если вы отвечаете как за сервер, так и за клиентскую часть, вам повезло, поскольку вы можете настроить протокол, когда вам это нужно.
Для синхронизации между главной и клиентской базами данных вы можете использовать любой транспортный протокол, к которому у вас есть доступ, HTTP или другие. Важной частью является логика синхронизации. Для простого подхода просто объедините с сервером все последние изменения, необходимые клиенту с момента последней отметки времени в клиентской БД. Примените это к клиентской БД и продолжайте с этим. Если у вас есть больше изменений на стороне клиента, загрузите их, если они все еще актуальны, в противном случае откажитесь.
Некоторые игры даже не используют локальную БД, они просто отслеживают статус, объединяя необходимую информацию с сервера при необходимости.
Если потеря локальных событий неприемлема, тогда да, вы должны иметь локальное хранилище и сохранять его как можно чаще. Вы можете попробовать сделать это перед каждой отправкой по сети.
Для проверки активных пользователей мы использовали эхо-запрос HTTP каждые 20 секунд в успешной игре ... Это значение сразу же возросло, поскольку серверы были перегружены :( Команда серверов не думала об успехе. Поэтому я бы сказал, что вам нужно добавить сообщение или какой-то специальный заголовок в вашем протоколе связи, который позволит вам перенастроить ваших клиентов (для пинговой балансировки нагрузки по частоте и других связанных с связью значений).
Проверок на стороне клиента достаточно, если вы не против читеров, хакеров и других автоматических скриптов, атакующих вашу игру. Сервер может просто отказаться от вашего действия и отправить сообщение об ошибке с некоторыми подробностями. Вы обрабатываете это сообщение об ошибке, либо откатывая локальные изменения, либо не применяя их к локальному хранилищу, если можете подождать, пока сервер ответит, чтобы фактически сохранить изменения.
Мы использовали шаблон команды в нашей игре, чтобы обеспечить простой и эффективный откат неудачных или недействительных действий пользователя. Команды воспроизводились локально, отправлялись одноранговым узлам или транслировались на серверное сообщение, а затем применялись к одноранговым узлам или проверялись на сервере, в случае возникновения проблем команды не воспроизводились, и игровая сцена возвращалась в исходное состояние с уведомлением.
Использование HTTP не является плохой идеей, так как позже оно позволит вам очень легко интегрироваться с клиентами Flash или HTML5, оно гибкое, вы можете использовать любой тип языка сценариев сервера и с помощью базовых методов балансировки нагрузки добавить больше серверов позже без особых усилий. масштабировать свой бэкэнд.
У вас много дел, но это веселая работа ... Так что наслаждайтесь!
источник
Самый простой способ - реализовать базу данных в виде одного файла, который вы можете передать. Если вы попытаетесь сравнить различия между базами данных, то это будет боль, и я говорю по опыту.
Обратите внимание, что ваш сервер не должен доверять решениям, принимаемым клиентом на основе этой локальной базы данных, поскольку клиент может изменить его. Он должен существовать исключительно для презентационных деталей.
Нет. Что если сервер решит, что событие никогда не произошло? В любом случае клиент не должен принимать решения о событиях, потому что клиенту нельзя доверять.
Я заметил, что вы также говорите о локальной БД двумя способами: один для «вещей, которые часто не меняются» и два для событий. Они не должны находиться в одной и той же базе данных по указанным выше причинам - вы не хотите начинать пытаться объединять или различать отдельные строки данных в базах данных. Например, ссылочная целостность становится проблемой, когда у клиента есть ссылка на элемент, который вы решили удалить с сервера. Или, если клиент меняет строку, а сервер меняет строку, какое изменение имеет приоритет и почему?
Да, если они довольно редки или малы. HTTP неэффективен по пропускной способности, так что имейте это в виду.
Если вы используете временный протокол, такой как HTTP, то это разумная идея. Когда сервер получает сообщение от клиента, вы можете обновить время «последнего просмотра» для этого клиента.
Нет, совсем нет. Клиент в руках врага. То, как отменить действие, полностью зависит от того, что вы считаете действием, и какие последствия оно может иметь. Самый простой способ - вообще не реализовывать действие, пока сервер не ответит, чтобы разрешить его. Немного более хитрый путь - убедиться, что каждое действие имеет возможность отката для отмены действия и кэширования всех неподтвержденных действий на клиенте. Когда сервер их подтвердит, удалите их из кэша. Если действие отклонено, выполните откат каждого действия в обратном порядке, включая отклоненное.
источник