ping値計算の改善について
その前に、今回の記事で使用する専門用語についてご案内します:
クライアントとサーバー: クライアントとは、それぞれのコンソール、モバイルデバイス、PCやMacなどのことです。各クライアントは、ゲームをホストする専用サーバーに接続します。サーバーはゲーム全体の状況(プレイヤーの位置、サークルの状態、有効な宝箱など多くの情報)を管理しています。そしてゲームの状況が変わるたびに、各クライアントに最新の情報を届けるのもサーバーの役目となります。
パケット: パケットとは、クライアントからサーバーへ、またサーバーからクライアントへと、ネットワークを通じて送受信されるひとかたまりの情報のことです。クライアントとサーバーの間では、パケットが送られたり受け取られたりしています。フォートナイトでは(そしてUE4でも)、パケットを使ってpingを計算しています。
フレーム: サーバー側におけるフレームとは、新しいパケットが届いているかの確認、ゲームの状況の更新、更新内容を各クライアントへ送信、というタスクを実行する頻度のことです。クライアント側におけるフレームとは、画面が更新される頻度のことを指します。「FPS」や「1秒あたりフレーム数」とも言われる「フレームレート」は、サーバーやクライアントにおいて、1秒あたり何フレーム処理されるか、という数値です。「クライアントが60 FPSで動作している」と言う場合は、毎秒60フレーム処理されている、ということになります。
それでは、ping値についてご説明しましょう!
これまでのpingパケット計算方法
多くの場合、「ping」というのは、クライアントがサーバーへパケットを送り、サーバーが返事を返すまでの時間、あるいはその逆のことを指します。これは「ラウンドトリップタイム」、または「RTT」と呼ばれます。そしてこれこそ、ほとんどのプレイヤーが知りたがる情報です。すなわち、プレイヤーがサーバーの最新情報を受け取れるまでの時間、サーバーに最新情報を送ることができるまでの時間です。プレイヤーのping値が高いほど、プレイヤーのワープ、不意に倒される、宝箱や他のオブジェクトの反応が遅い、といった望ましくない現象に出くわす可能性が大きくなります。私たちはpingをミリ秒で表示し、数値は低いほど良い接続を意味します。サーバーを収容しているデータセンターのすぐ隣に住んでいる場合、pingは一桁になるかもしれません!その一方で、地球の裏側にあるサーバーとつないでいる場合、ping値は100msを超えてしまう可能性もあるでしょう。
しかし、クライアントとサーバーの間の通信には、パケットが行き来する時間以外にも考えなければいけない要素があります。フォートナイトでは、一般的にサーバー/クライアントの両側で、毎フレームごとにフレーム開始付近に新しいパケットを確認するようにしてます。これにより、パケットが実際に届いたタイミングと、クライアント/サーバーが新しいパケットが届いているかどうかを確認するタイミングに、最大で1フレームの遅れが発生する可能性が生まれます。また、届いたパケットの内容を理解して、ゲーム状況を更新するまでにも時間がかかります。
こちらが概略図になります:
クライアントとサーバーの黒い矢印は時間を表しています。こちらの例では、サーバーとクライアントは完全に同期していて、同じフレームレートで動作しています。黒い垂直の線は各フレームの始まりを示しています。青い部分はクライアントやサーバーが新しいパケットの受信を確認しているタイミングで、オレンジの線はクライアントやサーバーがパケットを送信しているタイミングです。紫色の点線は、インターネットを通じたパケットの流れを表しています。
一連の処理はこうなります:
- クライアントがサーバーへパケットを送信します。
- サーバーがパケットを受信します。
- サーバーが新しいパケットが届いていないかを確認します。先ほどクライアントが送信したパケットが確認されるのは、このタイミングです。先ほどのパケットがサーバーに届いたのは、サーバー側がパケットの確認をした後のため、1フレーム近く待っていたことになります。
- サーバーがクライアントにパケットの到着を伝えます。
- サーバーの返事がクライアントに届きます。
- クライアントがサーバーの返事の内容を確認します。
より安定した値を表示するために、数秒間にわたるパケットの数値を平均化しています。
ただし、これは私たちが望んでいるほど正確な値とはなりません。「受信済みで処理を待っているパケット」の時間を計算に含んでいないため、表示されるping値は高いものになりがちです。ここで難しいのは、ほとんどのプラットフォームにおいて特定のパケットが受信されたタイミングを知ることができないため、実際にどれほどの時間を差し引けば良いのかが分からないということです。
7.30におけるpingパケット計算方法
7.30では、新しい方法を試しました。それは、クライアントからサーバーへ送られたパケットのうち、最短時間で反応を得られたパケットのみを使用してはどうか? というものです。最短時間で反応を得られたということは、待ち時間が限りなくゼロに近かったということなので、待ち時間を計算に入れる必要がなくなります。そこで、最も時間の速かった25%のパケットをping値の計算に使用しました。25%というのは、現実的な値を導き出すのに十分なデータの量だと想定したからです。問題点
7.30のリリース後、ping値が一桁であったり、ゼロのプレイヤーすらも見受けられました。これが事実だとすると、パケットのスピードが光速を超えていることを意味します。UE4は素晴らしいゲームエンジンですが、まだそこまで進化していません!つまり、何かがおかしいということです。問題の原因は、私たちのping計算の一部にありました。ここで再び計算方法をご紹介します:
問題は、サーバーのフレーム時間を差し引くところにありました。最速のパケットのみを考慮すると、差し引く時間が大きすぎたのです。パケットがサーバーへ届いてすぐに処理されたとすると、内容を処理して返事を返すのに数ミリ秒しかかかりません。しかし、サーバーのフレーム時間はその5倍もかかっているかもしれないのです!
概略図にするとこうなります:
こちらは、サーバーよりもかなり速いフレームレートを持つクライアントです。ここでは緑色のパケットのみを計算に使用しています。緑のパケットはサーバーが確認する直前に届いています。このケースでは、サーバーは固定されたフレームレートよりも速いスピードで動作しています。そのため、フレームの開始時、パケットの到着をチェックする前に何もしない時間(スリープ)が発生しています。
赤い線はサーバーのフレームレートとして差し引いている時間を示していますが、正しくはオレンジ色の線を差し引くべきです。赤い線では差し引く値が大きすぎます。これが、一部のクライアントでping値がゼロと表示されていた原因です。
古い計算方法では、より多様なパケットを使用していましたが、それでもこの問題は影響を及ぼします。しかし、処理までに時間がかかったパケットも計算に含めることで、時間を差し引きすぎていたパケットの分をキャンセルする効果もありました。
今後の予定
表示されるping値の精度を高めるためにどのように改善すればよいのか、いくつかの予定があります。少し前にこう書きました:
「ここで難しいのは、ほとんどのプラットフォームにおいて特定のパケットが受信されたタイミングを知ることができないため、実際にどれほどの時間を差し引けば良いのかが分からないということです。」
ラッキーなことに、Linuxならば分かるのです!そして私たちのサーバーは全てLinuxで動いているため、ping値の計算方法を次のように変更することができます:
ping=パケットがサーバーまで送られる時間+パケットがクライアントへ送られる時間-パケットがサーバーに届いて返事を送り出すまでの時間-ここまでのクライアントのフレーム時間
この計算方法ですと、推測でサーバーのフレーム時間を差し引くということをしなくてすみます。これで精度の高いping値を表示できるようになると考えていますが、まだテストを実施して確認する必要があります。
また、クライアント側におけるパケットの確認頻度の増加を検討しています。これが実現できれば、ping値の計算から「ここまでのクライアントのフレーム時間」を外すことができます。
これらのふたつの変更の組み合わせにより、これまでよりも精度の高いping値を表示できるようになると考えています。
結論
この記事が、ping値の計算の仕組みや、今後の改善についての理解につながっていけば幸いです。pingのような情報を表示する際は、その情報が正確であることは重要です。不正確な情報を表示するというのは、何も情報を表示しないよりも悪いことさえあります。プレイヤーが攻撃を外したり、ゲームにラグを感じたりした場合に、その原因がpingにあるのかどうかを知ることは大切です。原因が分かれば、改善することも可能になります。
コメント欄にある質問には全て目を通して、可能な限りお答えさせていただきます。最後までお読みいただき、ありがとうございました!