Files
UnrealEngine/Engine/Source/Editor/LevelInstanceEditor/Private/PackedLevelActorUtils.cpp
2025-05-18 13:04:45 +08:00

183 lines
5.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if WITH_EDITOR
#include "PackedLevelActorUtils.h"
#include "PackedLevelActor/PackedLevelActor.h"
#include "PackedLevelActor/PackedLevelActorBuilder.h"
#include "LevelInstance/LevelInstanceInterface.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Engine/World.h"
#include "Engine/Blueprint.h"
#include "EngineUtils.h"
#include "Misc/ScopedSlowTask.h"
#include "Editor.h"
#include "UObject/UObjectIterator.h"
#define LOCTEXT_NAMESPACE "FPackedLevelActorUtils"
void FPackedLevelActorUtils::GetPackedBlueprintsForWorldAsset(const TSoftObjectPtr<UWorld>& InWorldAsset, TSet<TSoftObjectPtr<UBlueprint>>& OutPackedBlueprintAssets, bool bInLoadedOnly)
{
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
if (InWorldAsset.IsNull())
{
return;
}
TArray<FSoftObjectPath> AssetsToProcess;
AssetsToProcess.Add(InWorldAsset.ToSoftObjectPath());
TSet<FSoftObjectPath> ProcessedAssets;
while (!AssetsToProcess.IsEmpty())
{
FSoftObjectPath ProcessingAsset = AssetsToProcess.Pop();
ProcessedAssets.Add(ProcessingAsset);
TArray<FName> ReferencerPackages;
AssetRegistry.GetReferencers(*ProcessingAsset.GetLongPackageName(), ReferencerPackages);
for (FName ReferencerPackage : ReferencerPackages)
{
TArray<FAssetData> Assets;
AssetRegistry.GetAssetsByPackageName(ReferencerPackage, Assets);
for (const FAssetData& Asset : Assets)
{
if (UClass* AssetClass = Asset.GetClass(bInLoadedOnly ? EResolveClass::No : EResolveClass::Yes))
{
if (TSubclassOf<UBlueprint> BlueprintClass = AssetClass)
{
if (UBlueprint* Blueprint = Cast<UBlueprint>(Asset.GetAsset()); Blueprint && Blueprint->GeneratedClass && Blueprint->GeneratedClass->IsChildOf<APackedLevelActor>())
{
FSoftObjectPath BlueprintAsset(Blueprint);
if (!ProcessedAssets.Contains(BlueprintAsset) && ProcessedAssets.Contains(Blueprint->GeneratedClass->GetDefaultObject<APackedLevelActor>()->GetWorldAsset().ToSoftObjectPath()))
{
OutPackedBlueprintAssets.Add(Blueprint);
AssetsToProcess.Add(BlueprintAsset);
}
}
}
else if (TSubclassOf<AActor> ActorClass = AssetClass; ActorClass && ActorClass->ImplementsInterface(ULevelInstanceInterface::StaticClass()))
{
FSoftObjectPath ReferencingAsset(Asset.GetSoftObjectPath().GetWithoutSubPath());
if (!ProcessedAssets.Contains(ReferencingAsset))
{
AssetsToProcess.Add(ReferencingAsset);
}
}
else if (TSubclassOf<UWorld> WorldClass = AssetClass)
{
FSoftObjectPath ReferencingAsset(Asset.GetSoftObjectPath());
if (!ProcessedAssets.Contains(ReferencingAsset))
{
AssetsToProcess.Add(ReferencingAsset);
}
}
}
}
}
}
}
bool FPackedLevelActorUtils::CanPack()
{
if (!GEditor)
{
return false;
}
if (GEditor->GetPIEWorldContext())
{
return false;
}
if (ULevelInstanceSubsystem* LevelInstanceSubsystem = GEditor->GetEditorWorldContext().World()->GetSubsystem<ULevelInstanceSubsystem>())
{
return !LevelInstanceSubsystem->GetEditingLevelInstance();
}
return false;
}
void FPackedLevelActorUtils::PackAllLoadedActors()
{
if (!CanPack())
{
return;
}
TSet<APackedLevelActor*> PackedLevelActorsToUpdate;
TSet<UBlueprint*> BlueprintsToUpdate;
if (UWorld* EditorWorld = GEditor->GetEditorWorldContext().World())
{
for (TActorIterator<APackedLevelActor> PackedLevelActorIt(EditorWorld); PackedLevelActorIt; ++PackedLevelActorIt)
{
APackedLevelActor* PackedLevelActor = *PackedLevelActorIt;
UBlueprint* Blueprint = PackedLevelActor->GetRootBlueprint();
if (Blueprint)
{
BlueprintsToUpdate.Add(Blueprint);
}
else
{
PackedLevelActorsToUpdate.Add(PackedLevelActor);
}
}
}
int32 Count = BlueprintsToUpdate.Num() + PackedLevelActorsToUpdate.Num();
if (!Count)
{
return;
}
GEditor->SelectNone(true, true);
FScopedSlowTask SlowTask(Count, (LOCTEXT("TaskPackLevels", "Packing Levels")));
SlowTask.MakeDialog();
auto UpdateProgress = [&SlowTask]()
{
if (SlowTask.CompletedWork < SlowTask.TotalAmountOfWork)
{
SlowTask.EnterProgressFrame(1, FText::Format(LOCTEXT("TaskPackLevelProgress", "Packing Level {0} of {1}"), FText::AsNumber(SlowTask.CompletedWork), FText::AsNumber(SlowTask.TotalAmountOfWork)));
}
};
TSharedPtr<FPackedLevelActorBuilder> Builder = FPackedLevelActorBuilder::CreateDefaultBuilder();
const bool bCheckoutAndSave = false;
for (UBlueprint* Blueprint : BlueprintsToUpdate)
{
Builder->UpdateBlueprint(Blueprint, bCheckoutAndSave);
UpdateProgress();
}
for (APackedLevelActor* PackedLevelActor : PackedLevelActorsToUpdate)
{
PackedLevelActor->UpdateLevelInstanceFromWorldAsset();
UpdateProgress();
}
}
bool FPackedLevelActorUtils::CreateOrUpdateBlueprint(ILevelInstanceInterface* InLevelInstance, TSoftObjectPtr<UBlueprint> InBlueprintAsset, bool bCheckoutAndSave, bool bPromptForSave)
{
return FPackedLevelActorBuilder::CreateDefaultBuilder()->CreateOrUpdateBlueprint(InLevelInstance, InBlueprintAsset, bCheckoutAndSave, bPromptForSave);
}
bool FPackedLevelActorUtils::CreateOrUpdateBlueprint(TSoftObjectPtr<UWorld> InWorldAsset, TSoftObjectPtr<UBlueprint> InBlueprintAsset, bool bCheckoutAndSave, bool bPromptForSave)
{
return FPackedLevelActorBuilder::CreateDefaultBuilder()->CreateOrUpdateBlueprint(InWorldAsset, InBlueprintAsset, bCheckoutAndSave, bPromptForSave);
}
void FPackedLevelActorUtils::UpdateBlueprint(UBlueprint* InBlueprint, bool bCheckoutAndSave)
{
FPackedLevelActorBuilder::CreateDefaultBuilder()->UpdateBlueprint(InBlueprint, bCheckoutAndSave);
}
#undef LOCTEXT_NAMESPACE
#endif