クライアント側のアクター生成処理について

お世話になっております。

アクター同期時のクライアント側の挙動について気になったところがありましたので確認のため質問させて頂きます。

PackageMapClient.cppのSerializeNewActor()関数内は下記クライアント側のアクターを生成するコードがあります(476行目あたり):

// Spawn actor if necessary (we may have already found it if it was dormant)
if ( Actor == NULL )
{
	if ( Archetype )
	{
		// For streaming levels, it's possible that the owning level has been made not-visible but is still loaded.
		// In that case, the level will still be found but the owning world will be invalid.
		// If that happens, wait to spawn the Actor until the next time the level is streamed in.
		// At that point, the Server should resend any dynamic Actors.
		ULevel* SpawnLevel = Cast(ActorLevel);
		if (SpawnLevel == nullptr || SpawnLevel->GetWorld() != nullptr)
		{
			FActorSpawnParameters SpawnInfo;
			SpawnInfo.Template = Cast(Archetype);
			SpawnInfo.OverrideLevel = SpawnLevel;
			SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
			SpawnInfo.bRemoteOwned = true;
			SpawnInfo.bNoFail = true;

			UWorld* World = Connection->Driver->GetWorld();
			FVector SpawnLocation = FRepMovement::RebaseOntoLocalOrigin(Location, World->OriginLocation);
			Actor = World->SpawnActorAbsolute(Archetype->GetClass(), FTransform(Rotation, SpawnLocation), SpawnInfo);
			if (Actor)
			{
				// Velocity was serialized by the server
				if (bSerializeVelocity)
				{
					Actor->PostNetReceiveVelocity(Velocity);
				}

				// Scale was serialized by the server
				if (bSerializeScale)
				{
					Actor->SetActorScale3D(Scale);
				}

				GuidCache->RegisterNetGUID_Client(NetGUID, Actor);
				bActorWasSpawned = true;
		   }

World->SpawnActorAbsoluteを呼ぶ際にTransformにScaleを入れていなくて、Spawnした後でScaleだけを再設定するのはなぜでしょうか?

SpawnInfoのbDeferConstructionがデフォルト値のままなのでSpawnActorAbsolute()の中ではBeginPlayが呼ばれません。そのためSetActorScale3D()を呼ばれるタイミングではBeginPlayがまだ呼ばれていませんけど、SetActorScale3D()経由でUpdateOverlap()が呼ばれます。その挙動は正しいのでしょうか?

よろしくお願いいたします。

お世話になっております。

調査を進めた所、どうやらUE4.9(2015年頃)に以下の不具合を解決するために入ったコードのようです。

CLは 2553803 です(もしかすると、ライセンシ様には見えないCLかもしれません)。このCLで SerializeNewActor関数における bSerializeScale, bSerializeVelocityの対応が入ったことで、デフォルト値から変化のないScale, Velocityが無駄にReplicateされる問題が回避されました。

本題であるなぜSpawnActorAbsoluteにScaleが入っていないのかに関してですが、残念ながら当時の実装者が既に退職済みのため、当時どのような意図でそのように実装したかを確認することができませんでした。ただコードの変更履歴を追った所、現在のSpawnActorAbsoluteを使ったコードの前はSpawnActorが使われており、さらに実装当時はSpawnActorはLocation, Rotationしか指定できなかったようです。そして、その事情を知らない別の担当者がSpawnActorからSpawnActorAbsoluteに変更したことで、現在のScaleだけ再設定する形になってしまった可能性が高いかと思います。

おそらく、SpawnActorAbsoluteにてScaleを設定しても問題ないかとは思うのですが、Actor->SetActorScale3Dを削除することによる影響で何か別の問題が発生するかもしれません。もしUpdateOverlapが呼ばれることが問題になっている場合は、UpdateOverlapsを呼ばないSetActorScale3Dを別途用意することもご検討頂けますと幸いです。

よろしくお願いいたします。

お世話になっております。

SetActorScale3Dを削除すると影響が出る可能性がある旨を承知しました。

今回の件に関してはBeginPlayでコリジョンの設定を行っているため、BeginPlayが呼ばれる前にUpdateOverlapsが呼ばれると想定外の挙動になります。仕様上BeginPlayが呼ばれる前に該当アクターのコリジョンをオフにしても問題がないので今回はアプリ側でコリジョンをオフにする形で対処いたします。

調査と情報共有ありがとうございました。

よろしくお願いいたします。