アクタの ネットワーク休止 (AActor::NetDormancy
) は、マルチプレイヤー プロジェクトで実行することができる最も効果的なサーバー最適化の 1 つです。特にプロジェクト内に頻繫に変更されないレプリケートされたアクタが多数ある場合は、これによってフレームあたりのサーバー CPU 時間を数ミリ秒節約できる可能性があります。ネットの更新中、NetDriver では接続に関連するすべてのレプリケートされたアクタの一覧を収集し、これらのアクタとそのプロパティを反復処理して、変更点やクライアントに送信する必要があるかどうかを判断します。アクタのネットワーク休止により、収集された接続のアクタ一覧にそのアクタを追加するかどうかが制御されます。休止状態のアクタは一覧に追加されませんが、アウェイク状態 (休止状態ではない) アクタは一覧に追加されます。アクタとそのプロパティの反復処理は、特にレプリケートされたアクタが多数あるプロジェクトの場合、負荷が大きくなる可能性があります。このことから、効率的にネットワーク休止を使用してレプリケーションの一覧からアクタを外すことが、マルチプレイヤー プロジェクトにとって重要な最適化となる場合があります。
ネットワーク休止の使用方法
次の手順に従って、プロジェクトで効率的にネットワーク休止を使用します。
-
コンストラクタでアクタの
AActor::NetDormancy
をENetDormancy::DORM_DormantAll
に設定します。NetDormancy = ENetDormancy::DORM_DormantAll;
- アクタがマップに配置されている場合、アクタの
AActor::NetDormancy
をENetDormancy::DORM_Initial
に設定します。 - 休止している間、アクタはレプリケートされません。
- アクタをレプリケートするには、レプリケートされたプロパティを変更する前に
AActor::FlushNetDormancy
、AActor::ForceNetUpdate
、またはAActor::SetNetDormancy(ENetDormancy::DORM_Awake)
を呼び出します。 - レプリケートされたコンポーネントやサブオブジェクトの場合は、レプリケートされたプロパティが変更される前に、所有するアクタをフラッシュするかアウェイク状態にする必要があります。
レプリケートされたアクタが休止状態としてマークされると、NetDriver
はその接続の収集されたアクタ一覧への追加をスキップできるようになります。これにより時間を節約できますが、そうでない場合はアクタをレプリケーションの対象として検討したり、そのプロパティを比較したりするために時間がかかります。休止状態のアクタがアウェイク状態になるか、休止状態がフラッシュされるまで、そのアクタはレプリケーションの対象にはなりません。したがって、レプリケートされたプロパティへの変更はクライアントに送信されません。また、アクタが休止状態の間は、レプリケートされた状態を変更してはいけないことにも注意する必要があります。その場合の変更は、アクタがアウェイク状態になると失われることがあります。これは、レプリケートされたプロパティを頻繫に変更しないアクタが、休止状態の適切な候補となることを意味しています。ポーンなどの頻繫に更新が必要なアクタには、あまりメリットがありません。また、アクタの休止状態を変更またはフラッシュする場合の追加オーバーヘッドにより、あまりにも頻繫に状態を変更すると、ただアクタをアウェイク状態で維持するよりもパフォーマンスが低下する可能性があります。
レプリケートされたアクタが休止状態になるとアクタ チャンネルは閉じますが、休止状態のアクタはサーバーとクライアントの両方で引き続き存在します。これは、アクタの関連性 を処理する方法とは異なります。動的にレプリケートされているアクタは、関連性がなくなるとクライアントで破棄されます。休止状態のアクタは関連性をチェックされないため、休止アクタがクライアント上で関連性を失った場合もクライアント上では破棄されないことに注意してください (レプリケーション グラフ で Net.RepGraph.DormantDynamicActorsDestruction
コンソール変数を有効にして使用している場合を除きます)。
アクタのネットワーク休止を変更する
アクタの休止状態は、AActor::NetDormancy
プロパティに格納されます。このプロパティは、AActor::SetNetDormancy
を呼び出して変更できます。AActor::NetDormancy
はパブリックですが、このプロパティをアクタのコンストラクタの外部で直接設定しないでください。AActor::SetNetDormancy
は NetDriver
への変更の通知も処理するため、アクタの休止状態を変更するには、この関数を呼び出す必要があります。
ネットワーク休止状態
ENetDormancy
列挙型クラス (EngineTypes.h
で定義されます) には、5 つの休止状態が記述されています。次の表で、これらの休止状態について説明します。
ネットワーク休止状態 | 説明 |
---|---|
DORM_Never |
このアクタは、休止状態になることがありません。 これは、休止システムによって強制されるものではありません。 |
DORM_Awake |
このアクタは休止状態ではなく、レプリケーションの対象になります。 |
DORM_DormantPartial |
このアクタは一部の接続で休止状態となっていますが、すべてではありません。 部分的な休止の使用は推奨していません。部分的な休止は廃止される予定です。 |
DORM_Initial |
このアクタは、最初はすべての接続で休止状態です。 これは、最初にマップに配置されるアクタのみが使用します。 |
DORM_DormantAll |
このアクタは、すべての接続で休止状態となります。 |
アクタの休止状態を解除する
アクタの休止状態を解除するには、主に 2 つの方法があります。
- Net Dormancy プロパティを設定する。
- Flush Net Dormancy 関数を呼び出す。
ネット休止を設定する
AActor::SetNetDormancy(ENetDormancy::DORM_Awake)
を呼び出して、アクタの休止状態を解除できます。アクタがアウェイク状態の間は、アクタから AActor::SetNetDormancy(ENetDormancy::DORM_DormantAll)
を呼び出して休止状態に戻るまで、通常どおりにレプリケートされます。これは、静止しているオブジェクトが動き始めるなど、休止アクタがフレームごとに変更し始めるような場合に便利です。
静的に配置され、最初は休止状態だったアクタがアウェイク状態になったら、ENetDormancy::DORM_Initial
に戻さないでください。代わりに、ENetDormancy::DORM_DormantAll
を使用します。
ネット休止をフラッシュする
アクタで AActor::FlushNetDormancy
を呼び出すと、休止中のアクタの変更をレプリケートできます。これにより、アクタでは強制的に少なくとも 1 つの更新を関連するすべての接続にレプリケートしますが、実際に休止状態が変更されることはありません。1 つの例外として、AActor::NetDormancy
が ENetDormancy::DORM_Initial
に設定されているアクタで AActor::FlushNetDormancy
を呼び出すと、AActor::FlushNetDormancy
への呼び出しによってアクタの休止状態が ENetDormancy::DORM_DormantAll
に変更されます。
ネット更新を強制する
休止状態のアクタで AActor::ForceNetUpdate
を呼び出すと AActor::FlushNetDormancy
も呼び出されますが、そのアクタは次のネット更新で確実にレプリケーションの対象となります。これは単一フレームで発生するアクタへの頻度の低い、1 回限りの更新の場合に役立ちます。
アクタの休止状態がフラッシュされたあと (または、アウェイク状態から休止状態に設定されると)、アクタはすぐに休止状態にならないため、複数の更新を送信することがあります。代わりに、アクタとそのサブオブジェクトに送信を必要とする未確認の変更がなくなるまで、アクタはレプリケートし続けます。休止ヒステリシスが有効な場合も、アクタはすぐに休止状態になりません (UActorChannel::ReadyForDormancy
と FObjectReplicator::ReadyForDormancy
を参照してください)。
ウェイク メソッドを使用するタイミング
レプリケートされたプロパティに変更を加える前に、アクタで AActor::SetNetDormancy(ENetDormancy::DORM_Awake)
や AActor::FlushNetDormancy
を呼び出す必要があります。アクタの休止状態を解除すると、そのアクタのレプリケートされたプロパティの現在値をすべてコピーすることにより、アクタのシャドウ状態 (どのプロパティが変更されてレプリケートする必要があるかを比較するために使用される状態) が再初期化されます。これはまた、アクタのレプリケートされた状態を、休止状態の間は変更すべきではない理由にもなります。アクタがアウェイク状態になると、レプリケーションのプロパティを比較する際、これらの変更が検出されないためです。
ただしほとんどの場合、変更後に呼び出しても、これらの変更は予測どおりにレプリケートされる可能性があります。その場合も、この動作は実装の詳細のため、これに依存しないでください。たとえば、休止している高速配列を変更する場合などは、プロパティの変更後に AActor::FlushNetDormancy
を呼び出すと、変更がまったくレプリケートされない状況になります。
ブループリント アクタによる休止
ブループリント アクタで休止を使用する場合、レプリケートされたプロパティを設定すると、アクタは自動的に AActor::FlushNetDormancy
を呼び出します。
レプリケートされたプロパティを ActorComponent
ブループリントに設定する場合は自動的に発生しないため、この動作が一貫して行われるように取り組んでいます。
休止およびレプリケーション グラフ
レプリケーション グラフ を使用する場合、休止はデフォルトの NetDriver
を使用するときと同様に操作する必要があるため、プロジェクト コードでアクタを休止 / アウェイク状態に設定し、通常どおりに AActor::FlushNetDormancy
を呼び出すことができます。アクタの一覧を収集する際、ノードで休止アクタが返された場合にも、UReplicationGraph::ReplicateActorListsForConnections_Default
は引き続き、それらのアクタのレプリケートをスキップします。
Replication Graph ノードには、休止アクタ用の特別な処理を含めることができます。これにより、ノードで休止アクタの処理に費やされる時間とメモリが削減され、収集されるアクタの一覧のサイズも縮小することができます。たとえば、GridSpatialization2D
ノードには休止アクタの追加処理が含まれています。これは休止状態のアクタを静的として扱い、アウェイク状態の場合は動的として扱います。これはグリッドを移動することがあり、それ以外の場合は静止して休止状態にもなるアクタに対して役立ちます。
ネットワーク休止をデバッグする
ログ記録
LogNetDormancy
ログ カテゴリを有効にして、アクタの休止ステータスに関する情報をログで取得します。このカテゴリの詳細度を高めると、アクタの休止状態をフラッシュする場合などにより詳細な情報が記録されます。
コンソール変数
次の表に、ネットワーク休止に関連するコンソール変数をいくつか示します。
コンソール変数 | 説明 |
---|---|
net.DormancyEnable |
すべてのアクタの休止状態を完全に有効または無効にするために使用します。これは、レプリケーションの問題が休止状態に関連しているかどうかを判断する場合に役立ちます。 |
net.ReuseReplicatorsForDormantObjects |
これを有効にすると、サーバーでは、アクタが休止状態になった場合に休止オブジェクトの この機能は内部では使用されなくなりました。これらのレプリケーターを保持すると、サーバーのメモリ使用量が増加します。休止アクタが多数あるプロジェクトの場合、この追加メモリ使用量がかなりの量になる可能性があります。これらのレプリケーターを再利用すると、サブレベルでアクタをレプリケートする場合に問題が発生する可能性もあります。 |
net.DormancyValidate |
これを有効にすると、アクタが休止状態中にレプリケートされたプロパティを変更した場合、ログに警告が出力されます。
休止の検証を有効にした場合、休止中にレプリケートされたプロパティを比較するのに必要となるため、休止状態のオブジェクトのレプリケーターが再利用されます。 |
net.DormancyHysteresis |
完全に休止状態になるまでにアクタ チャンネルが待機する時間 (秒)。これはデフォルトで「0」に設定されていますが、値を増やすと、アクタが急速に休止状態に入ったり解除されたりする場合のチャーンを防ぐことができます。 |
Net.RepGraph.LogNetDormancyDetails |
これを有効にすると、レプリケーション グラフが休止アクタを処理する方法に関するより詳細なログ情報が出力されます。 |
Net.RepGraph.DormantDynamicActorsDestruction |
これを有効にすると、休止アクタは関連性が失われるとクライアント上で破棄されます。その他のこの動作を構成する方法については、ReplicationGraph.cpp の上部にあるコンソール変数を確認してください。 |
Unreal Engine でのコンソール変数の詳細については、「コンソール変数」のドキュメント ページを参照してください。