ネットワーク上でデータ構造の同期を維持する方法は?


12

環境

私が取り組んでいるゲーム(一種のポイントアンドクリックグラフィックアドベンチャー)では、ゲームの世界で起こるほとんどすべてのことが、次のような構造のアクションマネージャーによって制御されます。

ここに画像の説明を入力してください

たとえば、オブジェクトを調べた結果、キャラクターに挨拶をさせ、少し歩き、座った場合、次のコードを生成します。

var actionGroup = actionManager.CreateGroup();
actionGroup.Add(new TalkAction("Guybrush", "Hello there!");
actionGroup.Add(new WalkAction("Guybrush", new Vector2(300, 300));
actionGroup.Add(new SetAnimationAction("Guybrush", "Sit"));

これにより、新しいアクショングループ(上の画像の行全体)が作成され、マネージャーに追加されます。すべてのグループは並行して実行されますが、各グループ内のアクションはチェーン化され、2番目のグループは最初のグループが終了した後にのみ開始されます。グループ内の最後のアクションが終了すると、グループは破棄されます。

問題

ここで、この情報をネットワーク全体に複製する必要があります。そのため、マルチプレイヤーセッションでは、すべてのプレイヤーが同じものを見ることができます。個々のアクションをシリアル化することは問題ではありません。しかし、私はネットワーキングに関してはまったくの初心者であり、いくつか質問があります。この説明の単純化のために、アクションマネージャーコンポーネントを次のように抽象化できると思います。

var actionManager = new List<List<string>>();

上記のデータ構造の内容をすべてのプレーヤー間で同期させるにはどうすればよいですか?

コアの質問に加えて、私はそれに関連するいくつかの他の懸念も持っています(つまり、上記と同じ問題のすべての可能な影響):

  • 私は、との1(サーバーとクライアントの両方として動作する選手の一人で)サーバ/クライアントアーキテクチャを使用している場合は、クライアント生み出したアクションのグループを、彼はマネージャーに直接追加、または唯一のリクエストを送信する必要がありますサーバーに、順番にすべてのクライアントにそのグループを追加するように指示しますか?
  • パケット損失などはどうですか?ゲームは決定論的ですが、クライアントで実行されるアクションのシーケンスに矛盾があると、世界の一貫性のない状態につながる可能性があると考えています。そのような問題からどのように保護しますか?
  • 一度に追加するアクションが多すぎると、接続に問題が発生しませんか?それを軽減する方法はありますか?

5
必須の「最初にお読みください」リンクgafferongames.com/networking-for-game-programmersは、いくつかのコードがありますが技術的ではありませんが、冗長であり、オプションをかなりよく説明しています。さらに、そのリンクを読んでいる他のすべての人と対等な立場に立つことができ、それは幸せな場所です。
パトリックヒューズ

@PatrickHughesリンクをありがとう!私は間違いなくすべてを読んでいます。
デビッドゴーベイア

このようなことを管理するパッケージがいくつかあります。私はそれがどれほど効率的か高速かわかりませんが、NowJS(nowjs.com)は興味深い例です。開発者の観点から見ると、クライアントとサーバー間でデータ構造を共有しているだけです。一方を変更し、もう一方を変更します。
ティム・ホルト

回答:


9

サーバー/クライアントアーキテクチャ(サーバーとクライアントの両方として動作するプレイヤーの1つを使用)を使用し、クライアントの1つがアクションのグループを生成した場合、それらをマネージャーに直接追加するか、リクエストのみを送信する必要がありますサーバーに、順番にすべてのクライアントにそのグループを追加するように命令しますか?

この場合、3つのオプションがあり、そのうちの2つはすでに述べました。どのオプションを選択するかは、あなただけが次のことを判断できるさまざまな要因によって異なります。

1:クライアントはアクションのグループを生成し、それらを直接追加してからサーバーに送信します。サーバーはチェックなしでそれを受け入れます

*このアプローチの利点は、クライアントに関する限り、独自のアクションにより、ネットワーク遅延に関係なく即座にフィードバックが得られることです。欠点は、クライアントのメッセージがサーバーによって実際に受け入れられることです(実際にはそうではない場合があります)*

2:クライアントはサーバーにリクエストを送信し、サーバーはリクエストを送信したクライアントを含む全員にリクエストをブロードキャストします。

このアプローチの利点は、違法行為に関するほとんどの問題を軽減するゲーム内で発生するすべてをサーバーが制御できるようになったことです(ここで、違法なのは、クライアントが壁を切り取ってから、サーバーがクライアントが特定の動きをしたときにクライアントが持っていなかった詳細情報)

3:クライアントはアクションのグループを生成し、それらを直接追加してからサーバーに送信します。サーバーはリクエストを処理し、アクションに対して独自のチェックを実行してアクションが違法ではないことを確認してから、クライアントを含むすべてのプレーヤーに動きをブロードキャストします。

これにより、帯域幅の要件がわずかに増えますが、1と2の両方の利点が得られます。利点は、クライアント自身の移動に対するクライアントへの即時フィードバックであり、クライアントが行う移動が違法である場合、サーバーは適切なアクションを実行します(クライアントを強制的に修正します)。

パケット損失などはどうですか?ゲームは決定論的ですが、クライアントで実行されるアクションのシーケンスに矛盾があると、世界の一貫性のない状態につながる可能性があると考えています。そのような問題からどのように保護しますか?

パケット損失と極端な遅延は修正が難しい問題です。ゲームのタイプ(推測航法など)に応じて、さまざまなソリューション(いずれも完璧ではない)を使用して問題に対処します。私はあなたのゲームが物理学を同期する必要がないと仮定します。

最初にすべきことの1つは、すべての動きにタイムスタンプを付けることです。システムはこれらを考慮し、それに応じて動き再生ます(おそらくサーバーがこの責任を負い、違法な動きを拒否します)。このシステムを実装するときは、待ち時間を0と想定します(ローカルでテストします)。

もちろん、ローカルネットワークであっても、待ち時間0は適切な仮定ではないため、すべての移動が時間を尊重するようになった今、どの時間を信頼しますか?ここで、時刻同期の問題が発生します。多くのオンラインの記事/論文は、この問題を解決するためのガイドとなります。

一度に追加するアクションが多すぎると、接続に問題が発生しませんか?それを軽減する方法はありますか?

まず明らかなもの。文字列またはシリアル化されたオブジェクトを送信しないでください。ゲーム自体が更新しているのと同じ速さでメッセージを送信しないでください。チャンクで送信します(たとえば、1秒間に10回)。サーバー/クライアントがたまにエラーを修正する必要があるエラー(特に丸めエラー)があります(したがって、サーバーはすべてを送信します[すべて=ゲーム内の物事を正しい状態に保つために重要なすべてのデータ状態]その後、クライアントはスナップします状態を修正するためにし、および/または考慮します)。編集:私の同僚の一人は、UDPを使用している場合(大量のデータがある場合はこれを使用する必要があります)、ネットワークの順序付けはないと述べました。1秒間に10個を超えるパケットを送信すると、順不同で到着するパケットの変更が増加します。その主張を引用できるかどうかを確認します。異常パケット自体については、それらを破棄するか、過去の変更を処理して現在の状態を修正するように設計されたシステムのメッセージ/移動キューに追加できます。

スペースをほとんど占有しない何かに依存するメッセージングシステムが必要です。2つの値しか持てないものを送信する必要がある場合は、1ビットのみを送信します。256の移動しかできないことがわかっている場合は、符号なし文字を送信します。メッセージをできるだけ密にパックするためのさまざまなちょっとした工夫があります。

メッセージングシステムは、多くの列挙型を使用して、着信メッセージから動きを簡単に抽出できるようにします(ここでの意味がわからない場合は、RakNetとその例を参照することをお勧めします)。

高レイテンシーとパケット損失で発生する問題を修正することはできませんが、その影響をあまり目立たなくすることができることは既に知っていると思います。幸運を!

編集:上記のリンクを持つパトリック・ヒューズのコメントは、この回答を不完全で、せいぜいOPの質問に特化しています。代わりにリンクされたトピックを読むことを強くお勧めします


詳細な対応に感謝します。それは私の懸念のほとんどをカバーしています。あなたが言う部分についての1つの質問ですso every second, the server sends everything ... which the client then snaps to。このような大量の情報を一度に送信できますか?合理的な最大サイズとは何ですか?
デヴィッドゴーベイア

合理的な最大値は、遅延を生じさせない数値になります:)...あなたはその答えを探していなかったのは知っていますが、私はあなたのゲームに慣れていないので数字を書きたくありません。
サマーサ

また、1つの大きなチャンクを送信するという厳しいルールはありません。これを例として挙げました。
サマールサ

@Samaursa-「UDPを使用している場合(大量のデータがある場合に必要です)」というコメントには同意しません。ネットワークプログラミングが初めてであるため、TCPは非常に低速ですが、ほとんどの困難なものを処理します。彼らの場合、ボトルネックになるまでTCPを使用していました。その時点で、彼らは自分のアプリがどのようにネットワークを使用しているかをよりよく理解できるようになり、UDPの実装がより簡単になります。
クリス

@Chris:私は同意しません:) ... TCPとUDPを使用するかどうかの決定は、(imo)開発用にPythonとC ++を選択するかの決定に似ています。理論的には大丈夫に聞こえるかもしれませんが、実際には単純に切り替えるのは難しいでしょう(これもです)。
サマーサ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.