Quake 3のような精密なネットワークゲームでサーバーとクライアントのクロックを同期させる方法は?


15

私は2Dトップダウンシューターに取り組んでおり、Quake 3のようなネットワークゲームで使用されるコンセプトをコピーするために最善を尽くしています。

  • 信頼できるサーバーがあります。
  • サーバーはクライアントにスナップショットを送信します。
  • スナップショットには、タイムスタンプとエンティティの位置が含まれます。
  • スナップショット位置間でエンティティが補間されるため、動きがスムーズに見えます。
  • 必要に応じて、エンティティの補間は「過去に」わずかに行われるため、複数のスナップショットを補間します。

私が直面している問題は「クロック同期」です。

  • わかりやすくするために、サーバーとの間でパケットを転送する際のレイテンシーがゼロであると少しの間ふりをしましょう。
  • サーバーのクロックがクライアントのクロックより60秒進んでいる場合、スナップショットのタイムスタンプはクライアントのローカルのタイムスタンプより60000ミリ秒進んでいます。
  • したがって、クライアントのクロックが追いつくのに時間がかかるため、エンティティスナップショットが収集され、クライアントが特定のエンティティが移動するのをクライアントが見るまで約60秒間待機します。

スナップショットを受信するたびにサーバーとクライアントのクロックの差を計算することで、この問題を克服することができました。

// For simplicity, don't worry about latency for now...
client_server_clock_delta = snapshot.server_timestamp - client_timestamp;

エンティティが補間にどの程度沿っているかを判断するとき、単にクライアントの現在の時間に差を追加します。ただし、これに関する問題は、スナップショットが他のクロックよりも速く/遅く到着するために2つのクロックの差が突然変動するため、ジャーキネスが発生することです。

知覚可能な遅延が補間のためにハードコードされている遅延と、通常のネットワーク遅延によって引き起こされる遅延のみであるように、クロックをどのように密接に同期できますか?

言い換えると、ジャーキネスを導入せずに、クロックが大幅に非同期化されたときに、補間の開始が遅すぎる、または早すぎるのを防ぐにはどうすればよいですか?

編集:Wikipediaによると、NTPを使用して、インターネット上のクロックを数ミリ秒以内に同期できます。ただし、プロトコルは複雑に思えますが、おそらくゲームで使用するには過剰ですか?


どのように複雑ですか?それは、それぞれ送信と到着のタイムスタンプを備えた要求と応答であり、デルタを取得するための少しの数学です
ラチェットフリーク

@ratchetfreak:(mine-control.com/zack/timesync/timesync.html)によれば、「残念ながら、NTPは非常に複雑であり、さらに重要なことには、正確な時間への収束が遅い。これにより、NTPはネットワークにとって理想的ではなくなるプレイヤーがゲームをすぐに開始することを期待するゲームプレイ...」
Joncom

回答:


9

周りを検索した後、2台以上のコンピューターのクロックを同期することは簡単な作業ではないようです。NTPのようなプロトコルは良い仕事をしますが、ゲームでは実用的であるには時間がかかり複雑すぎると思われます。また、UDPを使用しますが、UDPをサポートしていないWebソケットで作業しているため、私にとっては機能しません。

しかし、ここでメソッドを見つけましたが、これは比較的簡単に思えます:

クロックを互いに150ミリ秒(またはそれ以上)以内に同期すると主張しています。

それが私の目的にとって十分かどうかはわかりませんが、より正確な代替案を見つけることができませんでした。

提供するアルゴリズムは次のとおりです。

ゲームにはシンプルなクロック同期技術が必要です。理想的には、適度に正確(150ミリ秒以上)、収束が速く、実装が簡単、TCPなどのストリームベースのプロトコルで実行可能なプロパティが必要です。

これらのプロパティを持つ単純なアルゴリズムは次のとおりです。

  1. クライアントは「時間要求」パケットに現在の現地時間をスタンプし、サーバーに送信します
  2. サーバーが受信すると、サーバーはサーバー時間にスタンプを付けて戻ります
  3. クライアントが受信すると、クライアントは送信時間から現在の時間を差し引き、2で割ってレイテンシを計算します。サーバー時間から現在の時間を差し引いてクライアントとサーバーの時間の差分を決定し、半遅延を加算して正しいクロックの差分を取得します。(これまでのところ、このalgothimはSNTPに非常に似ています)
  4. 最初の結果は、クロックを更新するためにすぐに使用する必要があります。ローカルクロックが少なくとも適切な球場(少なくとも適切なタイムゾーン!)に到達するからです。
  5. クライアントは、ステップ1〜3を5回以上繰り返し、毎回数秒間停止します。他のトラフィックは暫定的に許可される場合がありますが、最良の結果を得るには最小化する必要があります
  6. パケット受信の結果は累積され、最低遅延から最高遅延の順にソートされます。待ち時間の中央値は、この順序付きリストから中間点のサンプルを選択することにより決定されます。
  7. 中央値から約1標準偏差を超えるすべてのサンプルは破棄され、残りのサンプルは算術平均を使用して平均されます。

