ULevelStreamingDynamic::LoadLevelInstanceのロード完了時の状態がエディター版とパッケージ版で異なる

結果として、エディター版はあきらか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]