EntityRefハイジャック
はじめに
EntityRef ハイジャック は、予測ロールバックモデルがビューに与える既知の副作用を指す用語です。
説明
これに関与するいくつかの要素があります:
- 予測ロールバック
- エンティティの作成
- エンティティビュー
シミュレーションは常に次の数フレームを予測しています。予測フレームは、未検証のプレイヤー入力を使用します。すべてのプレイヤーの入力がサーバーによって検証されると、Quantumは検証されたフレームをシミュレートします。
もし予測フレームがエンティティAの作成を必要とする場合、それは進められ、「EntityRef X」が割り当てられます。その関連するEntityViewAsset
のBind Behaviour
が非検証に設定されている場合、ビュー要素は次回のOnUpdateView
コールバックでUnity内に作成されます。
サーバーから確認された入力を受信すると、Quantumはサーバー側で検証された情報を使用してフレームを再シミュレートします - これが 検証された フレームです。ここから興味深い事態が発生します。
もし再シミュレートされたフレーム内でエンティティAの前に別のエンティティBが作成され、予測フレームでは作成されていなかった場合、「EntityRef X」が再割り当てされます。なぜなら、EntityRefsは決定論的であり、順次渡されるからです。この場合、エンティティAには新しい「EntityRef Y」が割り当てられます。
ここで二つの事象が発生します。
エンティティAとエンティティBがそれぞれ__異なる__
EntityViewAsset
を使用する場合、EntityViewUpdater
スクリプトは不一致を検知し、エンティティAのリンクとその関連ビューを破棄します。クリーンアップが完了した後、新しいビューをエンティティAとエンティティBのために作成します。エンティティAとエンティティBが__同じ__
EntityViewAsset
を使用する場合、EntityViewUpdater
スクリプトは次の更新で不一致を検知し、エンティティAとそのビューのリンクを切断し、エンティティBを既存のビューにリンクさせ、新しいビューをエンティティAのためにインスタンス化します。エンティティAには新しいビューがあります。このビューは正しいデータを使用します。
エンティティBは以前のエンティティAに関連付けられたビューを持っています。このビューは誤ったデータで初期化されているため、更新する必要があります。
EntityViewUpdaterについての注意:
EntityViewUpdater
スクリプトは、シミュレーション内のエンティティとそのビューとのリンクを、EntityRefとEntityViewAssetのキーと値のペアをキャッシュすることで保存します。詳細については、EntityViewUpdater.cs
を参照してください。バインドビヘイビアについての注意:
エンティティビューが__検証された__バインドビヘイビアを使用している場合、それは検証されたフレームでのみインスタンス化されるため、上記の事象は決して発生しません。これはトレードオフです。エンティティの「タイプ」によって、どのビヘイビアがより適切であるかが決まります(以下の一般的なアドバイスセクションを参照)。
対処方法
コードで
C#
if(f.IsVerified) {
// Do stuff
}
Or bail out early on non-verified, i.e. predicted, frames by using:
C#
if (f.IsPredicted == false)
return;
APIは、必要に応じてOnPlayerDataSet
でも使用できます。
Unityでの対処
ビューでは、初期化ビヘイビアを変更することで問題に対処するか、保持しているデータの不一致を検知した場合にビューが自動的に更新されるようにすることができます。解決策は、バインドビヘイビアを__検証された__に設定するか、非検証に設定するかによって異なります。
バインドビヘイビア をUnityで変更するには、EntityViewAsset
に関連付けられたプレハブ内のEntity View
スクリプトに移動し、非検証 から 検証された に切り替えるだけです。

バインドビヘイビア - 検証された
この場合、最初から正しい情報が保証されており、UnityのStart()
メソッドの時点で利用可能な情報を信頼することができます。また、OnEntityInstantiated
エンティティビューイベントを使用することも可能です(プレハブに添付されたエンティティビュースクリプトを参照してください)。
バインドビヘイビア - 非検証
この場合、インスタンス化時に利用可能な情報が誤っている可能性があります。
ビューがこの変更を反映できるようにするためには、UnityのUpdate()
内でポーリングを通じて自身を設定できるようにしてください。これにより、データが間違っている場合にはデータを切り替えることができます。もしビューがシミュレーションから完全に独立しており、必要な情報をすでに保持している場合、この予防策は必要ありません。なぜなら、EntityViewUpdater
が問題を修正し、GameObjectを破壊して再作成するからです。
バインドビヘイビアに関する一般的なアドバイス
__検証された__ビヘイビアと非検証ビヘイビアの両方には、それぞれの利点と欠点があります。
検証された
: ミリ秒単位の正確なインスタンス化に対してそれほど敏感でないもの、例えばプレイヤーキャラクターなど。非検証
: プレイヤーが反応するために時間が必要なもの、例えば弾丸など、速い動作のもの。