このアルゴリズムの唯一の微妙な点は、中央値を超える1標準偏差を超えるパケットが破棄されることです。これの目的は、TCPによって再送信されたパケットを排除することです。これを視覚化するために、5つのパケットのサンプルがTCPを介して送信され、再送信がなかったことを想像してください。この場合、レイテンシヒストグラムには、レイテンシの中央値を中心とした単一モード(クラスター)があります。次に、別の試行で、5つのパケットのうち1つが再送信されることを想像してください。再送信により、この1つのサンプルは、レイテンシヒストグラムの右端、平均でプライマリモードの中央値の2倍の距離になります。中央値から1標準偏差以上離れているすべてのサンプルを単純にカットすることにより、これらの漂遊モードは統計の大部分を構成しないと仮定して簡単に排除されます。

このソリューションは、時計を同期してから停止し、時間を線形に流すことができるため、私の質問に十分に答えているようです。私の最初の方法はクロックを絶えず更新していたので、スナップショットが受信されると少し時間がかかります。


そのとき、これはどのようにあなたのために働くことが証明されましたか?私は今、同じ状況にいます。TCPのみをサポートするサーバーフレームワークを使用しているため、UDPデータグラムを送信するNTPは使用できません。TCP経由で信頼性の高い時刻同期を行うと主張する時刻同期アルゴリズムを見つけるのに苦労しています。ただし、1秒以内の同期で十分です。
-dynamokaj

@dynamokajはかなりうまくいきます。
ジョンコム

涼しい。実装を共有できる可能性はありますか?
-dynamokaj

@dynamokaj私は、私が今考えることができるどんなプロジェクトでもそのような実装を見つけることができないようです。別の方法としては、1)1つのpingリクエスト/レスポンスから計算したレイテンシーをすぐに使用してから、2)新しい値に向けての今後のすべてのレスポンスに対して、即座にではなく徐々に使用します。これには「平均化」効果があり、私の目的には十分正確です。
ジョンコム

問題ない。私はGoogle App Engineでバックエンドサービスを実行しているため、Google NTPサーバーを使用してサーバーが同期されるGoogleインフラストラクチャで:time.google.com(developers.google.com/time)したがって、Xamarin Mobileクライアントには次のNTPクライアントを使用しますクライアントとサーバー間のオフセットを取得します。components.xamarin.com/view/rebex-time-お返事ありがとうございます。
-dynamokaj

1

基本的に、[全体]の世界を修正することはできず、最終的には線を引く必要があります。

サーバーとすべてのクライアントが同じフレームレートを共有している場合、接続時に同期する必要があり、その後、特に遅延イベント後に同期する必要があります。遅延は時間の流れやそれを測定するPCの能力に影響を与えないため、多くの場合、内挿ではなく外挿する必要があります。これは同様に望ましくない効果を生み出しますが、繰り返しますが、それはそれであり、利用可能なすべての悪の中で最も少ないものを選択しなければなりません。

多くの人気のあるMMOでは、遅れているプレーヤーは視覚的に明らかであることを考慮してください。それらが所定の場所で、直接壁に向かって走っているのを見ると、クライアントは外挿しています。クライアントが新しいデータを受信すると、プレーヤーは(クライアント上で)かなりの距離を移動した可能性があり、「ゴムバンド」または新しい場所にテレポートします(あなたが言った「ジャーキネス」?)。これは、主要な有名ブランドのゲームでも起こります。

技術的には、これはゲームではなく、プレーヤーのネットワークインフラストラクチャの問題です。それが一方から他方に行くポイントは、あなたが描く必要があるまさにその線です。コードは、3台の別々のコンピューターで、同じ量の経過時間を記録する必要があります。更新を受信しなくても、Update()のフレームレートに影響はありません。どちらかといえば、おそらく更新する必要が少ないため、より高速になります。

「もしあなたがインターネットの悪さをしているなら、このゲームを競争的にプレイすることはできない。」
それは一過性でもバグでもありません。

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