これは、MMORPGモバイルゲームに適したアーキテクチャですか?


14

最近、私は会社のために新しいMMORPGモバイルゲームのアーキテクチャを設計しようとしています。このゲームは、マフィア戦争、iMobsters、またはリスクに似ています。基本的な考え方は、敵(オンラインユーザー)と戦うために軍隊を準備することです。

以前は複数のモバイルアプリに取り組んできましたが、これは私にとって新しいことです。多くの苦労の末、高レベルのフロー図を使用して説明するアーキテクチャを思いつきました。

高レベルのフロー図

クライアントサーバーモデルを使用することにしました。サーバーに集中データベースがあります。各クライアントには、サーバーとの同期を維持する独自のローカルデータベースがあります。このデータベースは、マップ、製品、在庫など、頻繁に変更されないものを保存するためのキャッシュとして機能します。

このモデルが適切に配置されているため、次の問題に取り組む方法がわかりません。

  • サーバーとクライアントのデータベースを同期する最良の方法は何でしょうか?
  • イベントをサーバーに更新する前に、ローカルDBに保存する必要がありますか?集中DBに変更を保存する前に、何らかの理由でアプリが終了した場合はどうなりますか?
  • 単純なHTTP要求は同期の目的を果たしますか?
  • 現在ログインしているユーザーを知る方法は?(1つの方法は、クライアントがアクティブであることを通知するためにx分ごとにサーバーにリクエストを送信し続けることです。
  • クライアント側の検証は十分ですか?そうでない場合、サーバーが何かを検証しない場合にアクションを元に戻す方法は?

これが効率的なソリューションであるかどうか、およびどのように拡張されるかはわかりません。すでにそのようなアプリに取り組んでいる人々が自分の経験を共有できれば、もっと良いものを思い付くのに役立つかもしれません。前もって感謝します。

追加情報:

クライアント側は、マーマレードと呼ばれるC ++ゲームエンジンに実装されています。これは、すべての主要なモバイルOSでアプリを実行できることを意味するクロスプラットフォームゲームエンジンです。私たちは確かにスレッド化を達成することができ、それは私のフロー図にも示されています。サーバーにMySQLを、クライアントにSQLiteを使用する予定です。

これはターンベースのゲームではないため、他のプレイヤーとのやり取りはあまりありません。サーバーはオンラインプレーヤーのリストを提供し、バトルボタンをクリックしてバトルを行うことができます。いくつかのアニメーションの後、結果がアナウンスされます。

データベースの同期には、2つのソリューションがあります。

  1. 各レコードのタイムスタンプを保存します。また、ローカルDBが最後に更新された日時を追跡します。同期するときは、タイムスタンプの大きい行のみを選択して、ローカルDBに送信します。削除された行にはisDeletedフラグを保持して、すべての削除が更新として動作するようにします。しかし、すべての同期要求について、完全なDBをスキャンし、更新された行を探す必要があるため、パフォーマンスに関して深刻な疑問があります。
  2. 別の手法として、ユーザーに対して行われた各挿入または更新のログを保持することもできます。クライアントアプリが同期を要求したら、このテーブルに移動して、どのテーブルのどの行が更新または挿入されたかを見つけます。これらの行がクライアントに正常に転送されたら、このログを削除します。しかし、ユーザーが別のデバイスを使用するとどうなるかを考えます。ログテーブルによると、すべての更新はそのユーザーに転送されましたが、実際には別のデバイスで行われました。そのため、デバイスも追跡する必要があります。この手法の実装には時間がかかりますが、最初の手法が実行されるかどうかはわかりません。

2
私はMsSQLの評価を取得し、それをいじくります-MySQLがレプリケーションに関して何を提供するのかはわかりませんが、MsSQL 2008 R2はあなたに選択するためのレプリケーション(5-6)のテクニックを提供します。考えは、MySQLなどを嫌うものではありませんが、Microsoftは本当にクラスタリングが得意です。
ジョナサンディキンソン

1
@ジョナサンディキンソン:MySQL Clusterのがあります:P
コヨーテ

1
PostgreSQLもご覧ください-バージョン9にはレプリケーションテクノロジーがあり、PostgreSQLは非常に高い負荷をうまく処理できるという長年の名声があり、多くの開発者は最適化のナッツであり、何よりもオープンソースであり、すべての用途で完全に無料です(コマーシャルを含む)。
ランドルフリチャードソン

問題は、クライアント側とサーバー側で同じデータベースを使用できないことです。クライアントに最適なDBはSQLiteで、モバイルデバイスでアプリが実行されるので多くのリソースを消費しないと思います。サーバー部分で作業している人はMySQLしか知らないので、それを選択したのはそのためです。また、ほとんどのMMOゲームはMySQLデータベースを使用していると聞きました。
-umair

1
@umair:クライアント側はSQLiteにすることができます(たとえばiPhoneでは既に利用可能です)。ただし、必要な関連データのみをファイルに保存することを選択して(SQLiteが何をするにしても)、Javascriptアプリのようにクライアント側のDBに煩わされることはありません。
コヨーテ

回答:


15

プレイヤーがゲームシーンで他のプレイヤーのアクションの結果をすぐに見る必要がないという意味で「リアルタイム」ゲームでない場合は、HTTPリクエストで問題ないはずです。ただし、HTTPのオーバーヘッドに留意してください。

ただし、HTTPを使用しても、通信プロトコルを慎重に設計する必要はありません。ただし、サーバー側とクライアント側の両方を担当している場合は、必要なときにプロトコルを調整できるので幸運です。

マスターDBとクライアントDBの間で同期をとるには、アクセスできるHTTPまたはその他のトランスポートプロトコルを使用できます。重要な部分は、同期の背後にあるロジックです。簡単なアプローチでは、クライアントDBの最後のタイムスタンプ以降にクライアントが必要とするすべての最新の変更をサーバーからプールします。それをクライアントDBに適用し、それを実行します。クライアント側でさらに変更がある場合は、関連する場合はアップロードし、そうでない場合は破棄します。

一部のゲームはローカルDBさえ使用せず、必要に応じてサーバーからの関連情報をプールすることでステータスを追跡します。

ローカルイベントを失うことが許容できない場合は、はい、ローカルストレージを用意し、できるだけ頻繁にそのストレージに保存する必要があります。各ネットワークが送信する前にそれを試すことができます。

成功したゲームで20秒ごとにHTTPでpingを実行していたアクティブユーザーを確認するために...サーバーが過負荷になると、この値はすぐに上がりました:(サーバーチームは成功について考えていませんでした。通信プロトコルのメッセージまたは何らかの特別なヘッダー。これにより、クライアントの再構成が可能になります(ping周波数負荷分散およびその他の通信関連の値用)。

ゲームを攻撃する詐欺師、ハッカー、その他の自動スクリプトを気にしないのであれば、クライアント側の検証で十分です。サーバーは単にアクションを拒否し、詳細を含むエラーメッセージを送信できます。サーバーが応答して変更を実際に保存するまで待機できる場合は、ローカルの変更をロールバックするか、ローカルの変更を適用しないことで、このエラーメッセージを処理します。

ゲームでコマンドパターンを使用して、失敗または無効なユーザーアクションを簡単かつ効率的にロールバックできるようにしました。コマンドはローカルで再生され、ピアに送信されるか、サーバーメッセージに変換されてから、ピアに適用されるか、サーバーでチェックされます。問題が発生した場合、コマンドは再生されず、ゲームシーンは通知とともに初期状態に戻りました。

HTTPを使用するのは悪い考えではありません。後で、FlashまたはHTML5クライアントと非常に簡単に統合でき、柔軟性があり、あらゆる種類のサーバースクリプト言語を使用でき、基本的な負荷分散技術を使用すると、後から多くのサーバーを追加することができます。バックエンドをスケーリングします。

やるべきことはたくさんありますが、楽しい仕事です...楽しんでください!


3
おそらく:)であるため、「HTMLはおそらく十分である」ための+1。
ジョナサンディキンソン

1
@Coyote:時間を割いて、そのような詳細な答えを提供してくれてありがとう。他のクライアントにサポートを提供するためのHTTPアイデアに本当に似ています。
umair

1
力があなたと共にありますように:)
コヨーテ

