6

マルチユーザー RTS ゲームを (部分的に) C++ でプログラミングする可能性を検討しています。私がすぐに発見したことは、1 つの厳しい要件は、ゲーム シミュレーションがサーバーとすべてのクライアント全体で最後のビットまで完全に決定論的でなければならないことであり、ネットワーク通信をゲームの状態自体ではなくユーザー入力に制限できるようにすることです。 . 誰もが異なるコンピューターを持っているため、これは難しい問題のように思えます。

では、Linux (サーバー)、Windows、および Mac で完全に決定論的な実行可能ファイルを C++ コンパイラに作成させる「魔法の」方法はありますか? 2 つの主な OSS C++ コンパイラは GCC と Clang だと思うので、この点で一方のパフォーマンスが他方より優れているかどうか疑問に思っていました。

また、C++ 決定論の検証に使用できるテスト スイートにも興味があります。

[編集] 決定論的とは、コンパイルされたプログラムが、同じ初期状態と同じ順序の入力を与えられた場合、それが実行されるどのプラットフォームでも、常に同じ出力を生成することを意味しました。したがって、ネットワーク全体でも。一貫性があるというのは、この動作の適切な定義のように思えますが、私はネイティブ スピーカーではないため、正確な意味を誤解する可能性があります。

[編集#2] 決定論/一貫性が重要かどうか、ゲーム エンジンでそれを目指すべきかどうか、C++ で一般的にどれほど大きな問題であるかについての議論は非常に興味深いものですが、実際には決して答えはありません。質問。これまでのところ、Clang と GCC のどちらを使用して最も信頼性が高く、決定論的で、一貫性のある結果を得る必要があるかを誰も教えてくれませんでした。

[編集#3] C++ で Java とまったく同じ結果を得る方法があることに気付きました。JVM のオープン ソース実装を使用して、演算子と数学関数を実装するコードを抽出する必要があります。次に、それをスタンドアロン ライブラリに変換し、演算子を直接使用する代わりに、その中でインライン化可能な関数を呼び出します。手作業で行うのは面倒ですが、コードが生成されれば完璧な解決策です。多分それはクラスと演算子のオーバーロードでもできるので、自然に見えます.

4

5 に答える 5

1

未定義または未指定の動作に依存しないでください (特に、浮動小数点を使用しないでください)。使用するコンパイラは関係ありません。

aが 1 で、bが 2 の場合はa + b3 です。これは、言語標準によって保証されています。

C++ は、一部のコンパイラでは「決定論的」であり、他のコンパイラではそうではない土地ではありません。C++ は、いくつかの事実 (1 + 2 == 3 など) を述べ、一部をコンパイラーに任せます (関数引数の評価順序など)。プログラムの出力が前者 (およびユーザーの入力) のみに依存し、標準準拠のコンパイラを使用している場合、プログラムは同じユーザー入力に対して常に同じ出力を生成します。

プログラムの出力が (たとえば) ユーザーのオペレーティング システムにも依存している場合、プログラムは依然として決定論的です。出力がユーザーの入力とオペレーティング システムの両方によって決定されるだけです。ユーザーの入力のみに依存する出力が必要な場合は、ユーザーのオペレーティング システムがプログラムの出力に影響しないようにする必要があります。これを行う 1 つの方法は、言語標準によって保証された動作のみに依存し、その標準に準拠するコンパイラを使用することです。

要約すると、すべてのコードは入力に基づいて決定論的です。入力が必要なものだけで構成されていることを確認する必要があります。

于 2012-02-26T01:14:15.773 に答える
1

誰もが異なるコンピューターを持っているため、これは難しい問題のように思えます。

そうではありません。実際、この種のネットワーキングは、仕様で定義されていないことを何もしない限り、非常に単純です。IEEE-754は、浮動小数点演算の実行方法、丸めの実行方法などについて非常に明確であり、プラットフォーム間で同じように実装されています。

あなたがする必要のない最大のことは、決定論的である必要があるコードの SIMD CPU 命令に依存することです (注: これは物理学、AI などです: ゲームの状態です。SIMD が必要なグラフィックスではありません)。これらの種類の命令は、浮動小数点の規則で高速かつ緩く再生されます。したがって、ゲーム コードに SIMD はありません。「クライアント」コード (グラフィック、サウンドなど) のみ。

また、ゲームの状態が時間などに依存しないようにする必要があります。各ゲーム ステート クロック ティックは、PC のクロックやその性質に基づくものではなく、一定の時間間隔である必要があります。

明らかに、コードを持っていないランダム関数は避けるべきです。ただし、メインのゲームプレイ ループのみです。グラフィックは単なるビジュアルであり、問​​題ではないため、クライアント固有のものにすることができます。

2 つのゲーム ステートの同期を維持する限り、これでほぼ完了です。使用するコンパイラは、大きな問題にはなりません。

StarCraft と StarCraft II は、これをネットワーク モデルの基礎として使用していることに注意してください。どちらも Mac と PC で動作し、互いに対戦することができます。したがって、それは非常に可能であり、Clang は必要ありません。

ただし、Clang が好きな場合は、それを使用する必要があります。しかし、それはネットワーキングのためではなく、あなたが好きだからであるべきです。

于 2011-07-10T11:41:14.320 に答える
0

使用しているコンパイラはそれほど重要ではないと思います。

このような完全に決定論的なアプローチは、たとえば Doom で使用されました。乱数ジェネレーターの代わりに、固定の「乱数」配列を使用していました。ゲーム時間はゲーム内ティックで測定されました (覚えていれば、約 1/30 秒でした)。

さまざまなバージョンで提供される可能性のあるいくつかの標準ライブラリに作業をオフロードするのではなく、ゲーム内のメカニズムによってすべてを測定する場合、さまざまなマシン間で優れた移植性を実現できるはずです。もちろん、それらのマシンがコードを実行するのに十分な速さである場合に限ります!

ただし、ネットワーク通信自体が遅延やドロップなどの問題を引き起こす可能性があります。ゲームは遅延メッセージを処理し、必要に応じてゲーム自体を再同期できる必要があります。たとえば、ユーザー入力のみに依存するのではなく、完全な (または少なくとも: より詳細な) ゲーム ステートを時々送信したい場合があります。

エクスプロイトの可能性についても考えてください。

  • クライアント: 私は手榴弾を投げています
  • サーバー: 手榴弾がありません
  • クライアント: 気にしません。それでも手榴弾を投げる
于 2011-07-10T11:42:48.153 に答える
0

これはややばかげた用事です。あなたのプログラムは、ビッグ エンディアン マシン対リトル エンディアン マシンでも、64 ビット マシン対 32 ビット マシン対他のランダム マシンでも、「完全に決定論的」(それが何を意味するにせよ) 「最後のビットまで」ではありません。

ランダムといえば、多くのゲームにはランダム性の要素があります。C 標準関数 rand() を呼び出してこれを達成している場合、すべての賭けはオフです。

于 2011-07-10T11:43:30.660 に答える
0

浮動小数点の使用を開始すると、すべての賭けが無効になります。Intel または AMD の CPU を選択するだけで、同じプラットフォームでも異なる値が得られるという問題を見つけたり修正したりするのは困難です。

多くのランタイム ライブラリには、さまざまなチップのコード パスが最適化されています。これらはすべて仕様の範囲内ですが、一部はそれよりもわずかに正確です。これにより、微妙な丸め誤差が発生し、遅かれ早かれ、問題が発生する可能性のある差に蓄積されます。

あなたの目標は、100% determinisim なしで逃げることです。結局のところ: 対戦相手が必要以上に左に 1 ピクセル離れていても、プレイヤーにとって問題になるのでしょうか? そうではない。重要なのは、クライアントとサーバーのわずかな違いがゲームプレイを台無しにしないことです。

プレーヤーが自分の画面に表示するものは決定論的に見えるべきなので、だまされたと感じることはありませんが、必須ではありません。

私が取り組んできたゲームは、すべてのクライアント間ですべてのエンティティのゲーム状態を常に再同期することで、これをアーカイブしました。ただし、ゲームの状態全体を送信することはほとんどありませんでしたが、フレームごとにいくつかのオブジェクトのゲームの状態を送信し、数秒間にわたってジョブを分散させました。

最も重要なオブジェクトに他のオブジェクトよりも高い優先度を与えるだけで問題ありません。たとえば、カーレース ゲームでは、対戦相手の車が遠くにある場合、正確な位置を取得しても問題はありません。また、20 秒程度ごとに更新するだけで問題ありません。

これらの更新の合間には、小さな丸め誤差があまり蓄積されず、問題が発生することはないと信じています。

于 2011-07-10T12:14:44.590 に答える