基本的なプロパティのレプリケーション
今回は、ネイティブ コードでレプリケートされたプロパティを処理する場合に役立つ秘訣をいくつかお話ししたいと思います。
プロパティをレプリケートする方法について説明し尽くすことは、今回の記事の範囲から外れますので、基本事項についてざっと見て行くことにしましょう。
プロパティをレプリケートするには、以下のことが必要となります。
プロパティが定義されている Actor クラスのヘッダに、UPROPERTY 宣言の引数の 1 つとして replicated キーワードを入れます。
class ENGINE_API AActor : public UObject
{
UPROPERTY( replicated )
AActor * Owner;
};
Actor クラスの実装では、GetLifetimeReplicatedProps 関数を実装します。
void AActor::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const
{
DOREPLIFETIME( AActor, Owner );
}
Actor のコンストラクタで、bReplicates フラグを true にセットします。
AActor::AActor( const class FPostConstructInitializeProperties & PCIP ) : Super( PCIP )
{
bReplicates = true;
}
大体こんなところでしょうか。これで、メンバー変数の Owner は、現在インスタンス化されているこの Actor 型 (この場合、ベースの Actor クラス) のあらゆるコピーのために接続されているすべてのクライアントと同期します。
条件付きプロパティのレプリケーション
いったんプロパティがレプリケーションのために登録されると、登録を外すことはできません (ライフタイムの部分はこのことに基づきます)。その理由は、できるだけ多くの情報を組み入れることによって、同一セットのプロパティのために接続されている多数のクライアント間で作業を分配することができるからです。計算時間をかなり節約できるわけです。
では、このプロパティのレプリケーションをより細かく制御するにはどうしたらよいでしょうか?そこで出てくるのが、条件付きプロパティです。
デフォルトでは、レプリケートされた各プロパティは、固有の条件をもっていて、それらが変化していない場合は、レプリケートされないということになります。
プロパティのレプリケーションをより緻密に制御するためには、第二の条件を加えることができる特別なマクロがあります。
このマクロは、DOREPLIFETIME_CONDITION という名前が付いています。以下にその使用例を挙げてみます。
void AActor::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const
{
DOREPLIFETIME_CONDITION( AActor, ReplicatedMovement, COND_SimulatedOnly );
}
COND_SimulatedOnly フラグが条件マクロに渡され、レプリケーション対象のプロパティが評価される前であっても、追加の条件チェックが実行されるようになります。この場合は、このアクタのシミュレートしているコピーをもつクライアントにのみレプリケートされます。
こうすることには大きなメリットがあります。それは帯域幅が節約できるということです。このアクタの自律的なプロキシバージョンをもつクライアントが、このプロパティを認識する必要はないと定めたからです (このクライアントは、たとえば、予測目的でこのプロパティを直接セットしています)。もう一つのメリットは、サーバーが、このプロパティを受け取っていないクライアントのために、クライアントのローカルコピーについて処理しなくなるということがあります。
以下は、現在サポートされている条件のリストの概略です。
- COND_InitialOnly - このプロパティは、最初のパケットのみを転送しようとします。
- COND_OwnerOnly - このプロパティは、アクタのオーナーにのみ送信します。
- COND_SkipOwner - このプロパティは、オーナー以外の接続すべてに送信します。
- COND_SimulatedOnly - このプロパティは、シミュレートされたアクタにのみ送信します。
- COND_AutonomousOnly - このプロパティは、自律的なアクタにのみ送信します。
- COND_SimulatedOrPhysics- このプロパティは、シミュレートされたアクタまたは bRepPhysics のアクタに送信します。
- COND_InitialOrOwner - このプロパティは、最初のパケットのみを転送します。あるいは、アクタのオーナーにのみ転送します。
- COND_Custom - このプロパティには、特定の条件がありませんが、SetCustomIsActiveOverride によって on/off の切り替え機能をもたせることができます。
ここまで、既知の状態に基づく状態について話してきました。これによって、エンジンは必要な最適化を行うことが容易になるとともに、みなさんはプロパティのレプリケーションを充分に制御できるようになります。
しかし、これで充分な制御が得られない場合はどうなるでしょうか?実は、このテーマについては、もう 1 つお話しすべきことがあります。DOREPLIFETIME_ACTIVE_OVERRIDE という名前のマクロがあります。これを利用すると、あなたが必要とする任意の条件を使って、プロパティをレプリケートする場合しない場合を、完全に制御することが可能になるのです。ただし、1 つ注意しなければならないことがあります。それは、アクタ単位であって、接続単位ではないということです。言い換えれば、カスタムの条件において接続単位で変化する状態を使用することは安全ではないということになります。次がその例です。
void AActor::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker )
{
DOREPLIFETIME_ACTIVE_OVERRIDE( AActor, ReplicatedMovement, bReplicateMovement );
}
これで、ReplicatedMovement というプロパティは、bReplicateMovement が true である場合にのみレプリケートされるようになります。
なぜこのマクロを常に使わないのでしょうか?このメソッドを避ける理由は、主に 2 つあります。
- 1 つは、カスタムの条件値が頻繁に変化すると、重くなるからです。
- • もう 1 つは、通信単位で変化できる条件を使えないからです。(ここで RemoteRole はチェックされない)
プロパティのレプリケーションに関する条件を使うことによって、制御とパフォーマンスの間で適切なバランスが実現します。これらの条件によって、エンジンは、多数の接続のためにチェックおよび送信する時間を最適化するチャンスが得られます。一方、プログラマーは、プロパティのレプリケーションをいつどのようにするか微調整できるようになります。
これで、ネットワークに関するヒントと秘訣はお終いですが、何か質問はありませんか?ぜひ、フォーラムに参加して、ディスカッションを続けてください!