Language:
Page Info
Engine Version:
The translation of this page is out of date. Please see the English version for the latest version of the page.

コンポーネントのレプリケーション

アンリアル エンジン 4 はコンポーネントのレプリケーションをサポートしています。使い方は簡単ですが、あまり一般的ではなく、ほとんどのコンポーネントはレプリケーションしません。ほとんどのゲームプレイのロジックは、Actor クラスで行われ、 コンポーネントは Actor を構成する小さな部分を表します。Actor のゲームプレイ ロジックがレプリケーションの対象であり、結果としてコンポーネントを呼び出し / 変更することがあります。しかし、場合によっては、 コンポーネント上のプロパティやイベント自体を直接レプリケーションする必要があります。このドキュメントではその使用方法を説明します。

コンポーネントは、所有するアクタの一部としてレプリケートします。アクタはなおも役割、プライオリティ、関連性、カリングなどを規定します。アクタがレプリケートすると、そのコンポーネントもレプリケートする場合があります。こうしたコンポーネントは、 アクタと同様の方法でプロパティと RPC をレプリケーションします。コンポーネントはアクタと同様の方法で::GetLifetimeReplicatedProps (...) 関数を実装しなければなりません。

コンポーネントのレプリケーションについて言及する場合、2 つの大きなコンポーネントのカテゴリがあります。静的コンポーネントはアクタ作成時に作成されるコンポーネントです。つまり、所有しているアクタがクライアントまたはサーバーでスポーンされた場合に、こうしたコンポーネントもスポーンされます。 コンポーネントがレプリケーションされるか、否かは関係ありません。サーバーはクライアントに対して、このようなコンポーネントを明示的にスポーンするように指示しません。こうした意味で、静的コンポーネントはデフォルトのサブオブジェクトとして C++ コンストラクタで作成される、またはブループリント エディタのコンポーネント モードで作成されるコンポーネントです。静的コンポーネントは、クライアント上に存在するようにレプリケーションする必要はなく、 デフォルトで存在します。サーバーとクライアントとの間でプロパティやイベントを自動的に同期する必要がある場合に限り、レプリケーションする必要があります。

動的コンポーネントはランタイムにサーバーでスポーンされるコンポーネントであり、その作成と削除はクライアントにレプリケーションされます。アクタとほとんど同じように機能します。静的コンポーネントとは異なり、 動的コンポーネントは、すべてのクライアント上に存在するようにレプリケーションする必要があります。または、クライアントが独自のローカルのレプリケーションしないコンポーネントをスポーンすることができます。これは実際には、多くのケースでうまくいきます。レプリケーションが関わってくる場合のみ、サーバー上でトリガーしたプロパティまたは イベントを自動的にクライアントに同期する必要があります。

使用法

コンポーネントでのプロパティと RPC の設定は、アクタと全く同じように機能します。クラスがレプリケーションされたものを持つようにセットアップされると、こうしたコンポーネントの実際のインスタンスは必ずレプリケーションするようにセットアップされなければなりません。

C++

コンポーネントをレプリケートさせるには、単に AActorComponent::SetIsReplicated(true) を呼び出します。コンポーネントがデフォルトのサブオブジェクトである場合、これはコンポーネントをスポーン後にクラス コンストラクタで行うようにします。

以下はその例です。

ACharacter::ACharacter()
{
    // Etc...

    CharacterMovement = CreateDefaultSubobject<UMovementComp_Character>(TEXT("CharMoveComp"));
    if (CharacterMovement)
    {
        CharacterMovement->UpdatedComponent = CapsuleComponent;

        CharacterMovement->GetNavAgentProperties()->bCanJump = true;
        CharacterMovement->GetNavAgentProperties()->bCanWalk = true;
        CharacterMovement->SetJumpAllowed(true);
        CharacterMovement->SetNetAddressable(); // Make DSO components net addressable
        CharacterMovement->SetIsReplicated(true); // Enable replication by default

    }
}

ブループリント

静的なブループリント コンポーネントをレプリケートするには、コンポーネントのデフォルトで Replicates をトグルするだけです。繰り返しになりますが、これはコンポーネントがレプリケートする必要があるプロパティやイベントを持っている場合にのみ 行う必要があります。静的コンポーネントの作成はクライアントとサーバーの両方で暗示的です。

components_checkbox.png

