クライアント側の予測はどのように機能しますか?


33

私はValve + GafferonとGoogleの何百ものページを読みましたが、何らかの理由でクライアントの予測に頭を悩ませることはできません。

私の理解では、基本的な問題は次のとおりです。

  • クライアントAは入力を送信します T0
  • サーバーはで入力を受け取ります T1
  • すべてのクライアントが変更を受け取ります T2

T2しかし、クライアントの予測を使用して、クライアントAは、に位置適切になりましたT4

サーバーが移動要求を受け入れると予測するときに、クライアントAがサーバーの前にいないことをどのように確認しますか?明らかに、常に先を行っているため、サーバーが最後に見た場所に戻ってしまいます。私が試したすべての修正を行っても、サーバーはあなたの後ろで停止するため、停止してもこれは依然として顕著です

回答:


35

これに関する一連の記事を書きまし。それはあなたが他の場所で読んだ同じアイデアに基づいていますが、非常に詳細で(私は)アクセスしやすい方法で説明しました。

特に、クライアント側の予測に関する記事はこちらです。


素晴らしい記事:-)シリーズの第4部をご覧ください。小さな提案として、各記事の最後にある次の部分へのリンクは、確か​​にナビゲーションを改善します。
ORマッパー

5
@ORMapper-ついに4番目の記事を書きました!gabrielgambetta.com/fpm4.html
ggambett

あなたの記事シリーズへの称賛:-)非常に参考になりました、ありがとう:-)
ORマッパー

保存されたスナップショットを使用して過去を再構築することについて話すすべての記事(私が見つけることができます)は、例として撮影を取ります。これは動きにも当てはまりますか?動きの再シミュレーションは、他のプレイヤーが互いに衝突する可能性がある場合、他のプレイヤーにとって大きな違いにつながる可能性があると想像できます。2人のプレイヤーが互いに反対に動き、そのうちの1人が衝突点である「ステップ」から少し移動するのを止めたとしましょう。この停止コマンドは遅れのために遅れて到着するため、世界を再シミュレートすると、2人のプレイヤーは非常に異なるポジションになります
ロペ

それは興味深い質問です。残念ながら、決定的な答えはありません。ゲームの動きがどれほど重要かによると思います。他の人にぶつかっても何も起こりませんか?その場合、サーバーはおそらく気にせず、予測の誤りと見なされます(チョークポイントで発生するのを見たことがあるでしょう?)。接触して他のプレイヤーを殺しますか?その場合、それを正しくすることははるかに重要であり、再シミュレーションする価値があるかもしれません。
-ggambett

4

私は実際にこれを実装していません(そのため、すぐには見られない問題があるかもしれません)が、私は助けようと思った。

あなたが言ったことは次のとおりです。

クライアントAはT0で入力を送信します

サーバーはT1で入力を受け取ります

すべてのクライアントはT2で変更を受け取ります

ただし、T2では、クライアント予測を使用して、クライアントAはT4に適切な位置にあります。

サーバー時間の観点から考えると便利でしょう。その(おそらく)補間の仕組みに非常に似ています。

すべてのコマンドはサーバー時間とともに送信されます。このサーバー時間は、サーバーティックを照会してping時間を補正することにより、一致の開始時に計算されます。クライアントでは、独自のローカルティックカウントがあり、送信する各コマンドはサーバーティックに変換されます(単純な減算操作です)

また、クライアントは常に「過去」にレンダリングしています。したがって、クライアントが見る世界は、たとえばサーバーの実際の時間より100ミリ秒遅れていると仮定します。

サーバー時間(Sで指定)を使用して例を言い換えましょう。

クライアントは、サーバー時間S0でT0に入力を送信します(これは、実際には「サーバー時間から補間時間を引いたクライアント表現」です)。クライアントはサーバーからの応答を待たずにすぐに移動します。

サーバーはT1で入力を受け取ります。サーバーは、クライアントによって指定されたサーバー時間S0でクライアントの信頼できる位置を把握します。それをクライアントに送信します。

