EntityRef Hijacking
イントロダクション
EntityRef Hijacking は、予測ロールバックモデルにビューで発生し得る既知の副作用を指す用語です。
概要
ここでカギを握るのは以下のポイントです:
- 予測ロールバック;
- エンティティ作成;
- エンティティビュー
シミュレーションは常に次のいくつかのフレームを予測しています。予測フレーム は確認されていないプレイヤー入力を使用します。サーバーが受信した入力を全てのプレイヤーに対して確認するとQuantumは確認済みフレームのシミュレーションを行います。
予測フレームが エンティティA の作成を要求するとそれが行われ、続いて「EntityRef X」を割り当てます。関連するEntityViewAsset
のBind Behaviour
が未確認に設定されている場合、Unityでまさに次のOnUpdateView
コールバックでビューエレメントが作成されます。
確認した入力がサーバーから受信されると、Quantumはサーバーサイドの確認済み情報を用いて再度フレームのシミュレーションを行います。この情報が 確認済 フレームです。ここがおもしろい点です。
エンティティA の前に他の エンティティB が予測フレームにはなく再度シミュレーションされたフレーム内に作成されていると、EntityRefが決定性であり連続して生み出されるため「EntityRef X」が再割り当てされます。このケースでは、エンティティA が新しい「EntityRef Y」に割り当てられています。
ここまでくると、以下のうち1つが発生します。:
エンティティA と エンティティB がそれぞれ 異なる
EntityViewAsset
を使用します。EntityViewUpdater
スクリプトがミスマッチを検証し、エンティティA に対して持っていたリンクと関連するビューを破棄します。クリーンアップが完了すると今度はエンティティA と エンティティB に対して新しいビューが作成されます。エンティティA と エンティティB が 同じ
EntityViewAsset
を使用します。EntityViewUpdater
スクリプトが次のアップデートでミスマッチを検証し、エンティティA とそのビューの間のリンク、既存のビューへのエンティティB を破棄し、エンティティA の新しいビューをインスタンス化します。- エンティティA は新しいビューを持ちます。このビューには正しいデータが使用されています。
- エンティティB はそれまで エンティティA に関連付けられていたビューを持ちます。このビューは誤ったデータで初期化されているため、アップデートが必要です。
EntityViewUpdater注意:
EntityViewUpdater
スクリプトはシミュレーション内のエンティティとそのビューの間のリンクをEntityRefとEntityViewAssetのキーペア値のキャッシュにより保存します。詳細はEntityViewUpdater.cs
を参照してください。
Bind Behaviour注意:
エンティティビューが 確認済み Bind Behaviorを使用する場合、インスタンス化されるのは確認済みフレームでのみになります。そのため、上に記したようなことは発生しません。エンティティの「タイプ」でどの挙動が適切であるかきまります(以下の一般的なアドバイス を参照してください)。
対処法
この状況は、シミュレーションまたはニューの微調整で簡単に解決できます。
コード内
エンティティが確認済みのフレーム上のみで作成されるようにするには、以下のいずれかの条件宣言をラップします:
C#
if(f.IsVerified) {
// Do stuff
}
または未確認で早めに出しておきます。例:以下を使用した予測フレーム:
C#
if (f.IsPredicted == false)
return;
必要に応じてOnPlayerDataSet
でもAPIを使用することができます。
Unityで
ビューで、問題を初期化の挙動を修正することで対処するか、ビューのデータにミスマッチがあった場合、ビューそのものをアップデートして対処するか選択できます。解決法は 確認済み もしくは 未確認 に Bind Behaviour を設定しているかどうかでかわります。
Unityで [Bind Behaviour] を変更するには、プレハブにあるEntityViewAsset
と関連づいたEntity View
スクリプトに移動して未確認から 確認済み に切り替えます。
Bind Behaviour - 確認済み
このケースでは初めから正しい情報の提供が保証されており、UnityのStart()
メソッドの時点で使用可能な情報を信用できます。OnEntityInstantiated
EntityViewイベントを使用することもできます(プレハブにアタッチされているエンティティビュースクリプトを参照してください)。
Bind Behaviour - 未確認
このケースではインスタンス化の時点で提供される情報は誤っている可能性があります。
ビューに変更が確実に反映されるようにするには、ポーリングを介してUnity Update()
内からビューを設定できることを確認してください。そうすることでデータが誤っていた場合に切り替えることができます。ビューはシミュレーションから完全独立していて、必要な情報を備えている必要があります。それが整っていれば、EntityViewUpdater
がGameObjectを破壊して再作成し問題を修正してくれるので、この予防措置は必要でなくなります。
Bind Behaviourでの一般的なアドバイス
確認済み と 未確認のどちらの挙動にも、メリットとデメリットがあります。
確認済み
: プレイヤーキャラクターなどミリ秒単位で精密なインスタンス化に極端に敏感でないもの。未確認
: 弾丸など高速でプレイヤーが反応するのに時間を必要とするもの。