結果として、エディター版はあきらかactorの数がすくない
こちらはエンジン側の不具合なのでしょうか、こちらのほうでAPIの使用方法が誤っているのであればご教示いただきたいです。
<br/>
ためしに別のデリゲートであるOnLevelShownのタイミングまでロード完了をまってみたのですが、同じ結果でした。
<br/>
<br/>
[Attachment Removed]
結果として、エディター版はあきらかactorの数がすくない
こちらはエンジン側の不具合なのでしょうか、こちらのほうでAPIの使用方法が誤っているのであればご教示いただきたいです。
<br/>
ためしに別のデリゲートであるOnLevelShownのタイミングまでロード完了をまってみたのですが、同じ結果でした。
<br/>
<br/>
[Attachment Removed]
再現手順
下記のようにロード処理を行うローダークラスを作成した。
RequestLevelInstanceLoadでロードを開始し、OnLevelLoaded.AddUniqueDynamicでロード完了後の処理としてロードされたレベルのactorを全走査してなんらかの処理をするようにしているが、パッケージ版とエディター版で取得できるactorの数が異なっておりました。
UCLASS()
class UTestLoader
{
GENERATED_BODY()
private:
UPROPERTY()
TObjectPtr<class ULevelStreamingDynamic> loaded_instance_ = nullptr;
public:
//ロード処理
bool RequestLevelInstanceLoad(UWorld* _world, const FString& level_name);
//ロード完了後呼び出される処理
void OnInstanceLoaded()
};
bool UTestLoader::RequestLevelInstanceLoad(UWorld* _world, const FString& level_name)
{
loaded_instance_ = ULevelStreamingDynamic::LoadLevelInstance(_world_ptr, _level_name, FVector::Zero(), FRotator::ZeroRotator, result);
if (loaded_instance_)
{
// ロード要求
loaded_instance_->SetShouldBeLoaded(true);
loaded_instance_->SetShouldBeVisible(false);
loaded_instance_->OnLevelLoaded.AddUniqueDynamic(this, &ThisClass::OnInstanceLoaded); //ロード完了後のデリゲート処理登録
}
}
//ロード完了時によばれる
void UTestLoader::OnInstanceLoaded()
{
auto *level = loaded_instance_->GetLoadedLevel();
if (IsValid(level))
{
//パッケージ版とエディター版で取得できるactorの数が異なる
//エディター版だと明らかにすくない
for (auto &actor :level->Actors)
{
// do something ....
}
}
loaded_instance_->SetShouldBeVisible(true);
}
[Attachment Removed]
いつもお世話になっております。
ご提供いただいた再現手順、ありがとうございます。コードを確認いたしました。
まずAPIの使用方法についてですが、ULevelStreamingDynamic::LoadLevelInstanceによるロード要求、およびOnLevelLoadedへのデリゲート登録の流れは正しく、ロード完了後にGetLoadedLevelからActorsを走査する方法についても問題ございません。この点に誤りは見当たりませんでした。
OnLevelShownを試された件についてですが、OnLevelShownはレベルがワールドに追加(AddToWorld)された後に呼ばれるため、OnLevelLoadedよりも遅いタイミングとなります。それでもアクター数が変わらないということは、少なくとも同じ実行状況においては、ストリーミングの完了待ちといったタイミングの問題ではなく、その時点でロード済みレベルのActorsにアクターが存在していないことを示していると考えられます。
一方で、これがエンジン側の不具合なのか、プロジェクトの構成上想定どおりの挙動なのかは、再現手順のみでは判断いたしかねます。原因の切り分けのため、下記についてご教示いただけますでしょうか。
①対象のマップでWorld Partitionが有効になっているか、また「One File Per Actor(OFPA)」が有効になっているか。
②「エディター版」とは、PIE(Play In Editor)での実行を指すのか、それともプレイ実行ではなく、エディター上でレベルインスタンスをロードした状態を指すのか。
③エディター版とパッケージ版とで、具体的にどのアクターが取得できていないのか。両者で取得できたアクターの一覧(アクター名とクラス)を比較いただくか、不足しているアクターの傾向をお知らせいただけますと、原因の特定につながります。
特に③は切り分けに最も有効な情報となりますので、可能でしたらご共有いただけますと幸いです。
いただいた情報をもとに詳細を確認のうえ、改めてご回答いたします。
何卒よろしくお願いいたします。
[Attachment Removed]
ありがとうございます。
①対象のマップでWorld Partitionが有効
有効になってます
②「エディター版」とは、PIE(Play In Editor)での実行を指すのか、それともプレイ実行ではなく、エディター上でレベルインスタンスをロードした状態を指すのか。
PIEでの実行をさしてます
③エディター版とパッケージ版とで、具体的にどのアクターが取得できていないのか。
パッケージ版では およそ 2000のActorがロードされており
PIEでは 3~4このActorがロードされました。
今回は、ロード時にライトを制御したく 下記のコンポーネントがついているActorを操作したいのですが
“ULightComponentBase”
PIEだと取得できませんでした。
[Attachment Removed]
お世話になっております。
詳細をご提供いただき、ありがとうございます。エンジンソースを確認いたしました。
結論としましては、エンジンの不具合でもAPIの使用方法の誤りでもなく、World Partitionが有効なマップにおけるPIEとパッケージ版のデータ構造の違いによる仕様上の挙動と考えられます。
パッケージ版では、クック時に常時ロード扱い(Is Spatially Loadedが無効)のアクターがパーシスタントレベルへ移動されます。UWorldPartitionRuntimeLevelStreamingCell::OnPrepareGeneratorPackageForCookがFWorldPartitionLevelHelper::MoveExternalActorsToLevelでPersistentLevelへ移動する実装となっており、そのため約2000個のアクターが取得できております。
一方PIEではこの移動が行われず、すべてのアクターがWorld Partitionの生成するセル(別のULevel)経由でストリーミングされます。GetLoadedLevel()->Actorsに含まれるのは組み込みのアクターのみとなるため、どのタイミングで走査してもライトは取得できません。OnLevelShownで結果が変わらなかったのもこのためです。
対処としましては、下記をご検討いただけますでしょうか。
①当該マップ内でのストリーミングが不要であれば、World Partition無効の通常レベルとして作成し直す方法。PIEとパッケージ版で挙動が一致いたします。
②World Partitionを維持される場合は、FWorldDelegates::LevelAddedToWorldで追加される各レベルのActorsを処理する方法。当該インスタンス由来かどうかは、FWorldPartitionHelpers::GetWorldPartition(InLevel)の戻り値の比較で判定できます。ロード完了の待機にはUWorldPartitionSubsystem::IsStreamingCompletedをご利用いただけます。
なお、ライト制御が目的であれば、アクター側のBeginPlayでSubsystemに自己登録する設計にしていただくと、配置先レベルに依存せず確実に処理できるかと思います。
ご不明な点がございましたら、お気軽にお問い合わせください。
お手数ですが、よろしくお願いします。
[Attachment Removed]