クライアントは、T2で権限のある位置を受け取ります(サーバー時間S0の指定もあります)。クライアントは、過去のイベントに相当する過去の時間を追跡します(おそらくすべての未確認の予測のキュー)。

サーバーがS0に送り返す予測位置/速度/何でも、クライアントがS0に保存したものと異なる場合、クライアントはこれを何らかの方法で処理します。プレーヤーを過去の位置にスナップバックするか、以前の入力を再シミュレートするか、またはおそらく私が考えていない他の何かによって。


3
過去のクライアントレンダリングに関するビットを除き、それはすべて正しいです。サーバーに対して、クライアントは実際に将来レンダリングしています!サーバーは、各クライアントから取得した情報が古く、それ以降各クライアントがすでに変更されていることを認識しています。
キロタン

2

実際、githubにはオープンソースの実装があり、これがどのように行われるかを示しています。Lance.ggをご覧ください

githubリポジトリ:https : //github.com/lance-gg/lance

クライアント予測コードは、と呼ばれるモジュールに実装されます src/syncStrategies/ExtrapolateStrategy.js

外挿のほかに、上で言及されていない2つの概念があります。

  1. 増分曲げ。 基本的に、サーバー修正を一度にすべて適用するのではなく、デルタを少しずつ適用します。これにより、リモートオブジェクトはサーバーの位置に合わせて徐々に位置を調整します。位置曲げ、速度曲げ、角度曲げ、角速度曲げがあります。また、オブジェクトごとに異なる曲げ係数が必要な場合があります。
  2. ステップ再制定。 データが過去にあるという事実は、サーバーのデータ時間に時間をロールバックし、その時点から再開できることを意味します。もちろん、そこにジャンプするのではなく、新たに見つかった位置に向かって曲げる必要があります。

1

クライアントAは常にサーバーより先にありますが、問題ではありません。サーバーが報告された位置に問題があると言った場合にのみクライアントを元に戻す必要があります。サーバーで。

これを行うには、クライアントは過去の状態と過去の更新の一部を記憶する必要があります。これは、位置、速度、方向、そのようなことなど、いくつかの単純な値にすぎない場合があります。サーバーは、さまざまなクライアントの更新が合法であるという確認を定期的に送信します。これは、クライアントからそれらを忘れることができることを意味します。ただし、サーバーが更新が無効であると報告した場合、クライアントの状態はその時点までロールバックし、将来の変更はその変更された状態に適用されます。

Valveの記事の下部には、読む価値のある追加のリンクがあります-これはそのうちの1つです:https : //developer.valvesoftware.com/wiki/Prediction


だから、私は(で、クライアントがその権利思考にしていますt=4)に関する情報を受け取りt=2、それは状態をリセットように、t=2からオブジェクトを持参し、その後再実行更新をt=2しますかt=4
ジョージダケット

なんらかの理由でまだ把握していません。サーバーはプレイヤーの位置を知らされるのではなく、入力のみを伝えられます。そのため、プレイヤーはサーバーが言った最後の位置から移動しています。入力が適用されます。サーバーに通知されます。サーバーは全員への入力を確認します。すべてのコマンドが受け入れられたと仮定すると、サーバーはまだクライアントAの背後にあります。したがって、クライアントAが停止すると、そのキャラクターはすぐに停止し、停止確認を受信するとサーバーの場所に戻ります。
クリスエヴァンス

@GeorgeDuckett:はい(t = 4である必要はありませんが、不一致が検出されるたびに発生する可能性があり、再適用された更新がいくつでもある可能性があります。)
Kylotan

@ChrisEvans:既知の状態+入力に基づく変更は、とにかく状態を送信することと同等です。停止の例については、それ自体が入力であり、サーバーはその入力を受け取るまで移動をシミュレートしています。一定のレイテンシを想定すると、クライアントはサーバーの前方にいたため、サーバーはプレイヤーが移動を停止したときに見たのとまったく同じ位置でプレイヤーの移動を停止します。(現実の世界では、待ち時間はさまざまなので、少し補間して滑らかにします。)
Kylotan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.