MMOのサーバーとの低トラフィッククライアント同期


22

プレイヤーが矢印キーで宇宙船を操縦して宇宙船で飛行し、他のプレイヤーと協力するMMOを実装しています。

プレイヤーがロケットなどから船をかわすことができるように実装したいので、サーバー使用と同じ世界をシミュレートするアルゴリズムを使用して、クライアント側でゲーム全体の状態を予測しようとしています。そのゲームワールドはC#で記述され、クライアント内で直接呼び出され(Unity3Dで記述されます)、C ++サーバー上のCLRを介して(Linuxの下で)呼び出されます。UDPを介した接続。

問題は、たとえば、単一のマップ内で1000人のプレーヤーを維持する方法です(他のすべてのゲームオブジェクト、Mobを除く)。

  • サーバーをクライアントと毎秒50回同期する
  • (一定の半径内で)彼が見ることができるゲームオブジェクト(およびプレイヤー)の状態を各クライアントに送信する
  • ビュー半径内の各プレイヤーに100個のオブジェクトを送信する必要があります
  • ゲームオブジェクトごとに平均50バイトを送信する必要があります(id、x、y座標、回転、状態...)

そのため、次のようなネットワーク帯域幅が必要になります:1000(クライアント)* 50(1秒あたりの回数)* 100(各プレーヤーに送信するオブジェクト)* 50(オブジェクトあたりのバイト数)= 250 000 000バイト/秒!それは不可能だ!

どういうわけかこの値を減らすことは可能ですか?たとえば、クライアントがゲームの世界を(長期間)完全にシミュレートし、他のクライアントの入力だけを送信し、数秒ごとにゲームの世界を同期できるようにします。 。

とにかく、そのようなゲームはどのように一般的な方法でプログラムされていますか?ありがとうございました。


1
オブジェクトに関する論理的な情報(世界の位置、現在の状態(1バイト)など)だけを送信します-グラフィックは送信しません。
スラヴ

1
@スレーブ:いいね!ビットシフトはすべて、ASMプログラミングの日々を思い出させます。
ランドルフリチャードソン

1
なぜ「今日の日」ではないのですか?:) AS3、Java、Lua、C#で書いてそのようなパフォーマンスの低下に直面すると、C ++が恋しくなり、ASMのことを思い出します。
スラヴ

1
@Slav:へー、私は最近あまりASMをしていません。私にとってのほとんどはJavaとPerl(ほとんどmod_perl2)にありますが、これらの言語も本当に楽しんでいます。
ランドルフリチャードソン

2
@Slav氏は次のように書いています。「AS3、Java、Lua、C#で書いてそのようなパフォーマンスの低下に直面したとき、C ++が恋しくて、ASMのことを思い出します」。LuaとC#を適切に使用する方法を学習する必要があります。おそらく、パフォーマンスはそれほどひどくないでしょう。また、(おそらく)最速のスクリプト言語について不満を言うのはせいぜい1つだけです...これはリアルタイムのヒトゲノム解析に関するゲームですか?
レイン

回答:


20

1秒間に必要な更新は約30(またはさらに少ない場合は10または20)です。クライアント側の移動オブジェクトの位置を補間します。一般的に、本当に必要な場合にのみデータを送信する必要があります。WoWでは、同じ場所にいるプレイヤーよりも、グループにいるプレイヤーからより多くの更新を受け取ることがあります。また、他のプレイヤーがあなたから遠く離れている場合、そのプレイヤーに関する1秒あたりの更新数は多くなりません。

次に、各プレーヤーが接続するときに、完全なスナップショットを1つだけ送信します。その後、ゲームオブジェクトの変更のみを送信します。変更が発生していない場合は、送信しないでください。

次に、BitVectorsを頻繁に使用するか、不要なデータの量を減らすためにBitVectorsを呼び出します。例:1バイトのみ(0から1または-1から1の範囲)を使用してfloatを書き込もうとすると、256または128の異なる値しかありません。しかし、補間のおかげで、プレイヤーはぎくしゃくした動きに気付かないでしょう。

データの圧縮方法に関するLidgrenLibraryの例については、こちらをご覧くださいhttp ://code.google.com/p/lidgren-network-gen3/wiki/Optimization

次:プレーヤーが移動するときの表示半径を減らし、その時間に重要な情報のみを送信するようにします。その後、停止すると、表示半径が再び増加します。空間ハッシュシステムまたはbspツリーを使用して、「範囲内」にあるオブジェクトを検索するオーバーヘッドを削減できます。これは、トピックの良い読み物です:http : //en.wikipedia.org/wiki/Collision_detection

また、データ圧縮、自分でだけでは、データ構造と(とすべきで悪用される可能性があります)データの時間的コヒーレンスについて知っているが。Bzip2、Deflateなどの一般的なアルゴリズムを使用する必要がありますが、圧縮の最終段階としてのみ使用してください。

また、ゲームに重要でない情報については、追加のP2Pテクニックを使用することもできます。例:プレーヤーは「hello」アニメーションを再生します。(グラフィック効果のみ)プレーヤーはこの情報をサーバーに送信しますが、サーバーは他のプレーヤーに情報を中継しません。その代わり、この重要ではない効果は、プレイヤー自身によって範囲内の他のクライアントに送信されます。

編集(コメントのため):

