鈴木です。
マルチプレイクライアント上でのBeginPlayやPostInitComponentの呼び出しタイミングはシングルプレイ時と差があり
マルチプレイを考慮していないといろいろな問題が出たり出なかったりします。
#シングルプレイ時の処理順序
- アクターのSpawnリクエスト
- SpawnActor
- (DeferConstruction)
- ユーザー初期化コード
- PostActorConstruction
- PreInitComponent
- PostInitComponent
- BeginPlay
#マルチプレイ時の処理順序
マルチプレイ時はパケット受信後にそのオーダーに合わせて初期化が行われます。
DeferConstructionは処理できません
注目すべきはプロパティのストア位置とRepNotifyがBeginPlayの前に呼ばれることと、SpawnParamterなどのプロパティ適用がPostInitComponentなどの後に行われうことです。
- パケット受信
- SpawnActor
- PostActorConstruction
- PreInitComponent
- PostInitComponent
- ReceiveBunch
- プロパティをアクターにストア
- RepNotifyを処理
- PostNetInit
- BeginPlay
このような流れになっています。シングルプレイやAuthorityを持っているプロセス上では初期化処理はストレートに行われますが、
クライアントではBeginPlayの前にさまざまなユーザーコードが実行される余地があるため問題が発生しやすいです。
この流れを考慮してあるとスムーズにマルチプレイゲームが構築できるかもしれません。
#BeginPlay前のRepNotifyについて
RepNotifyがBeginPlayなどに依存する場合、正しく処理できない可能性があります。
コールバック関数が呼び出される前にユーザーコードを挟む余地があれば初期化等をおこなって正しく処理出来そうです。
RepNotifies処理部近辺を探してみるといいのがありました
void FObjectReplicator::PostReceivedBunch()
{
...
if (!bIsServer && bHasReplicatedProperties)
{
PostNetReceive(); <----------------------------
bHasReplicatedProperties = false;
}
...
// Call RepNotifies
CallRepNotifies(true);
これだよこれ。
virtual void UObject::PostNetReceive()
こいつで初期化コードを処理すればいい感じ。
ただしAutorityやシングルプレイ時には呼び出され無いので注意が必要です
このあたりはBlueprintだと対処しにくいかもしれません。
糸冬