5

サーバーとクライアントのデータベースを同期する最良の方法は何でしょうか?

最も簡単な方法は、転送可能な単一ファイルとしてデータベースを実装することです。データベース間の違いを比較しようとすると、それは苦痛の世界であり、私は経験から話しています。

クライアントはローカルデータベースを変更できるため、サーバーはそのローカルデータベースに基づいてクライアントが下した決定を信頼してはならないことに注意してください。プレゼンテーションの詳細のためだけに存在する必要があります。

イベントをサーバーに更新する前に、ローカルDBに保存する必要がありますか?

いいえ。イベントが発生しなかったとサーバーが判断した場合はどうなりますか?クライアントは信頼できないため、とにかくイベントについて決定するべきではありません。

また、ローカルDBについて2つの方法で話していることに気付きます。1つは「頻繁に変更されないもの」、2つはイベントです。上記の理由により、これらは実際には同じデータベース内にあるべきではありません-データベース内の個々のデータ行をマージまたは差分しようとするのは望ましくありません。たとえば、サーバーから削除することにしたアイテムへの参照がクライアントにある場合、参照整合性が問題になります。または、クライアントが行を変更し、サーバーが行を変更した場合、どの変更が優先されますか?

単純なHTTP要求は同期の目的を果たしますか?

はい、それらがかなりまれまたは小さいことを条件とします。HTTPは帯域幅効率が悪いため、そのことに留意してください。

