フレーム
はじめに
Quantumの予測/ロールバック方式によって、レイテンシが軽減されます。Quantumは常にフレームをロールバックし、再シミュレーションを行います。これは決定論性に不可欠で、サーバーによるプレイヤー入力の検証を含みます。サーバーがプレイヤー入力を確定するか、入力の上書き/置換(入力が時間内にサーバーに到達しなかった場合のみ)を行った後、1フレーム分のすべての検証済みプレイヤー入力がクライアントに送信されます。検証済み入力を受信すると、その入力を使用して最新の確定フレームを進めます。
注意: プレイヤー自身の入力は、時間内にサーバーに到達しなかったり、検証できなかった場合は、ロールバックされます。
フレームの種類
Quantumは、2種類のフレームを区別します。
- 確定(verified)フレーム
- 予測(predicted)フレーム
確定フレーム
確定フレームは、信頼できるシミュレーションフレームです。確定フレームは決定論的であり、すべてのクライアントシミュレーション上で同一であることが保証されています。確定のシミュレーションは、サーバー検証済み入力を受信した時のみ、次の確定フレームに進みます。したがって、サーバーとのRTTの半分に比例して進みます。
フレームが確定するには、以下の2つの条件を両方満たす必要があります。
- そのティックで、すべてのプレイヤーの入力がサーバーによって確定している
- それ以前のすべてのティックが確定済みである
プレイヤーの一部のみの入力がサーバーによって検証済みである部分的なティックの確定は、確定ティック/フレームにはなりません。
予測フレーム
確定フレームとは対照的に、予測フレームはサーバー検証済み入力を必要としません。つまり、ローカルセッションのシミュレーションで十分な時間が経過するとすぐに、予測フレームを予測に基づいて進めることができます。
Unity側のAPIは、予測フレームに関する様々なAPIを提供しています。APIの説明は以下の通りです。
Predicted
:同期クロックに基づく「最新」の予測シミュレーションです。PredictedPrevious
(predicted - 1):メインクロックエイリアス補間に使用されます。(Unityのローカルクロックはメインサーバークロックから少しずれることがあるため、ほとんどのビューはこれを使用してスムーズに動きます。Quantumは独立したクロックで実行され、これはサーバークロックと同期して、スムーズに修正されます。)PreviousUpdatePredicted
:最後にSession.Update
が呼び出された際の「最新の予測」フレームです(そこに「修正された」データがあります)。これは誤差修正補間に使用されます(誤差が発生する時間はわずかです)。
API
確定フレームと予測フレームの概念は、シミュレーションとビューの両方に存在しますが、APIは少し異なります。
シミュレーション
シミュレーション中では、Frame
クラスから現在シミュレーションしているフレームの状態にアクセスできます。
メソッド | 戻り値 | 説明 |
---|---|---|
IsVerified | bool | フレームが、すべてのクライアント間で決定論的かつサーバー検証済み入力を使用している場合、trueを返します。 |
IsPredicted | bool | フレームが、ローカルの予測フレームの場合、trueを返します。 |
ビュー
ビューでは、QuantumRunner.Default.Game.Frames
から確定フレームと予測フレームが利用可能です。
メソッド | 説明 |
---|---|
Verified | すべてのクライアント間で同一の信頼できるシミュレーションフレームです。 |
Predicted | 同期されたQuantumクロックに基づく「最新」のローカルシミュレーションです。これはクライアントによって異なります。 |
PredictedPrevious | Predicted - 1 メインクロックエイリアス補間に使用され、ほとんどのビューはこれを使用してスムーズに動きます。Unityのローカルクロックはメインサーバークロックから少しずれることがあるため、Quantumは独立したクロックで実行され、これはサーバークロックと同期して、スムーズに修正されます。 |
PreviousUpdatePredicted | 最後にSession.Updateが呼び出された際の再シミュレーションされた「最新の予測」フレームです。これはロールバックが発生した場合に、保持しているデータを「修正」するために必要です。これはビューの補間の誤差修正で使用されますが、あくまで安全対策であり、必要になることはほとんどありません。 |
Frame.Userの使用
Frame.User.cs
にデータを追加することで、フレームを拡張できます。ただしその場合は、フレームで使用される対応の初期化・割り当て・シリアライズメソッドを実装する必要があります。
C#
partial void InitUser() // データの初期化
partial void SerializeUser(FrameSerializer serializer) // データのシリアライズ/デシリアライズ
partial void CopyFromUser(Frame frame) // 次のフレームのコピー
partial void AllocUser() // スペース割り当て
partial void FreeUser() // 割り当てスペースの解放
備考: フレームに過剰な量のデータを追加すると、パフォーマンス(シリアライズ/デシリアライズ)に大きく影響し、途中参加者にも影響を与えます。
例
これは手動のメモリ割り当てを必要としない非常にシンプルな例です。
C#
namespace Quantum {
unsafe partial class Frame {
public byte[] Grid => _grid;
private byte[] _grid;
partial void InitUser() {
_grid = new byte[RuntimeConfig.GridSize];
}
partial void SerializeUser(FrameSerializer serializer)
{
serializer.Stream.SerializeArrayLength<Byte>(ref _grid);
for (int i = 0; i < Grid.Length; i++)
{
serializer.Stream.Serialize(ref Grid[i]);
}
}
partial void CopyFromUser(Frame frame)
{
Array.Copy(frame._grid, _grid, frame._grid.Length);
}
}
}
Back to top