EntityRefハイジャック
はじめに
EntityRefハイジャックは、予測/ロールバックモデルがビューに与える既知の副作用を指す用語です。
説明
これには以下の要素が関連しています。
- 予測/ロールバック
- エンティティの作成
- エンティティビュー
シミュレーションは常に数フレーム先を予測しています。予測フレームでは未確定のプレイヤー入力を使用し、サーバーからすべてのプレイヤーの確定した入力を受信すると、Quantumは確定フレームをシミュレートします。
予測フレームで「エンティティ A」の作成が必要になると、実際にそれを作成して、「EntityRef
X」が割り当てられます。関連するQuantumEntityView
コンポーネントのBind Behaviour
がNon Verifiedに設定されている場合、Unityでは次回のOnUpdateView
コールバックでビュー要素が作成されます。
サーバーから確定した入力を受信すると、Quantumはサーバー側で確定された情報によってフレームの再シミュレーションを行います。これが確定フレームです。ここで興味深い事象が発生します。
予測フレームでは作成されなかった「エンティティ B」が、再シミュレーションされたフレームで「エンティティ A」より前に作成された場合、「EntityRef
X」は「エンティティ B」に再割り当てされて、「エンティティ A」には新しい「EntityRef
Y」が割り当てられます。これはEntityRef
が決定論的で順序通りに割り当てられるためです。
ここで2つの事象が発生します。
「エンティティ A」と「エンティティ B」がそれぞれ異なる
QuantumEntityView
を使用する場合:QuantumEntityViewUpdater
スクリプトは不一致を検知し、「エンティティ A」のリンクと関連ビューを破棄します。クリーンアップ完了後、「エンティティ A」と「エンティティ B」に新しいビューが作成されます。「エンティティ A」と「エンティティ B」がそれぞれ同じ
QuantumEntityView
を使用する場合:EntityViewUpdater
スクリプトは次の更新で不一致を検知し、「エンティティ A」のリンクと関連ビューを「エンティティ B」にリンクさせて、「エンティティ A」に新しいビューを作成します。- 「エンティティ A」は新しいビューを持つ。このビューは正しいデータを使用する。
- 「エンティティ B」は以前「エンティティ A」に関連付けられていたビューを持つ。このビューは間違ったデータで初期化されているので、更新する必要がある。
EntityViewUpdaterについての備考
QuantumEntityViewUpdater
スクリプトは、EntityRef
とQuantumEntityView
のキーバリューペアをキャッシュすることで、シミュレーションのエンティティとビュー間のリンクを保存します。詳細はQuantumEntityViewUpdater.cs
をご覧ください。
Bind Behaviourについての備考
エンティティビューのBind Behaviour
がVerifiedだった場合、確定フレームでのみインスタンス化が行われるため、上記の事象は発生しません。これはトレードオフで、エンティティの「タイプ」によって、どのBind Behaviour
が適切なのかが決まります(以下の一般的アドバイスを参照)。
対処方法
この状況は、シミュレーションかビューを調整することで簡単に解決できます。
コードでの対処
エンティティが確定フレームでのみ作成されるようにするために、次のような条件文でラップできます。
C#
if(f.IsVerified) {
// 何かする
}
または、非確定フレーム(つまり予測フレーム)で早期リターンさせます。
C#
if (f.IsPredicted == false)
return;
必要に応じて、APIをOnPlayerDataSet
でも使用できます。
Unityでの対処
ビュー側では、初期化処理を修正して問題に対処するか、ビュー自身が保持しているデータの不一致を検知して更新できるようにすることができます。解決策はBind Behaviourの設定をVerifiedにしているかNon-Verifiedにしているかによって異なります。
UnityでBind Behaviourを変更するには、EntityViewAsset
に関連付けられたプレハブのEntityView
スクリプトから、Non VerifiedからVeriiedに切り替えるだけです。

Bind Behaviour - Verified
この設定では、最初から正しい情報になっていることが保証されているため、UnityのStart()
メソッド時点で利用可能な情報を信頼できます。エンティティビューイベントのOnEntityInstantiated
を使用することもできます(プレハブに付いたエンティティビュースクリプトを参照)。
Bind Behaviour - Non-Verified
この設定では、インスタンス化直後に利用可能な情報は間違っている可能性があります。
ビューに変更が反映されることを保証するために、UnityのUpdate()
でポーリングして、ビュー自身を設定できるようにしてください。これによって、データが間違っていた場合にデータを切り替えることができます。ビューがシミュレーションから完全に独立していて、既に必要な情報を保持している場合、この予防策は必要ありません。EntityViewUpdater
によってゲームオブジェクトの破棄/再作成が行われ、問題は修正されているためです。
Bind Behaviourの一般的なアドバイス
VerifiedとNon Verifiedの両方に、それぞれ利点と欠点があります。
Verified
:プレイヤーキャラクターなど、ミリ秒単位の正確なインスタンス化が要求されないものに適しています。Non Verified
:射撃の弾など、プレイヤーが素早く反応するための時間が必要になるものに適しています。