現在ログインしているユーザーを知る方法は?(1つの方法は、クライアントがアクティブであることを通知するためにx分ごとにサーバーにリクエストを送信し続けることです。

HTTPのような一時的なプロトコルを使用する場合、それは合理的な考えです。サーバーがクライアントからメッセージを受信すると、そのクライアントの「最終確認」時間を更新できます。

クライアント側の検証は十分ですか?そうでない場合、サーバーが何かを検証しない場合にアクションを元に戻す方法は?

いいえ、まったくありません。クライアントは敵の手にあります。アクションを元に戻す方法は、アクションが何であると考えるか、およびアクションにどのような影響があるかによって完全に異なります。最も簡単な方法は、サーバーが応答して許可するまでアクションをまったく実装しないことです。少し注意が必要な方法は、すべてのアクションにロールバック機能を持たせて、アクションを元に戻し、未承認のアクションをすべてクライアントにキャッシュすることです。サーバーがそれらを確認したら、キャッシュから削除します。アクションが拒否された場合、拒否されたアクションを含む、逆の順序で各アクションをロールバックします。


1
あなたはそれを打ちました。DBの同期については正しいです+1クライアントは、それ自体でDBを変更してはいけません...サーバーで実行する関数を呼び出し、ゲームのロジックを使用してDBを更新し、結果を取得します。
コヨーテ

@Kylotan:モデルのフローを指摘してくれてありがとう
umair

@Kylotan:「最も簡単な方法は、転送可能な単一のファイルとしてデータベースを実装することです。データベース間の違いを比較しようとすると、それは苦痛の世界であり、経験から話しています。」これは、アプリケーションが起動されるたびにすべてのデータがダウンロードされることを意味します。非常に頻繁に変更されることはないため、毎回ダウンロードすることは受け入れられない場合があります。これにより、アプリの起動時間が大幅に長くなります。何かご意見は?
umair

データが小さい場合、問題はなくなります。静的データの集中化されたデータベースが非常に大きい場合、私は驚くでしょう。しかし、とにかく、静的データを小さな部分に分割した場合、前回から変更されたもののみを送信する必要があります。もちろん、各行で変更時間を維持する場合は、行ごとにこれを行うことができます。一般に、簡単に上書きできるように、リレーショナルDBの外部に静的データを保持することを好みます。
キロタン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.