必ずしもすべてのコンポーネントがこれを表示するわけではなく、何らかのレプリケーションをサポートするものだけが表示することに注意してください。

これは、SetIsReplicated 関数を呼び出して、動的にスポーンされたコンポーネントによって行うこともできます。

components_function.png

タイムライン

タイムラインでは、プロパティにある Replicated オプションで必ずレプリケートを有効にしなければなりません。サーバー制御のプレイ位置、レート、方向をクライアントにレプリケートします。これは基本的な実装であり、 ニーズの変化に応じて進化する場合があります。ほとんどのタイムラインはレプリケートする必要はありません。レプリケートされたゲームプレイ オブジェクトのように、レプリケートされたタイムラインは、 直接サーバー上でのみ (開始/終了など) 操作するようにします。クライアントはレプリケートされたプレイ位置だけを見るようにしますが、タイムラインそのものを変更しようとしないでください。レプリケートの更新間では、 クライアントはプレイ位置を推定します。

帯域幅のオーバーヘッド

コンポーネント レプリケーションのオーバーヘッドは比較的低いものです。レプリケートするアクタ内の各コンポーネントは、NetGUID (4 バイト) 'ヘッダ' と 約 1 バイトの 'フッタ' をそのプロパティと共に新たに追加します。CPU の観点からは、プロパティをアクタでレプリケートすることと、コンポーネント上でレプリケートすることにはわずかな違いしかないはずです。

一般化されたサブオブジェクトのレプリケーション

さらに進んだ手順を行うことができます。すなわち、単にコンポーネントだけでなくすべてのアクタのサブオブジェクトをレプリケート可能です。

適用範囲は非常に狭いものですが、場合によっては非常に役立ちます。これを行うインターフェースは以下のクラスレベルで定義されます。

/** サブオブジェクトのレプリケーションのためにテンプレート化された TobjectReplicator クラスをインスタンス化するための FActory メソッド */
virtual class FObjectReplicatorBase * InstantiateReplicatorForSubObject(UClass *SubobjClass);

/** アクタがアクタ チャンネル上でサブオブジェクトをレプリケートできるようにするメソッド*/
virtual bool ReplicateSubobjects(class UActorChannel *Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags);

/** 新規サブオブジェクトがレプリケーションによって動的に作成される場合にアクタで呼び出されます。*/
virtual void OnSubobjectCreatedFromReplication(UObject *NewSubobject);

非 ActorComponent サブオブジェクトをレプリケーションする必要があるクラスは上記の 3 つのメソッドを実装すべきです。

使用事例

これは、アクタ チャンネル レベルで UObjects とポリモーフィズムを利用可能であるため役立ちます。これまでは、複雑なデータ構造のレプリケーションは常に、 型が Actor クラス内で静的に定義されている構造体に制限されていました。サブオブジェクトのレプリケーションでは、例えば、インベントリ システムを持つことができるようになりました。 このシステムでは、各アイテムは基底インベントリ クラスから拡張するクラスであり、完全にレプリケート可能であり、アイテムが Actors である必要はありません (これは、リソースが重たくなりすぎます)。

最適化

レプリケートするサブオブジェクトが多い場合は、Actor で、どれが最近変更され、レプリケートする必要があるサブオブジェクトであるかを把握することで多くの時間を節約できます。つまり、アクセサ関数によって変更するサブオブジェクトを追跡し続けます。 これを行うインターフェースは AActorChannel にあります。:

bool KeyNeedsToReplicate(int32 ObjID, int32 RepKey);

この関数は、Actor によって ::ReplicateSubobjects 実装で呼び出されます。Actor クラスでは、レプリケーション システムは各クライアントに対して追跡する任意のオブジェクト ID と レプリケーション キーをセットアップできます。ReplicateSubobjects が true を戻すと、呼び出し元はそのオブジェクト ID で追跡しているサブオブジェクトで ReplicateSubobjects を呼び出すはずです。 例えば、AQAInventory::ReplicateSubobjects をご覧ください。ここで覚えておくべき重要なことは、オブジェクト ID とレプリケーション キーは完全に任意の物であるという点です。オブジェクト ID は単に「もの」を参照するために使用されます。それはサブオブジェクトのリスト全体、部分的リスト、または個々のオブジェクトである場合があります。レプリケーション キーも任意であり、追跡しているオブジェクト ID が変わればインクリメントするカウンタのようなものです。ここで説明した最適化は完全に任意のものです。