各プレーヤーの1秒あたりの平均ビット数を減らす追加の方法:

  1. 「オブジェクトは変更されませんでした」というメッセージを送信しました。これを行う理由はありません。パケット損失を心配する場合(そして、このためにシミュレーションが同期しないようにする場合)、以下を考慮してください:各固定タイムステップ(例:100、200、300、400 ...)でシミュレーション状態をハッシュし、サーバーに送信します。サーバーは、すべてのデータの完全なスナップショットを確認または送信します。

  2. ロケットやプレーヤーのようなものについては、シミュレーションをより現実的にするために、補間だけでなく外挿も使用できます。例 'Rocket':「Is now at position x」などのメッセージで更新する代わりに、次の内容を含むメッセージを1回送信するだけです。「Rocket Spawned:position(vector)、Time(at which step step the rocket is spawned))、velocity(ベクター)"。先端は常に「速度」方​​向になるため、回転を含める必要さえありません。

  3. 1つのメッセージに複数のコマンドを組み合わせて、udpヘッダーがメッセージ自体よりも大きくなるため、16〜20バイト未満のメッセージを送信しないでください。また、プロトコルのMTUよりも大きいパッケージを送信しないでください。断片化により、転送速度が遅くなります。


ああ、いくつかのオブジェクトを他のオブジェクトよりも頻繁に更新し、P2Pを使用し、浮動小数点の精度を下げ、変更のみを送信することをお勧めします(定期的にオブジェクトを同期するつもりでしたが、「オブジェクトは変更されませんでした」も)。これらすべての変更により、全体像がよりリアルに見えます!
スラヴ

1
「オブジェクトは変更されませんでした」タイプの通知を送信することは、ネットワークだけでなく処理にも要求をかける可能性があるため、忙しい時間にプレイヤーがゲーム中にどのように動作するかを確認するためのテスト目的に役立つテクニックかもしれませんが、これよりもさらに優れたソリューションがあります(実際のゲーム内キャラクターを制御するスタンドアロンデーモンを作成し、異なるマシンからそのデーモンを複数回実行するなど)。
ランドルフリチャードソン

5

以下に2つのアプローチを示します。

最初:
決定論的物理学に切り替え、プレイヤーコマンド、AIアクション、表示されるオブジェクト、およびクライアント側で決定できないものをクライアントに送信します。これには、非コマンド、特定の時点までに送受信されたコマンドのみが適用されることの確認を含める必要があります。

クライアントは、2つまたは3つの同時シミュレーションを実行する必要があります。
1:次のステップのデータが欠落するたびに停止します。
2:推測データの使用を継続し、レンダリングに使用される状態を提供します。3:1が停止するたびに、このシミュレーションは1の状態をコピーし、現在の時間に追いつき、2を引き継いでからドロップします。

追いつきが十分に速い場合は、2と3の違いを除外して、古いデータをただちに削除できます。

2番目:
決定論的な物理学を使用せず、上記と同じことを行いますが、「フルフレーム」を数秒に1回送信します。弾丸のような一時的なものの転送を完全に省くことができます。

どちらの場合も、誰かが死ぬことをクライアントが予測することを警戒したいかもしれません。相手が爆発するのを見るとちょっと馬鹿げています。

そして、数学を行うために+1すると、あまりにも多くの人々が単純なリソース使用の見積もりをすることに失敗します。


2
「決定論的物理学」とは、浮動小数点値または異なるシミュレーションステップを使用できないことを意味しますか?たとえば、ロケットがクライアントの敵の砲塔に通り過ぎてサーバーに衝突すると(浮動小数点の不正確さのため)プレイヤーが次のサーバーの同期パケットまでその砲塔と戦い続ける場合に、重大な非同期が発生するのではないかと思います(数秒)。
スラヴ

3
これは整数と固定時間ステップを意味します。理論的には、フロートポイントをモックして動作させることができますが、整数を使用する方が簡単です。ミサイルが欠けている例でポイントがあります。非決定論的な物理学を使用する場合は、サーバーが死を完全に処理し、死/破壊のケースを迅速に送信するのがおそらく最善です。
aaaaaaaaaaaa

5

最初にいくつかの質問。

「ロケットまたは他の何か」はインテリジェントまたは愚かですか?それらが愚かな場合、必要なのは、火災のタイムスタンプ、原点、およびそれらのパスをシミュレートするベクトルだけです。彼らが知的であれば、彼らはどれほど知的か?火災時に、彼らがヒットまたはミスすることを計算できますか?その場合、クライアントでパス全体をシミュレートできます。(「T13でミサイルは船がドッジロールを失ったためにミサイルを攻撃します。シューターはクリティカルヒットを記録しました。」)

一般的には、A)50Hzのクロックレートを使用する理由はほとんどありません(ほとんどのシューターは15-20でMMOはそれよりも少なくなります)。B)フレームごとにフルステートを送信します。(宇宙でのミサイルの回転はまったく問題ですか?それとも、「前方」が移動するベクトルに沿って方向付けられていると仮定できますか?)

予測と補間に時間を費やすと、帯域幅が急激に低下します。私が取り組んだプロジェクトの更新レートは10Hzで、オブジェクト状態の表現は14バイトだと思います。(できる限りすべて圧縮します!x平面の周りの回転を定義するために6ビットを使用し、その平面の上/下の傾斜に別の6ビットを使用したと思います。実際の回転行列/四元数の送信と区別できませんでした。)

もう1つできることは、オブジェクトの優先順位付けです。表示、関連セットに100個のオブジェクトがあるかもしれませんが、サーバー上の彼の視錐台を知っていますか?彼の見解に何かがなければ、更新頻度を一桁下げることができますか?

一般的な考え方は、クライアント上で完璧なシミュレーションを行うことではなく、不可能です。完璧なシミュレーションではないことにプレイヤーが気付かない楽しいゲームを作成することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.