2020-08-11 01:36:57 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
WorldPartitionConvertCommandlet . cpp : Commandlet used to convert levels to partition
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "Commandlets/WorldPartitionConvertCommandlet.h"
2022-03-07 07:39:57 -05:00
# include "Algo/ForEach.h"
2022-03-15 13:52:28 -04:00
# include "AssetToolsModule.h"
2020-08-11 01:36:57 -04:00
# include "HAL/PlatformFileManager.h"
# include "Misc/Paths.h"
# include "Misc/ConfigCacheIni.h"
# include "Engine/Level.h"
# include "Engine/World.h"
# include "Engine/LevelBounds.h"
# include "Engine/LevelScriptActor.h"
# include "Engine/LODActor.h"
# include "Engine/LevelStreaming.h"
# include "Engine/MapBuildDataRegistry.h"
2021-01-26 14:20:22 -04:00
# include "Engine/Public/ActorReferencesUtils.h"
2020-08-11 01:36:57 -04:00
# include "WorldPartition/WorldPartition.h"
# include "WorldPartition/WorldPartitionSubsystem.h"
# include "WorldPartition/HLOD/HLODActor.h"
2020-11-02 11:27:09 -04:00
# include "WorldPartition/WorldPartitionMiniMap.h"
# include "WorldPartition/WorldPartitionMiniMapHelper.h"
2021-01-22 16:09:31 -04:00
# include "LevelInstance/LevelInstanceActor.h"
2022-03-15 13:52:28 -04:00
# include "DataLayer/DataLayerFactory.h"
2020-08-11 01:36:57 -04:00
# include "GameFramework/WorldSettings.h"
# include "UObject/UObjectHash.h"
# include "PackageHelperFunctions.h"
# include "UObject/MetaData.h"
2021-11-23 20:56:06 -05:00
# include "UObject/SavePackage.h"
2020-08-11 01:36:57 -04:00
# include "Editor.h"
2021-01-11 17:21:37 -04:00
# include "HLOD/HLODEngineSubsystem.h"
2020-08-11 01:36:57 -04:00
# include "HierarchicalLOD.h"
# include "IHierarchicalLODUtilities.h"
# include "HierarchicalLODUtilitiesModule.h"
# include "InstancedFoliageActor.h"
# include "Engine/LevelScriptBlueprint.h"
# include "Editor/GroupActor.h"
# include "EdGraph/EdGraph.h"
# include "ProfilingDebugging/ScopedTimers.h"
2022-05-02 18:06:48 -04:00
# include "AssetRegistry/AssetRegistryModule.h"
2022-01-18 15:38:27 -05:00
# include "FoliageEditUtility.h"
2020-08-11 01:36:57 -04:00
# include "FoliageHelper.h"
2020-08-26 09:26:08 -04:00
# include "Engine/WorldComposition.h"
2020-09-14 08:43:13 -04:00
# include "ActorPartition/ActorPartitionSubsystem.h"
# include "InstancedFoliage.h"
2020-10-16 10:14:23 -04:00
# include "Landscape.h"
# include "LandscapeStreamingProxy.h"
# include "LandscapeInfo.h"
# include "LandscapeConfigHelper.h"
2020-11-23 08:28:12 -04:00
# include "ILandscapeSplineInterface.h"
# include "LandscapeSplineActor.h"
# include "LandscapeSplinesComponent.h"
# include "LandscapeSplineControlPoint.h"
2020-10-20 06:35:49 -04:00
# include "LandscapeGizmoActor.h"
2022-03-15 13:52:28 -04:00
# include "WorldPartition/DataLayer/DataLayerInstanceWithAsset.h"
2020-11-02 12:20:44 -04:00
# include "WorldPartition/DataLayer/WorldDataLayers.h"
2022-01-07 10:01:19 -05:00
# include "ActorFolder.h"
2020-08-11 01:36:57 -04:00
DEFINE_LOG_CATEGORY ( LogWorldPartitionConvertCommandlet ) ;
class FArchiveGatherPrivateImports : public FArchiveUObject
{
AActor * Root ;
UPackage * RootPackage ;
UObject * CurrentObject ;
TMap < UObject * , UObject * > & PrivateRefsMap ;
TSet < FString > & ActorsReferencesToActors ;
void HandleObjectReference ( UObject * Obj )
{
if ( ! Obj - > HasAnyMarks ( OBJECTMARK_TagImp ) )
{
UObject * OldCurrentObject = CurrentObject ;
CurrentObject = Obj ;
Obj - > Mark ( OBJECTMARK_TagImp ) ;
Obj - > Serialize ( * this ) ;
CurrentObject = OldCurrentObject ;
}
}
public :
FArchiveGatherPrivateImports ( AActor * InRoot , TMap < UObject * , UObject * > & InPrivateRefsMap , TSet < FString > & InActorsReferencesToActors )
: Root ( InRoot )
, RootPackage ( InRoot - > GetPackage ( ) )
, CurrentObject ( nullptr )
, PrivateRefsMap ( InPrivateRefsMap )
, ActorsReferencesToActors ( InActorsReferencesToActors )
{
SetIsSaving ( true ) ;
SetIsPersistent ( true ) ;
ArIsObjectReferenceCollector = true ;
ArShouldSkipBulkData = true ;
UnMarkAllObjects ( ) ;
}
~ FArchiveGatherPrivateImports ( )
{
UnMarkAllObjects ( ) ;
}
virtual FArchive & operator < < ( UObject * & Obj ) override
{
if ( Obj )
{
if ( Obj - > IsIn ( Root ) | | ( CurrentObject & & Obj - > IsIn ( CurrentObject ) ) )
{
HandleObjectReference ( Obj ) ;
}
else if ( Obj - > IsInPackage ( RootPackage ) & & ! Obj - > HasAnyFlags ( RF_Standalone ) )
{
if ( ! Obj - > GetTypedOuter < AActor > ( ) )
{
UObject * * OriginalRoot = PrivateRefsMap . Find ( Obj ) ;
if ( OriginalRoot & & ( * OriginalRoot ! = Root ) )
{
SET_WARN_COLOR ( COLOR_RED ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Duplicate reference %s.%s(%s) (first referenced by %s) " ) , * Root - > GetName ( ) , * Obj - > GetName ( ) , * Obj - > GetClass ( ) - > GetName ( ) , * ( * OriginalRoot ) - > GetName ( ) ) ;
CLEAR_WARN_COLOR ( ) ;
}
else if ( ! OriginalRoot )
{
// Actor references will be extracted by the caller, ignore them
if ( Obj - > IsA < AActor > ( ) & & ! Obj - > HasAnyFlags ( RF_ClassDefaultObject | RF_ArchetypeObject ) & & Obj - > GetTypedOuter < ULevel > ( ) )
{
AActor * ActorRef = ( AActor * ) Obj ;
ActorsReferencesToActors . Add (
FString : : Printf (
TEXT ( " %s, %s, %s, %s, %.2f " ) ,
* RootPackage - > GetName ( ) ,
CurrentObject ? * CurrentObject - > GetName ( ) : * Root - > GetName ( ) ,
CurrentObject ? * Root - > GetName ( ) : TEXT ( " null " ) ,
* Obj - > GetName ( ) ,
( ActorRef - > GetActorLocation ( ) - Root - > GetActorLocation ( ) ) . Size ( ) )
) ;
}
else if ( ! Obj - > IsA < ULevel > ( ) )
{
if ( ! CurrentObject | | ! Obj - > IsIn ( CurrentObject ) )
{
PrivateRefsMap . Add ( Obj , Root ) ;
SET_WARN_COLOR ( COLOR_WHITE ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Warning , TEXT ( " Encountered reference %s.%s(%s) " ) , * Root - > GetName ( ) , * Obj - > GetName ( ) , * Obj - > GetClass ( ) - > GetName ( ) ) ;
CLEAR_WARN_COLOR ( ) ;
}
HandleObjectReference ( Obj ) ;
}
}
}
}
}
return * this ;
}
} ;
UWorldPartitionConvertCommandlet : : UWorldPartitionConvertCommandlet ( const FObjectInitializer & ObjectInitializer )
2020-10-20 13:56:19 -04:00
: Super ( ObjectInitializer )
, bConversionSuffix ( false )
, ConversionSuffix ( TEXT ( " _WP " ) )
2021-01-26 14:20:22 -04:00
, bConvertActorsNotReferencedByLevelScript ( true )
2020-10-20 13:56:19 -04:00
, WorldOrigin ( FVector : : ZeroVector )
2022-01-13 12:14:52 -05:00
, WorldExtent ( WORLDPARTITION_MAX * 0.5 )
2020-10-20 13:56:19 -04:00
, LandscapeGridSize ( 4 )
2022-03-15 13:52:28 -04:00
, DataLayerAssetFolder ( TEXT ( " Game/DataLayers/ " ) )
, DataLayerFactory ( NewObject < UDataLayerFactory > ( ) )
2020-08-25 07:27:44 -04:00
{ }
2020-08-11 01:36:57 -04:00
2020-09-16 09:33:56 -04:00
UWorld * UWorldPartitionConvertCommandlet : : LoadWorld ( const FString & LevelToLoad )
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : LoadWorld ) ;
2020-08-11 01:36:57 -04:00
SET_WARN_COLOR ( COLOR_WHITE ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Loading level %s. " ) , * LevelToLoad ) ;
2020-08-11 01:36:57 -04:00
CLEAR_WARN_COLOR ( ) ;
UPackage * MapPackage = LoadPackage ( nullptr , * LevelToLoad , LOAD_None ) ;
if ( ! MapPackage )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Error loading %s. " ) , * LevelToLoad ) ;
return nullptr ;
}
2020-09-16 09:33:56 -04:00
return UWorld : : FindWorldInPackage ( MapPackage ) ;
}
ULevel * UWorldPartitionConvertCommandlet : : InitWorld ( UWorld * World )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : InitWorld ) ;
2020-09-16 09:33:56 -04:00
SET_WARN_COLOR ( COLOR_WHITE ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Initializing level %s. " ) , * World - > GetName ( ) ) ;
2020-09-16 09:33:56 -04:00
CLEAR_WARN_COLOR ( ) ;
// Setup the world.
World - > WorldType = EWorldType : : Editor ;
World - > AddToRoot ( ) ;
if ( ! World - > bIsWorldInitialized )
2020-08-11 01:36:57 -04:00
{
2020-09-16 09:33:56 -04:00
UWorld : : InitializationValues IVS ;
IVS . RequiresHitProxies ( false ) ;
IVS . ShouldSimulatePhysics ( false ) ;
IVS . EnableTraceCollision ( false ) ;
IVS . CreateNavigation ( false ) ;
IVS . CreateAISystem ( false ) ;
IVS . AllowAudioPlayback ( false ) ;
IVS . CreatePhysicsScene ( true ) ;
2020-08-11 01:36:57 -04:00
2020-09-16 09:33:56 -04:00
World - > InitWorld ( IVS ) ;
World - > PersistentLevel - > UpdateModelComponents ( ) ;
World - > UpdateWorldComponents ( true , false ) ;
2020-08-11 01:36:57 -04:00
2020-09-16 09:33:56 -04:00
World - > FlushLevelStreaming ( EFlushLevelStreamingType : : Full ) ;
2020-08-11 01:36:57 -04:00
}
2020-09-16 09:33:56 -04:00
return World - > PersistentLevel ;
2020-08-11 01:36:57 -04:00
}
2022-02-25 19:31:01 -05:00
UWorldPartition * UWorldPartitionConvertCommandlet : : CreateWorldPartition ( AWorldSettings * MainWorldSettings )
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : CreateWorldPartition ) ;
2021-11-07 23:43:01 -05:00
UWorldPartition * WorldPartition = UWorldPartition : : CreateOrRepairWorldPartition ( MainWorldSettings , EditorHashClass , RuntimeHashClass ) ;
2022-02-25 19:31:01 -05:00
if ( bDisableStreaming )
{
WorldPartition - > bEnableStreaming = false ;
WorldPartition - > bStreamingWasEnabled = false ;
}
2021-03-09 12:01:17 -04:00
2020-08-11 01:36:57 -04:00
// Read the conversion config file
if ( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * LevelConfigFilename ) )
{
WorldPartition - > EditorHash - > LoadConfig ( * EditorHashClass , * LevelConfigFilename ) ;
WorldPartition - > RuntimeHash - > LoadConfig ( * RuntimeHashClass , * LevelConfigFilename ) ;
WorldPartition - > DefaultHLODLayer = HLODLayers . FindRef ( DefaultHLODLayerName ) ;
}
2021-03-12 08:07:58 -04:00
2022-02-25 19:31:01 -05:00
if ( ( WorldPartition - > DefaultHLODLayer = = UHLODLayer : : GetEngineDefaultHLODLayersSetup ( ) ) & & ! bDisableStreaming )
{
WorldPartition - > DefaultHLODLayer = UHLODLayer : : DuplicateHLODLayersSetup ( UHLODLayer : : GetEngineDefaultHLODLayersSetup ( ) , WorldPartition - > GetPackage ( ) - > GetName ( ) , WorldPartition - > GetWorld ( ) - > GetName ( ) ) ;
UHLODLayer * CurrentHLODLayer = WorldPartition - > DefaultHLODLayer ;
while ( CurrentHLODLayer )
{
PackagesToSave . Add ( CurrentHLODLayer - > GetPackage ( ) ) ;
CurrentHLODLayer = Cast < UHLODLayer > ( CurrentHLODLayer - > GetParentLayer ( ) . Get ( ) ) ;
}
}
2021-03-09 12:01:17 -04:00
2020-08-11 01:36:57 -04:00
return WorldPartition ;
}
2021-12-06 16:16:42 -05:00
void UWorldPartitionConvertCommandlet : : GatherAndPrepareSubLevelsToConvert ( ULevel * Level , TArray < ULevel * > & SubLevels )
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : GatherAndPrepareSubLevelsToConvert ) ;
2020-08-25 07:27:44 -04:00
UWorld * World = Level - > GetTypedOuter < UWorld > ( ) ;
2020-08-11 01:36:57 -04:00
// Set all streaming levels to be loaded/visible for next Flush
2021-02-17 14:12:50 -04:00
TArray < ULevelStreaming * > StreamingLevels ;
2020-08-11 01:36:57 -04:00
for ( ULevelStreaming * StreamingLevel : World - > GetStreamingLevels ( ) )
{
2021-02-17 14:12:50 -04:00
if ( ShouldConvertStreamingLevel ( StreamingLevel ) )
{
StreamingLevels . Add ( StreamingLevel ) ;
StreamingLevel - > SetShouldBeLoaded ( true ) ;
StreamingLevel - > SetShouldBeVisible ( true ) ;
StreamingLevel - > SetShouldBeVisibleInEditor ( true ) ;
}
else
{
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Skipping conversion of streaming Level %s " ) , * StreamingLevel - > GetWorldAssetPackageName ( ) ) ;
2021-02-17 14:12:50 -04:00
}
2020-08-11 01:36:57 -04:00
}
World - > FlushLevelStreaming ( EFlushLevelStreamingType : : Full ) ;
2021-02-17 14:12:50 -04:00
for ( ULevelStreaming * StreamingLevel : StreamingLevels )
2020-08-11 01:36:57 -04:00
{
2021-12-06 16:16:42 -05:00
if ( PrepareStreamingLevelForConversion ( StreamingLevel ) )
2020-08-11 01:36:57 -04:00
{
2020-08-25 07:27:44 -04:00
ULevel * SubLevel = StreamingLevel - > GetLoadedLevel ( ) ;
check ( SubLevel ) ;
SubLevels . Add ( SubLevel ) ;
// Recursively obtain sub levels to convert
2021-12-06 16:16:42 -05:00
GatherAndPrepareSubLevelsToConvert ( SubLevel , SubLevels ) ;
2020-08-11 01:36:57 -04:00
}
2020-08-25 07:27:44 -04:00
}
}
2021-12-06 16:16:42 -05:00
bool UWorldPartitionConvertCommandlet : : PrepareStreamingLevelForConversion ( ULevelStreaming * StreamingLevel )
2020-08-25 07:27:44 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : PrepareStreamingLevelForConversion ) ;
2020-08-26 09:26:08 -04:00
ULevel * SubLevel = StreamingLevel - > GetLoadedLevel ( ) ;
check ( SubLevel ) ;
2020-08-25 07:27:44 -04:00
2021-12-06 16:16:42 -05:00
if ( bOnlyMergeSubLevels | | StreamingLevel - > ShouldBeAlwaysLoaded ( ) | | StreamingLevel - > bDisableDistanceStreaming )
2020-08-25 07:27:44 -04:00
{
2020-09-02 08:33:07 -04:00
FString WorldPath = SubLevel - > GetPackage ( ) - > GetName ( ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Converting %s streaming level %s " ) , StreamingLevel - > bDisableDistanceStreaming ? TEXT ( " non distance-based " ) : TEXT ( " always loaded " ) , * StreamingLevel - > GetWorldAssetPackageName ( ) ) ;
2020-09-02 08:33:07 -04:00
2021-12-07 11:50:24 -05:00
for ( AActor * Actor : SubLevel - > Actors )
{
2021-12-13 13:36:10 -05:00
if ( Actor & & Actor - > CanChangeIsSpatiallyLoadedFlag ( ) )
2020-08-11 01:36:57 -04:00
{
2021-12-07 11:50:24 -05:00
Actor - > SetIsSpatiallyLoaded ( false ) ;
2020-08-11 01:36:57 -04:00
}
}
}
2021-11-26 09:31:40 -05:00
2020-08-25 07:27:44 -04:00
return true ;
2020-08-11 01:36:57 -04:00
}
bool UWorldPartitionConvertCommandlet : : GetAdditionalLevelsToConvert ( ULevel * Level , TArray < ULevel * > & SubLevels )
{
return true ;
}
bool UWorldPartitionConvertCommandlet : : ShouldDeleteActor ( AActor * Actor , bool bMainLevel ) const
{
2020-12-03 11:38:17 -04:00
// We need to migrate transient actors as Fortnite uses a transient actor(AFortTimeOfDayManager) to handle lighting in maps and is required during the generation of MiniMap.
if ( Actor - > IsA < ALODActor > ( ) | |
2020-10-20 06:35:49 -04:00
Actor - > IsA < ALevelBounds > ( ) | |
Actor - > IsA < ALandscapeGizmoActor > ( ) )
2020-08-11 01:36:57 -04:00
{
return true ;
}
if ( ! bMainLevel )
{
// Only delete these actors if they aren't in the main level
if ( Actor - > IsA < ALevelScriptActor > ( ) | |
Actor - > IsA < AWorldSettings > ( ) | |
Actor = = ( AActor * ) Actor - > GetLevel ( ) - > GetDefaultBrush ( ) )
{
return true ;
}
}
return false ;
}
void UWorldPartitionConvertCommandlet : : PerformAdditionalWorldCleanup ( UWorld * World ) const
{
}
void UWorldPartitionConvertCommandlet : : OutputConversionReport ( ) const
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Display , TEXT ( " WorldPartitionConvertCommandlet report: " ) ) ;
auto OutputReport = [ ] ( const TCHAR * Msg , const TSet < FString > & Values )
{
if ( Values . Num ( ) ! = 0 )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Display , TEXT ( " - Found %s: " ) , Msg ) ;
TArray < FString > Array = Values . Array ( ) ;
Array . Sort ( ) ;
for ( const FString & Name : Array )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Display , TEXT ( " * %s " ) , * Name ) ;
}
UE_LOG ( LogWorldPartitionConvertCommandlet , Display , TEXT ( " " ) ) ;
}
} ;
OutputReport ( TEXT ( " sublevels containing LevelScriptBPs " ) , MapsWithLevelScriptsBPs ) ;
OutputReport ( TEXT ( " sublevels containing MapBuildData " ) , MapsWithMapBuildData ) ;
OutputReport ( TEXT ( " actors with child actors " ) , ActorsWithChildActors ) ;
OutputReport ( TEXT ( " group actors " ) , GroupActors ) ;
OutputReport ( TEXT ( " actors in actor groups " ) , ActorsInGroupActors ) ;
OutputReport ( TEXT ( " actor referencing other actors " ) , ActorsReferencesToActors ) ;
}
bool LevelHasLevelScriptBlueprint ( ULevel * Level )
{
if ( ULevelScriptBlueprint * LevelScriptBP = Level - > GetLevelScriptBlueprint ( true ) )
{
TArray < UEdGraph * > AllGraphs ;
LevelScriptBP - > GetAllGraphs ( AllGraphs ) ;
for ( UEdGraph * CurrentGraph : AllGraphs )
{
for ( UEdGraphNode * Node : CurrentGraph - > Nodes )
{
if ( ! Node - > IsAutomaticallyPlacedGhostNode ( ) )
{
return true ;
}
}
}
}
return false ;
}
bool LevelHasMapBuildData ( ULevel * Level )
{
return Level - > MapBuildData ! = nullptr ;
}
void UWorldPartitionConvertCommandlet : : ChangeObjectOuter ( UObject * Object , UObject * NewOuter )
{
FString OldPath = FSoftObjectPath ( Object ) . ToString ( ) ;
Object - > Rename ( nullptr , NewOuter , REN_DontCreateRedirectors ) ;
FString NewPath = FSoftObjectPath ( Object ) . ToString ( ) ;
RemapSoftObjectPaths . Add ( OldPath , NewPath ) ;
}
void UWorldPartitionConvertCommandlet : : FixupSoftObjectPaths ( UPackage * OuterPackage )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : FixupSoftObjectPaths ) ;
2021-07-13 16:12:20 -04:00
UE_SCOPED_TIMER ( TEXT ( " FixupSoftObjectPaths " ) , LogWorldPartitionConvertCommandlet , Display ) ;
2020-08-11 01:36:57 -04:00
struct FSoftPathFixupSerializer : public FArchiveUObject
{
FSoftPathFixupSerializer ( TMap < FString , FString > & InRemapSoftObjectPaths )
: RemapSoftObjectPaths ( InRemapSoftObjectPaths )
{
this - > SetIsSaving ( true ) ;
}
FArchive & operator < < ( FSoftObjectPath & Value )
{
if ( Value . IsNull ( ) )
{
return * this ;
}
FString OriginalValue = Value . ToString ( ) ;
auto GetSourceString = [ this ] ( )
{
FString DebugStackString ;
for ( const FName & DebugData : DebugDataStack )
{
DebugStackString + = DebugData . ToString ( ) ;
DebugStackString + = TEXT ( " . " ) ;
}
DebugStackString . RemoveFromEnd ( TEXT ( " . " ) ) ;
return DebugStackString ;
} ;
if ( FString * RemappedValue = RemapSoftObjectPaths . Find ( OriginalValue ) )
{
Value . SetPath ( * RemappedValue ) ;
}
else if ( Value . GetSubPathString ( ) . StartsWith ( TEXT ( " PersistentLevel. " ) ) )
{
int32 DotPos = Value . GetSubPathString ( ) . Find ( TEXT ( " . " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart ) ;
if ( DotPos ! = INDEX_NONE )
{
RemappedValue = RemapSoftObjectPaths . Find ( Value . GetAssetPathName ( ) . ToString ( ) ) ;
if ( RemappedValue )
{
FString NewPath = * RemappedValue + ' : ' + Value . GetSubPathString ( ) ;
Value . SetPath ( NewPath ) ;
}
}
FString NewValue = Value . ToString ( ) ;
if ( NewValue = = OriginalValue )
{
Value . Reset ( ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Warning , TEXT ( " Error remapping SoftObjectPath %s " ) , * OriginalValue ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Warning , TEXT ( " Source: %s " ) , * GetSourceString ( ) ) ;
}
}
if ( ! Value . IsNull ( ) )
{
FString NewValue = Value . ToString ( ) ;
if ( NewValue ! = OriginalValue )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Verbose , TEXT ( " Remapped SoftObjectPath %s to %s " ) , * OriginalValue , * NewValue ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Verbose , TEXT ( " Source: %s " ) , * GetSourceString ( ) ) ;
}
}
return * this ;
}
private :
virtual void PushDebugDataString ( const FName & DebugData ) override
{
DebugDataStack . Add ( DebugData ) ;
}
virtual void PopDebugDataString ( ) override
{
DebugDataStack . Pop ( ) ;
}
TArray < FName > DebugDataStack ;
TMap < FString , FString > & RemapSoftObjectPaths ;
} ;
FSoftPathFixupSerializer FixupSerializer ( RemapSoftObjectPaths ) ;
ForEachObjectWithPackage ( OuterPackage , [ & ] ( UObject * Object )
{
2021-01-26 14:20:22 -04:00
if ( Object - > HasAllFlags ( RF_WasLoaded ) )
{
Object - > Serialize ( FixupSerializer ) ;
}
2020-08-11 01:36:57 -04:00
return true ;
2022-02-02 02:21:12 -05:00
} , true , RF_NoFlags , EInternalObjectFlags : : Garbage ) ;
2020-08-11 01:36:57 -04:00
}
bool UWorldPartitionConvertCommandlet : : DetachDependantLevelPackages ( ULevel * Level )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : DetachDependantLevelPackages ) ;
2020-08-11 01:36:57 -04:00
if ( Level - > MapBuildData & & ( Level - > MapBuildData - > GetPackage ( ) ! = Level - > GetPackage ( ) ) )
{
PackagesToDelete . Add ( Level - > MapBuildData - > GetPackage ( ) ) ;
Level - > MapBuildData = nullptr ;
}
// Try to delete matching HLOD package
FHierarchicalLODUtilitiesModule & Module = FModuleManager : : LoadModuleChecked < FHierarchicalLODUtilitiesModule > ( " HierarchicalLODUtilities " ) ;
IHierarchicalLODUtilities * Utilities = Module . GetUtilities ( ) ;
const int32 NumHLODLevels = Level - > GetWorldSettings ( ) - > GetNumHierarchicalLODLevels ( ) ;
for ( int32 HLODIndex = 0 ; HLODIndex < NumHLODLevels ; HLODIndex + + )
{
if ( UPackage * HLODPackage = Utilities - > RetrieveLevelHLODPackage ( Level , HLODIndex ) )
{
PackagesToDelete . Add ( HLODPackage ) ;
}
}
for ( AActor * Actor : Level - > Actors )
{
2021-09-06 12:23:53 -04:00
if ( Actor & & IsValidChecked ( Actor ) & & Actor - > IsA < ALODActor > ( ) )
2020-08-11 01:36:57 -04:00
{
Level - > GetWorld ( ) - > DestroyActor ( Actor ) ;
}
}
Level - > GetWorldSettings ( ) - > ResetHierarchicalLODSetup ( ) ;
return true ;
}
bool UWorldPartitionConvertCommandlet : : RenameWorldPackageWithSuffix ( UWorld * World )
{
bool bRenamedSuccess = false ;
UPackage * Package = World - > GetPackage ( ) ;
FString OldWorldName = World - > GetName ( ) ;
FString NewWorldName = OldWorldName + ConversionSuffix ;
bRenamedSuccess = World - > Rename ( * NewWorldName , nullptr , REN_NonTransactional | REN_DontCreateRedirectors | REN_ForceNoResetLoaders ) ;
if ( ! bRenamedSuccess )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Unable to rename world to %s " ) , * NewWorldName ) ;
return false ;
}
FString OldPackageName = Package - > GetName ( ) ;
FString NewPackageName = OldPackageName + ConversionSuffix ;
2020-11-25 22:11:10 -04:00
FString NewPackageResourceName = Package - > GetLoadedPath ( ) . GetPackageName ( ) . Replace ( * OldPackageName , * NewPackageName ) ;
2020-08-11 01:36:57 -04:00
bRenamedSuccess = Package - > Rename ( * NewPackageName , nullptr , REN_NonTransactional | REN_DontCreateRedirectors | REN_ForceNoResetLoaders ) ;
if ( ! bRenamedSuccess )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Unable to rename package to %s " ) , * NewPackageName ) ;
return false ;
}
2020-11-25 22:11:10 -04:00
Package - > SetLoadedPath ( FPackagePath : : FromPackageNameChecked ( NewPackageResourceName ) ) ;
2020-08-11 01:36:57 -04:00
return true ;
}
UHLODLayer * UWorldPartitionConvertCommandlet : : CreateHLODLayerFromINI ( const FString & InHLODLayerName )
{
const FString PackagePath = HLODLayerAssetsPath / InHLODLayerName ;
2020-09-24 00:43:27 -04:00
UPackage * AssetPackage = CreatePackage ( * PackagePath ) ;
2020-08-11 01:36:57 -04:00
if ( ! AssetPackage )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Package \" %s \" creation failed " ) , * PackagePath ) ;
return nullptr ;
}
// Make sure we overwrite any existing HLODLayer asset package
AssetPackage - > MarkAsFullyLoaded ( ) ;
UHLODLayer * HLODLayer = NewObject < UHLODLayer > ( AssetPackage , * InHLODLayerName , RF_Public | RF_Standalone ) ;
if ( ! HLODLayer )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " HLODLayer \" %s \" creation failed " ) , * InHLODLayerName ) ;
return nullptr ;
}
HLODLayer - > LoadConfig ( nullptr , * LevelConfigFilename ) ;
// Notify the asset registry
FAssetRegistryModule : : AssetCreated ( HLODLayer ) ;
// Mark the package dirty...
HLODLayer - > Modify ( ) ;
PackagesToSave . Add ( HLODLayer - > GetOutermost ( ) ) ;
return HLODLayer ;
}
2021-01-11 17:21:37 -04:00
void UWorldPartitionConvertCommandlet : : SetupHLOD ( )
{
// No need to spawn HLOD actors during the conversion
GEngine - > GetEngineSubsystem < UHLODEngineSubsystem > ( ) - > DisableHLODSpawningOnLoad ( true ) ;
SetupHLODLayerAssets ( ) ;
}
2020-08-11 01:36:57 -04:00
void UWorldPartitionConvertCommandlet : : SetupHLODLayerAssets ( )
{
TArray < FString > HLODLayerSectionsNames ;
if ( GConfig - > GetPerObjectConfigSections ( LevelConfigFilename , TEXT ( " HLODLayer " ) , HLODLayerSectionsNames ) )
{
for ( const FString & HLODLayerSectionName : HLODLayerSectionsNames )
{
FString HLODLayerName ( * HLODLayerSectionName . Left ( HLODLayerSectionName . Find ( TEXT ( " " ) ) ) ) ;
UHLODLayer * HLODLayer = CreateHLODLayerFromINI ( HLODLayerName ) ;
HLODLayers . Add ( HLODLayerName , HLODLayer ) ;
}
}
// Assign HLOD layers to the classes listed in the level config
for ( const FHLODLayerActorMapping & Entry : HLODLayersForActorClasses )
{
UHLODLayer * HLODLayer = HLODLayers . FindRef ( Entry . HLODLayer ) ;
if ( ! ensure ( HLODLayer ) )
{
continue ;
}
// Load the BP class & assign
if ( UClass * LoadedObject = Entry . ActorClass . LoadSynchronous ( ) )
{
if ( AActor * CDO = CastChecked < AActor > ( LoadedObject - > GetDefaultObject ( ) ) )
{
if ( CDO - > GetHLODLayer ( ) ! = HLODLayer )
{
CDO - > SetHLODLayer ( HLODLayer ) ;
CDO - > MarkPackageDirty ( ) ;
PackagesToSave . Add ( CDO - > GetPackage ( ) ) ;
}
}
}
}
}
2020-10-15 06:31:42 -04:00
void UWorldPartitionConvertCommandlet : : SetActorGuid ( AActor * Actor , const FGuid & NewGuid )
{
FSetActorGuid SetActorGuid ( Actor , NewGuid ) ;
}
2020-08-26 09:26:08 -04:00
void UWorldPartitionConvertCommandlet : : OnWorldLoaded ( UWorld * World )
{
if ( UWorldComposition * WorldComposition = World - > WorldComposition )
{
// Add tiles streaming levels to world
World - > SetStreamingLevels ( WorldComposition - > TilesStreaming ) ;
// Make sure to force bDisableDistanceStreaming on streaming levels of World Composition non distance dependent tiles (for the rest of the process to handle streaming level as always loaded)
UWorldComposition : : FTilesList & Tiles = WorldComposition - > GetTilesList ( ) ;
for ( int32 TileIdx = 0 ; TileIdx < Tiles . Num ( ) ; TileIdx + + )
{
FWorldCompositionTile & Tile = Tiles [ TileIdx ] ;
ULevelStreaming * StreamingLevel = WorldComposition - > TilesStreaming [ TileIdx ] ;
if ( StreamingLevel & & ! WorldComposition - > IsDistanceDependentLevel ( Tile . PackageName ) )
{
StreamingLevel - > bDisableDistanceStreaming = true ;
}
}
}
}
2020-08-11 01:36:57 -04:00
int32 UWorldPartitionConvertCommandlet : : Main ( const FString & Params )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UWorldPartitionConvertCommandlet : : Main ) ;
2021-07-13 16:12:20 -04:00
UE_SCOPED_TIMER ( TEXT ( " Conversion " ) , LogWorldPartitionConvertCommandlet , Display ) ;
2020-08-11 01:36:57 -04:00
TArray < FString > Tokens , Switches ;
2022-01-18 15:38:27 -05:00
TMap < FString , FString > Arguments ;
ParseCommandLine ( * Params , Tokens , Switches , Arguments ) ;
2020-08-11 01:36:57 -04:00
2022-03-07 07:39:57 -05:00
if ( ! Tokens . Num ( ) )
2020-08-11 01:36:57 -04:00
{
2022-03-07 07:39:57 -05:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " missing map name " ) ) ;
return 1 ;
}
else if ( Tokens . Num ( ) > 1 )
{
FString BadParams ;
Algo : : ForEach ( Tokens , [ & BadParams ] ( const FString & Token ) { BadParams + = Token ; BadParams + = TEXT ( " " ) ; } ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " extra parameters %s " ) , * BadParams ) ;
2020-08-11 01:36:57 -04:00
return 1 ;
}
2020-11-02 11:27:09 -04:00
// This will convert incomplete package name to a fully qualified path, avoiding calling it several times (takes ~50s)
2020-08-11 01:36:57 -04:00
if ( ! FPackageName : : SearchForPackageOnDisk ( Tokens [ 0 ] , & Tokens [ 0 ] ) )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Unknown level '%s' " ) , * Tokens [ 0 ] ) ;
return 1 ;
}
2021-12-06 16:16:42 -05:00
bOnlyMergeSubLevels = Switches . Contains ( TEXT ( " OnlyMergeSubLevels " ) ) ;
2020-08-11 01:36:57 -04:00
bDeleteSourceLevels = Switches . Contains ( TEXT ( " DeleteSourceLevels " ) ) ;
2020-08-25 07:27:44 -04:00
bGenerateIni = Switches . Contains ( TEXT ( " GenerateIni " ) ) ;
bReportOnly = bGenerateIni | | Switches . Contains ( TEXT ( " ReportOnly " ) ) ;
2020-08-11 01:36:57 -04:00
bVerbose = Switches . Contains ( TEXT ( " Verbose " ) ) ;
2022-02-25 19:31:01 -05:00
bDisableStreaming = Switches . Contains ( TEXT ( " DisableStreaming " ) ) ;
2021-12-06 16:16:42 -05:00
ConversionSuffix = GetConversionSuffix ( bOnlyMergeSubLevels ) ;
2022-01-18 15:38:27 -05:00
FString * FoliageTypePathValue = Arguments . Find ( TEXT ( " FoliageTypePath " ) ) ;
if ( FoliageTypePathValue ! = nullptr )
{
FoliageTypePath = * FoliageTypePathValue ;
}
2020-11-30 12:57:53 -04:00
if ( ! Switches . Contains ( TEXT ( " AllowCommandletRendering " ) ) )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " The option \" -AllowCommandletRendering \" is required. " ) ) ;
return 1 ;
}
2020-08-25 07:27:44 -04:00
2022-03-15 13:52:28 -04:00
if ( FString * DataLayerAssetFolderValue = Arguments . Find ( TEXT ( " DataLayerAssetFolder " ) ) )
{
DataLayerAssetFolder = * DataLayerAssetFolderValue ;
}
2020-08-11 01:36:57 -04:00
ReadAdditionalTokensAndSwitches ( Tokens , Switches ) ;
if ( bVerbose )
{
LogWorldPartitionConvertCommandlet . SetVerbosity ( ELogVerbosity : : Verbose ) ;
}
2020-08-25 07:27:44 -04:00
bConversionSuffix = Switches . Contains ( TEXT ( " ConversionSuffix " ) ) ;
2020-08-11 01:36:57 -04:00
// Load configuration file
FString LevelLongPackageName ;
if ( FPackageName : : SearchForPackageOnDisk ( Tokens [ 0 ] , nullptr , & LevelLongPackageName ) )
{
LevelConfigFilename = FPaths : : ChangeExtension ( LevelLongPackageName , TEXT ( " ini " ) ) ;
if ( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * LevelConfigFilename ) )
{
LoadConfig ( GetClass ( ) , * LevelConfigFilename ) ;
}
else
{
2022-05-22 10:30:02 -04:00
EditorHashClass = FindObject < UClass > ( nullptr , TEXT ( " /Script/Engine.WorldPartitionEditorSpatialHash " ) ) ;
RuntimeHashClass = FindObject < UClass > ( nullptr , TEXT ( " /Script/Engine.WorldPartitionRuntimeSpatialHash " ) ) ;
2020-08-11 01:36:57 -04:00
}
}
if ( ! EditorHashClass )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Missing or invalid editor hash class " ) ) ;
return 1 ;
}
if ( ! RuntimeHashClass )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Missing or invalid runtime hash class " ) ) ;
return 1 ;
}
2021-01-11 17:21:37 -04:00
SetupHLOD ( ) ;
2020-08-11 01:36:57 -04:00
2020-08-25 07:27:44 -04:00
// Delete existing result from running the commandlet, even if not using the suffix mode to cleanup previous conversion
if ( ! bReportOnly )
2020-08-11 01:36:57 -04:00
{
2021-07-13 16:12:20 -04:00
UE_SCOPED_TIMER ( TEXT ( " Deleting existing conversion results " ) , LogWorldPartitionConvertCommandlet , Display ) ;
2020-08-11 01:36:57 -04:00
2020-08-24 10:14:03 -04:00
FString OldLevelName = Tokens [ 0 ] + ConversionSuffix ;
2022-01-07 10:01:19 -05:00
TArray < FString > ExternalObjectsPaths = ULevel : : GetExternalObjectsPaths ( OldLevelName ) ;
for ( const FString & ExternalObjectsPath : ExternalObjectsPaths )
2020-09-16 12:09:36 -04:00
{
2022-01-07 10:01:19 -05:00
FString ExternalObjectsFilePath = FPackageName : : LongPackageNameToFilename ( ExternalObjectsPath ) ;
if ( IFileManager : : Get ( ) . DirectoryExists ( * ExternalObjectsFilePath ) )
2020-09-16 12:09:36 -04:00
{
2022-01-07 10:01:19 -05:00
bool bResult = IFileManager : : Get ( ) . IterateDirectoryRecursively ( * ExternalObjectsFilePath , [ this ] ( const TCHAR * FilenameOrDirectory , bool bIsDirectory )
2020-09-16 12:09:36 -04:00
{
2022-01-07 10:01:19 -05:00
if ( ! bIsDirectory )
2020-09-22 10:32:44 -04:00
{
2022-01-07 10:01:19 -05:00
FString Filename ( FilenameOrDirectory ) ;
if ( Filename . EndsWith ( FPackageName : : GetAssetPackageExtension ( ) ) )
{
return PackageHelper . Delete ( Filename ) ;
}
2020-09-22 10:32:44 -04:00
}
2022-01-07 10:01:19 -05:00
return true ;
} ) ;
2020-09-16 12:09:36 -04:00
2022-01-07 10:01:19 -05:00
if ( ! bResult )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Failed to delete external package(s) " ) ) ;
return 1 ;
}
2020-09-22 10:32:44 -04:00
}
2020-08-11 01:36:57 -04:00
}
2020-08-25 07:27:44 -04:00
if ( FPackageName : : SearchForPackageOnDisk ( OldLevelName , & OldLevelName ) )
{
2020-09-11 08:14:37 -04:00
if ( ! PackageHelper . Delete ( OldLevelName ) )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Failed to delete previously converted level '%s' " ) , * Tokens [ 0 ] ) ;
return 1 ;
}
2020-08-25 07:27:44 -04:00
}
2020-08-11 01:36:57 -04:00
}
2020-09-16 09:33:56 -04:00
// Load world
UWorld * MainWorld = LoadWorld ( Tokens [ 0 ] ) ;
if ( ! MainWorld )
2020-08-11 01:36:57 -04:00
{
2020-09-16 09:33:56 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Unknown world '%s' " ) , * Tokens [ 0 ] ) ;
2020-08-11 01:36:57 -04:00
return 1 ;
}
2020-12-03 08:54:23 -04:00
// Make sure the world isn't already partitioned
2020-09-16 09:33:56 -04:00
AWorldSettings * MainWorldSettings = MainWorld - > GetWorldSettings ( ) ;
2021-09-02 08:09:40 -04:00
if ( MainWorldSettings - > IsPartitionedWorld ( ) )
2020-08-11 01:36:57 -04:00
{
2022-03-28 16:24:52 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Level '%s' is already partitioned " ) , * Tokens [ 0 ] ) ;
2020-08-11 01:36:57 -04:00
return 1 ;
}
2021-12-06 16:16:42 -05:00
// Setup the world partition object, do not create world partition object if only merging sublevels
UWorldPartition * WorldPartition = bOnlyMergeSubLevels ? nullptr : CreateWorldPartition ( MainWorldSettings ) ;
if ( ! bOnlyMergeSubLevels & & ! WorldPartition )
2020-08-26 09:26:08 -04:00
{
return 1 ;
}
2020-09-14 08:43:13 -04:00
2020-09-16 09:33:56 -04:00
// Initialize the world, create subsystems, etc.
ULevel * MainLevel = InitWorld ( MainWorld ) ;
if ( ! MainLevel )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Unknown level '%s' " ) , * Tokens [ 0 ] ) ;
return 1 ;
}
2021-05-12 11:26:54 -04:00
ON_SCOPE_EXIT
{
2021-05-27 10:31:55 -04:00
const bool bBroadcastWorldDestroyedEvent = false ;
MainWorld - > DestroyWorld ( bBroadcastWorldDestroyedEvent ) ;
2021-05-12 11:26:54 -04:00
} ;
2020-09-16 09:33:56 -04:00
UPackage * MainPackage = MainLevel - > GetPackage ( ) ;
2021-05-03 09:39:35 -04:00
AWorldDataLayers * MainWorldDataLayers = MainWorld - > GetWorldDataLayers ( ) ;
2021-12-06 16:16:42 -05:00
// DataLayers are only needed if converting to WorldPartition
check ( bOnlyMergeSubLevels | | MainWorldDataLayers ) ;
2020-09-16 09:33:56 -04:00
OnWorldLoaded ( MainWorld ) ;
2022-01-18 15:38:27 -05:00
auto PartitionFoliage = [ this , MainWorld ] ( AInstancedFoliageActor * IFA ) - > bool
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( PartitionFoliage ) ;
2021-11-07 23:43:01 -05:00
TMap < UFoliageType * , TArray < FFoliageInstance > > FoliageToAdd ;
int32 NumInstances = 0 ;
int32 NumInstancesProcessed = 0 ;
2022-01-18 15:38:27 -05:00
bool bAddFoliageSucceeded = IFA - > ForEachFoliageInfo ( [ IFA , & FoliageToAdd , & NumInstances , this ] ( UFoliageType * FoliageType , FFoliageInfo & FoliageInfo ) - > bool
2020-09-14 08:43:13 -04:00
{
2021-02-03 07:58:08 -04:00
if ( FoliageInfo . Type = = EFoliageImplType : : Actor )
2020-09-14 08:43:13 -04:00
{
2021-02-03 07:58:08 -04:00
// We don't support Actor Foliage in WP
FoliageInfo . ExcludeActors ( ) ;
2021-11-07 23:43:01 -05:00
return true ;
2020-09-14 08:43:13 -04:00
}
2021-11-07 23:43:01 -05:00
2022-01-18 15:38:27 -05:00
UFoliageType * FoliageTypeToAdd = FoliageType ;
if ( FoliageType - > GetTypedOuter < AInstancedFoliageActor > ( ) ! = nullptr )
{
UFoliageType * NewFoliageType = nullptr ;
if ( ! FoliageTypePath . IsEmpty ( ) )
{
UObject * FoliageSource = FoliageType - > GetSource ( ) ;
const FString BaseAssetName = ( FoliageSource ! = nullptr ) ? FoliageSource - > GetName ( ) : FoliageType - > GetName ( ) ;
FString PackageName = FoliageTypePath / BaseAssetName + TEXT ( " _FoliageType " ) ;
NewFoliageType = FFoliageEditUtility : : DuplicateFoliageTypeToNewPackage ( PackageName , FoliageType ) ;
}
if ( NewFoliageType = = nullptr )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error ,
TEXT ( " Level contains embedded FoliageType settings: please save the FoliageType setting assets, " )
TEXT ( " use the SaveFoliageTypeToContentFolder switch, " )
TEXT ( " specify FoliageTypePath in configuration file or the commandline. " ) ) ;
return false ;
}
FoliageTypeToAdd = NewFoliageType ;
PackagesToSave . Add ( NewFoliageType - > GetOutermost ( ) ) ;
}
2021-11-07 23:43:01 -05:00
if ( FoliageInfo . Instances . Num ( ) > 0 )
2021-02-03 07:58:08 -04:00
{
2022-01-18 15:38:27 -05:00
check ( FoliageTypeToAdd - > GetTypedOuter < AInstancedFoliageActor > ( ) = = nullptr ) ;
2021-11-07 23:43:01 -05:00
2022-01-18 15:38:27 -05:00
FoliageToAdd . FindOrAdd ( FoliageTypeToAdd ) . Append ( FoliageInfo . Instances ) ;
NumInstances + = FoliageInfo . Instances . Num ( ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Display , TEXT ( " FoliageType: %s Count: %d " ) , * FoliageTypeToAdd - > GetName ( ) , FoliageInfo . Instances . Num ( ) ) ;
2021-02-03 07:58:08 -04:00
}
2022-01-18 15:38:27 -05:00
2021-11-07 23:43:01 -05:00
return true ;
2021-02-03 07:58:08 -04:00
} ) ;
2020-09-14 08:43:13 -04:00
2022-01-18 15:38:27 -05:00
if ( ! bAddFoliageSucceeded )
{
return false ;
}
2020-09-14 08:43:13 -04:00
IFA - > GetLevel ( ) - > GetWorld ( ) - > DestroyActor ( IFA ) ;
2021-11-07 23:43:01 -05:00
// Add Foliage to those actors
for ( auto & InstancesPerFoliageType : FoliageToAdd )
{
for ( const FFoliageInstance & Instance : InstancesPerFoliageType . Value )
{
AInstancedFoliageActor * GridIFA = AInstancedFoliageActor : : Get ( MainWorld , /*bCreateIfNone=*/ true , MainWorld - > PersistentLevel , Instance . Location ) ;
FFoliageInfo * NewFoliageInfo = nullptr ;
UFoliageType * NewFoliageType = GridIFA - > AddFoliageType ( InstancesPerFoliageType . Key , & NewFoliageInfo ) ;
NewFoliageInfo - > AddInstance ( NewFoliageType , Instance ) ;
NumInstancesProcessed + + ;
}
}
check ( NumInstances = = NumInstancesProcessed ) ;
2022-01-18 15:38:27 -05:00
return true ;
2020-09-14 08:43:13 -04:00
} ;
2020-10-16 10:14:23 -04:00
auto PartitionLandscape = [ this , MainWorld ] ( ULandscapeInfo * LandscapeInfo )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( PartitionLandscape ) ;
2020-10-16 10:14:23 -04:00
// Handle Landscapes with missing LandscapeActor(s)
if ( ! LandscapeInfo - > LandscapeActor . Get ( ) )
{
// Use the first proxy as the landscape template
ALandscapeProxy * FirstProxy = LandscapeInfo - > Proxies [ 0 ] ;
FActorSpawnParameters SpawnParams ;
FTransform LandscapeTransform = FirstProxy - > LandscapeActorToWorld ( ) ;
ALandscape * NewLandscape = MainWorld - > SpawnActor < ALandscape > ( ALandscape : : StaticClass ( ) , LandscapeTransform , SpawnParams ) ;
NewLandscape - > GetSharedProperties ( FirstProxy ) ;
LandscapeInfo - > RegisterActor ( NewLandscape ) ;
}
2020-11-23 08:28:12 -04:00
TSet < AActor * > NewSplineActors ;
auto MoveControlPointToNewSplineActor = [ & NewSplineActors , LandscapeInfo ] ( ULandscapeSplineControlPoint * ControlPoint )
{
AActor * CurrentOwner = ControlPoint - > GetTypedOuter < AActor > ( ) ;
// Control point as already been moved through its connected segments
if ( NewSplineActors . Contains ( CurrentOwner ) )
{
return ;
}
const FTransform LocalToWorld = ControlPoint - > GetOuterULandscapeSplinesComponent ( ) - > GetComponentTransform ( ) ;
const FVector NewActorLocation = LocalToWorld . TransformPosition ( ControlPoint - > Location ) ;
ALandscapeSplineActor * NewSplineActor = LandscapeInfo - > CreateSplineActor ( NewActorLocation ) ;
// ULandscapeSplinesComponent doesn't assign SplineEditorMesh when IsCommandlet() is true.
NewSplineActor - > GetSplinesComponent ( ) - > SetDefaultEditorSplineMesh ( ) ;
NewSplineActors . Add ( NewSplineActor ) ;
LandscapeInfo - > MoveSpline ( ControlPoint , NewSplineActor ) ;
} ;
// Iterate on copy since we are creating new spline actors
TArray < TScriptInterface < ILandscapeSplineInterface > > OldSplineActors ( LandscapeInfo - > GetSplineActors ( ) ) ;
for ( TScriptInterface < ILandscapeSplineInterface > PreviousSplineActor : OldSplineActors )
{
if ( ULandscapeSplinesComponent * SplineComponent = PreviousSplineActor - > GetSplinesComponent ( ) )
{
SplineComponent - > ForEachControlPoint ( MoveControlPointToNewSplineActor ) ;
}
}
2020-10-16 10:14:23 -04:00
TSet < AActor * > ActorsToDelete ;
FLandscapeConfigHelper : : ChangeGridSize ( LandscapeInfo , LandscapeGridSize , ActorsToDelete ) ;
for ( AActor * ActorToDelete : ActorsToDelete )
{
MainWorld - > DestroyActor ( ActorToDelete ) ;
}
} ;
2022-03-15 13:52:28 -04:00
auto PrepareLevelActors = [ this , PartitionFoliage , PartitionLandscape , MainWorldDataLayers , MainWorld ] ( ULevel * Level , TArray < AActor * > & Actors , bool bMainLevel ) - > bool
2020-09-14 08:43:13 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( PrepareLevelActors ) ;
2020-10-20 13:56:19 -04:00
const FBox WorldBounds ( WorldOrigin - WorldExtent , WorldOrigin + WorldExtent ) ;
2020-09-14 08:43:13 -04:00
TArray < AInstancedFoliageActor * > IFAs ;
2020-10-16 10:14:23 -04:00
TSet < ULandscapeInfo * > LandscapeInfos ;
2022-03-15 13:52:28 -04:00
IAssetTools & AssetTools = FModuleManager : : GetModuleChecked < FAssetToolsModule > ( " AssetTools " ) . Get ( ) ;
FString DataLayerFolder = DataLayerAssetFolder + MainWorld - > GetName ( ) + TEXT ( " / " ) ;
2021-01-26 14:20:22 -04:00
for ( AActor * Actor : Actors )
2020-08-11 01:36:57 -04:00
{
2021-09-06 12:23:53 -04:00
if ( Actor & & IsValidChecked ( Actor ) )
2020-08-11 01:36:57 -04:00
{
2021-01-26 14:20:22 -04:00
check ( Actor - > GetLevel ( ) = = Level ) ;
2020-08-11 01:36:57 -04:00
if ( ShouldDeleteActor ( Actor , bMainLevel ) )
{
Level - > GetWorld ( ) - > DestroyActor ( Actor ) ;
}
2020-11-03 17:22:44 -04:00
else
2020-09-14 08:43:13 -04:00
{
2020-11-03 17:22:44 -04:00
if ( AInstancedFoliageActor * IFA = Cast < AInstancedFoliageActor > ( Actor ) )
2020-10-20 13:56:19 -04:00
{
2020-11-03 17:22:44 -04:00
IFAs . Add ( IFA ) ;
2020-10-20 13:56:19 -04:00
}
2020-11-03 17:22:44 -04:00
else if ( ALandscapeProxy * LandscapeProxy = Cast < ALandscapeProxy > ( Actor ) )
2020-10-20 13:56:19 -04:00
{
2020-11-03 17:22:44 -04:00
ULandscapeInfo * LandscapeInfo = LandscapeProxy - > GetLandscapeInfo ( ) ;
check ( LandscapeInfo ) ;
LandscapeInfos . Add ( LandscapeInfo ) ;
2020-10-20 13:56:19 -04:00
}
2021-12-07 11:50:24 -05:00
// Only override default grid placement on actors that are spatially loaded
2021-12-13 13:36:10 -05:00
else if ( Actor - > GetIsSpatiallyLoaded ( ) & & Actor - > CanChangeIsSpatiallyLoadedFlag ( ) )
2020-11-03 17:22:44 -04:00
{
2021-05-06 09:06:55 -04:00
const FBox ActorBounds = Actor - > GetStreamingBounds ( ) ;
2020-11-03 17:22:44 -04:00
if ( ! WorldBounds . IsInside ( ActorBounds ) )
{
2021-12-07 11:50:24 -05:00
Actor - > SetIsSpatiallyLoaded ( false ) ;
2020-11-03 17:22:44 -04:00
}
2020-11-02 12:20:44 -04:00
}
2020-11-03 17:22:44 -04:00
// Convert Layers into DataLayers with DynamicallyLoaded flag disabled
if ( Actor - > IsValidForDataLayer ( ) )
{
for ( FName Layer : Actor - > Layers )
{
2022-03-15 13:52:28 -04:00
FName DataLayerAssetFullName ( DataLayerAssetFolder + Layer . ToString ( ) ) ;
UDataLayerInstance * DataLayerInstance = const_cast < UDataLayerInstance * > ( MainWorldDataLayers - > GetDataLayerInstanceFromAssetName ( DataLayerAssetFullName ) ) ;
if ( ! DataLayerInstance )
2020-11-03 17:22:44 -04:00
{
2022-03-15 13:52:28 -04:00
if ( UObject * Asset = AssetTools . CreateAsset ( Layer . ToString ( ) , DataLayerFolder , UDataLayerAsset : : StaticClass ( ) , DataLayerFactory ) )
{
UDataLayerAsset * DataLayerAsset = CastChecked < UDataLayerAsset > ( Asset ) ;
DataLayerAsset - > SetType ( EDataLayerType : : Editor ) ;
DataLayerInstance = MainWorldDataLayers - > CreateDataLayer < UDataLayerInstanceWithAsset > ( DataLayerAsset ) ;
}
2020-11-03 17:22:44 -04:00
}
2022-03-15 13:52:28 -04:00
Actor - > AddDataLayer ( DataLayerInstance ) ;
2020-11-03 17:22:44 -04:00
}
}
2021-12-06 16:16:42 -05:00
// Clear actor layers as they are not supported yet in world partition, keep them if only merging
if ( ! bOnlyMergeSubLevels )
{
Actor - > Layers . Empty ( ) ;
}
2020-11-02 12:20:44 -04:00
}
2020-08-11 01:36:57 -04:00
}
}
2020-09-14 08:43:13 -04:00
2022-05-09 15:13:17 -04:00
if ( bMainLevel )
{
if ( LevelHasLevelScriptBlueprint ( Level ) )
{
ULevelScriptBlueprint * LevelScriptBlueprint = Level - > GetLevelScriptBlueprint ( true ) ;
TArray < AActor * > LevelScriptActorReferences = ActorsReferencesUtils : : GetActorReferences ( LevelScriptBlueprint ) ;
for ( AActor * LevelScriptActorReference : LevelScriptActorReferences )
{
if ( LevelScriptActorReference - > GetIsSpatiallyLoaded ( ) & & LevelScriptActorReference - > CanChangeIsSpatiallyLoadedFlag ( ) )
{
LevelScriptActorReference - > SetIsSpatiallyLoaded ( false ) ;
}
}
}
}
2020-09-14 08:43:13 -04:00
// do loop after as it may modify Level->Actors
2020-10-20 13:56:19 -04:00
if ( IFAs . Num ( ) )
2020-09-14 08:43:13 -04:00
{
2021-07-13 16:12:20 -04:00
UE_SCOPED_TIMER ( TEXT ( " PartitionFoliage " ) , LogWorldPartitionConvertCommandlet , Display ) ;
2020-10-20 13:56:19 -04:00
for ( AInstancedFoliageActor * IFA : IFAs )
{
2022-01-18 15:38:27 -05:00
if ( ! PartitionFoliage ( IFA ) )
{
return false ;
}
2020-10-20 13:56:19 -04:00
}
2020-09-14 08:43:13 -04:00
}
2020-10-16 10:14:23 -04:00
2020-10-20 13:56:19 -04:00
if ( LandscapeInfos . Num ( ) )
2020-10-16 10:14:23 -04:00
{
2021-07-13 16:12:20 -04:00
UE_SCOPED_TIMER ( TEXT ( " PartitionLandscape " ) , LogWorldPartitionConvertCommandlet , Display ) ;
2020-10-20 13:56:19 -04:00
for ( ULandscapeInfo * LandscapeInfo : LandscapeInfos )
{
PartitionLandscape ( LandscapeInfo ) ;
}
2020-10-16 10:14:23 -04:00
}
2022-01-18 15:38:27 -05:00
return true ;
2020-08-11 01:36:57 -04:00
} ;
2020-09-02 08:33:07 -04:00
// Gather and load sublevels
2020-08-25 07:27:44 -04:00
TArray < ULevel * > SubLevelsToConvert ;
2021-12-06 16:16:42 -05:00
GatherAndPrepareSubLevelsToConvert ( MainLevel , SubLevelsToConvert ) ;
2020-08-25 07:27:44 -04:00
if ( ! GetAdditionalLevelsToConvert ( MainLevel , SubLevelsToConvert ) )
{
return 1 ;
}
2020-09-02 08:33:07 -04:00
// Validate levels for conversion
2020-09-02 11:27:43 -04:00
bool bSkipStableGUIDValidation = Switches . Contains ( TEXT ( " SkipStableGUIDValidation " ) ) ;
if ( ! bSkipStableGUIDValidation )
2020-09-02 08:33:07 -04:00
{
2020-09-02 11:27:43 -04:00
bool bNeedsResaveSubLevels = false ;
for ( ULevel * Level : SubLevelsToConvert )
2020-09-02 08:33:07 -04:00
{
2020-09-02 11:27:43 -04:00
if ( ! Level - > bContainsStableActorGUIDs )
{
bNeedsResaveSubLevels | = true ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Unable to convert level '%s' with non-stable actor GUIDs. Resave the level before converting. " ) , * Level - > GetPackage ( ) - > GetName ( ) ) ;
}
2020-09-02 08:33:07 -04:00
}
2020-09-02 11:27:43 -04:00
if ( bNeedsResaveSubLevels )
{
return 1 ;
}
2020-09-02 08:33:07 -04:00
}
2020-08-25 07:27:44 -04:00
// Prepare levels for conversion
2020-08-11 01:36:57 -04:00
DetachDependantLevelPackages ( MainLevel ) ;
2022-01-18 15:38:27 -05:00
if ( ! PrepareLevelActors ( MainLevel , MainLevel - > Actors , true ) )
{
return 1 ;
}
2021-01-26 14:20:22 -04:00
PackagesToSave . Add ( MainLevel - > GetPackage ( ) ) ;
2020-08-11 01:36:57 -04:00
if ( bConversionSuffix )
{
FString OldMainWorldPath = FSoftObjectPath ( MainWorld ) . ToString ( ) ;
FString OldMainLevelPath = FSoftObjectPath ( MainLevel ) . ToString ( ) ;
FString OldPackagePath = FSoftObjectPath ( MainPackage ) . ToString ( ) ;
if ( ! RenameWorldPackageWithSuffix ( MainWorld ) )
{
return 1 ;
}
RemapSoftObjectPaths . Add ( OldMainWorldPath , FSoftObjectPath ( MainWorld ) . ToString ( ) ) ;
RemapSoftObjectPaths . Add ( OldMainLevelPath , FSoftObjectPath ( MainLevel ) . ToString ( ) ) ;
RemapSoftObjectPaths . Add ( OldPackagePath , FSoftObjectPath ( MainPackage ) . ToString ( ) ) ;
}
TMap < UObject * , UObject * > PrivateRefsMap ;
for ( ULevel * SubLevel : SubLevelsToConvert )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( ConvertSubLevel ) ;
2020-08-11 01:36:57 -04:00
UWorld * SubWorld = SubLevel - > GetTypedOuter < UWorld > ( ) ;
UPackage * SubPackage = SubLevel - > GetPackage ( ) ;
2022-05-24 12:07:44 -04:00
SubWorld - > PersistentLevel - > Model - > MarkAsGarbage ( ) ;
SubWorld - > PersistentLevel - > Model = nullptr ;
2021-01-26 14:20:22 -04:00
RemapSoftObjectPaths . Add ( FSoftObjectPath ( SubWorld ) . ToString ( ) , FSoftObjectPath ( MainWorld ) . ToString ( ) ) ;
RemapSoftObjectPaths . Add ( FSoftObjectPath ( SubLevel ) . ToString ( ) , FSoftObjectPath ( MainLevel ) . ToString ( ) ) ;
RemapSoftObjectPaths . Add ( FSoftObjectPath ( SubPackage ) . ToString ( ) , FSoftObjectPath ( MainPackage ) . ToString ( ) ) ;
TArray < AActor * > ActorsToConvert ;
2020-08-11 01:36:57 -04:00
if ( LevelHasLevelScriptBlueprint ( SubLevel ) )
{
2020-11-25 22:11:10 -04:00
MapsWithLevelScriptsBPs . Add ( SubPackage - > GetLoadedPath ( ) . GetPackageName ( ) ) ;
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
if ( bConvertActorsNotReferencedByLevelScript )
{
// Gather the list of actors referenced by the level script blueprint
TSet < AActor * > LevelScriptActorReferences ;
ALevelScriptActor * LevelScriptActor = SubLevel - > GetLevelScriptActor ( ) ;
LevelScriptActorReferences . Add ( LevelScriptActor ) ;
ULevelScriptBlueprint * LevelScriptBlueprint = SubLevel - > GetLevelScriptBlueprint ( true ) ;
LevelScriptActorReferences . Append ( ActorsReferencesUtils : : GetActorReferences ( LevelScriptBlueprint ) ) ;
for ( AActor * Actor : SubLevel - > Actors )
{
2021-09-06 12:23:53 -04:00
if ( IsValid ( Actor ) )
2021-01-26 14:20:22 -04:00
{
TSet < AActor * > ActorReferences ;
ActorReferences . Append ( ActorsReferencesUtils : : GetActorReferences ( Actor ) ) ;
for ( AActor * ActorReference : ActorReferences )
{
if ( LevelScriptActorReferences . Find ( ActorReference ) )
{
LevelScriptActorReferences . Add ( Actor ) ;
LevelScriptActorReferences . Append ( ActorReferences ) ;
break ;
}
}
}
}
for ( AActor * Actor : SubLevel - > Actors )
{
2021-09-06 12:23:53 -04:00
if ( IsValid ( Actor ) )
2021-01-26 14:20:22 -04:00
{
if ( ! LevelScriptActorReferences . Find ( Actor ) )
{
ActorsToConvert . Add ( Actor ) ;
}
}
}
}
// Rename the world if requested
UWorld * SubLevelWorld = SubLevel - > GetTypedOuter < UWorld > ( ) ;
UPackage * SubLevelPackage = SubLevelWorld - > GetPackage ( ) ;
if ( bConversionSuffix )
{
FString OldMainWorldPath = FSoftObjectPath ( SubLevelWorld ) . ToString ( ) ;
FString OldMainLevelPath = FSoftObjectPath ( SubLevel ) . ToString ( ) ;
FString OldPackagePath = FSoftObjectPath ( SubLevelPackage ) . ToString ( ) ;
if ( ! RenameWorldPackageWithSuffix ( SubLevelWorld ) )
{
return 1 ;
}
RemapSoftObjectPaths . Add ( OldMainWorldPath , FSoftObjectPath ( SubLevelWorld ) . ToString ( ) ) ;
RemapSoftObjectPaths . Add ( OldMainLevelPath , FSoftObjectPath ( SubLevel ) . ToString ( ) ) ;
RemapSoftObjectPaths . Add ( OldPackagePath , FSoftObjectPath ( SubLevelPackage ) . ToString ( ) ) ;
}
PackagesToSave . Add ( SubLevelPackage ) ;
// Spawn the level instance actor
2021-01-22 16:09:31 -04:00
ULevelStreaming * SubLevelStreaming = nullptr ;
2021-06-03 09:50:03 -04:00
for ( ULevelStreaming * LevelStreaming : MainWorld - > GetStreamingLevels ( ) )
2020-08-11 01:36:57 -04:00
{
2021-01-22 16:09:31 -04:00
if ( LevelStreaming - > GetLoadedLevel ( ) = = SubLevel )
{
SubLevelStreaming = LevelStreaming ;
break ;
}
}
check ( SubLevelStreaming ) ;
FActorSpawnParameters SpawnParams ;
SpawnParams . OverrideLevel = MainLevel ;
ALevelInstance * LevelInstanceActor = MainWorld - > SpawnActor < ALevelInstance > ( SpawnParams ) ;
2021-02-23 15:26:51 -04:00
2021-01-22 16:09:31 -04:00
FTransform LevelTransform ;
2022-01-26 15:00:04 -05:00
if ( SubLevelPackage - > GetWorldTileInfo ( ) )
2021-01-22 16:09:31 -04:00
{
2022-01-26 15:00:04 -05:00
LevelTransform = FTransform ( FVector ( SubLevelPackage - > GetWorldTileInfo ( ) - > Position ) ) ;
2021-01-22 16:09:31 -04:00
}
else
{
LevelTransform = SubLevelStreaming - > LevelTransform ;
}
2021-02-23 15:26:51 -04:00
LevelInstanceActor - > DesiredRuntimeBehavior = ELevelInstanceRuntimeBehavior : : LevelStreaming ;
2021-01-22 16:09:31 -04:00
LevelInstanceActor - > SetActorTransform ( LevelTransform ) ;
2021-01-26 14:20:22 -04:00
LevelInstanceActor - > SetWorldAsset ( SubLevelWorld ) ;
2021-01-22 16:09:31 -04:00
}
else
{
if ( LevelHasMapBuildData ( SubLevel ) )
{
MapsWithMapBuildData . Add ( SubPackage - > GetLoadedPath ( ) . GetPackageName ( ) ) ;
}
DetachDependantLevelPackages ( SubLevel ) ;
2021-01-26 14:20:22 -04:00
ActorsToConvert = SubLevel - > Actors ;
}
2021-01-22 16:09:31 -04:00
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Converting %s " ) , * SubWorld - > GetName ( ) ) ;
2021-01-26 14:20:22 -04:00
2021-12-07 11:50:24 -05:00
PrepareLevelActors ( SubLevel , ActorsToConvert , false ) ;
2021-01-26 14:20:22 -04:00
for ( AActor * Actor : ActorsToConvert )
{
2021-09-06 12:23:53 -04:00
if ( Actor & & IsValidChecked ( Actor ) )
2021-01-22 16:09:31 -04:00
{
2021-01-26 14:20:22 -04:00
check ( Actor - > GetOuter ( ) = = SubLevel ) ;
check ( ! ShouldDeleteActor ( Actor , false ) ) ;
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
if ( Actor - > IsA ( AGroupActor : : StaticClass ( ) ) )
{
GroupActors . Add ( * Actor - > GetFullName ( ) ) ;
}
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
if ( Actor - > GroupActor )
{
ActorsInGroupActors . Add ( * Actor - > GetFullName ( ) ) ;
}
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
TArray < AActor * > ChildActors ;
Actor - > GetAllChildActors ( ChildActors , false ) ;
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
if ( ChildActors . Num ( ) )
{
ActorsWithChildActors . Add ( * Actor - > GetFullName ( ) ) ;
}
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
FArchiveGatherPrivateImports Ar ( Actor , PrivateRefsMap , ActorsReferencesToActors ) ;
Actor - > Serialize ( Ar ) ;
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
// Even after Foliage Partitioning it is possible some Actors still have a FoliageTag. Make sure it is removed.
if ( FFoliageHelper : : IsOwnedByFoliage ( Actor ) )
{
FFoliageHelper : : SetIsOwnedByFoliage ( Actor , false ) ;
}
2020-09-14 14:48:31 -04:00
2021-01-26 14:20:22 -04:00
ChangeObjectOuter ( Actor , MainLevel ) ;
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
// Migrate blueprint classes
UClass * ActorClass = Actor - > GetClass ( ) ;
if ( ! ActorClass - > IsNative ( ) & & ( ActorClass - > GetPackage ( ) = = SubPackage ) )
{
ChangeObjectOuter ( ActorClass , MainPackage ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Extracted non-native class %s " ) , * ActorClass - > GetName ( ) ) ;
2020-08-11 01:36:57 -04:00
}
}
2021-01-26 14:20:22 -04:00
}
2020-08-11 01:36:57 -04:00
2021-01-26 14:20:22 -04:00
if ( ! LevelHasLevelScriptBlueprint ( SubLevel ) )
{
2021-01-22 16:09:31 -04:00
if ( ! bReportOnly )
2020-08-11 01:36:57 -04:00
{
2021-01-22 16:09:31 -04:00
TArray < UObject * > ObjectsToRename ;
ForEachObjectWithPackage ( SubPackage , [ & ] ( UObject * Object )
2020-08-11 01:36:57 -04:00
{
2021-01-22 16:09:31 -04:00
if ( ! Object - > IsA < AActor > ( ) & & ! Object - > IsA < ULevel > ( ) & & ! Object - > IsA < UWorld > ( ) & & ! Object - > IsA < UMetaData > ( ) )
{
ObjectsToRename . Add ( Object ) ;
}
return true ;
} , /*bIncludeNestedObjects*/ false ) ;
for ( UObject * ObjectToRename : ObjectsToRename )
{
ChangeObjectOuter ( ObjectToRename , MainPackage ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Warning , TEXT ( " Renamed orphan object %s " ) , * ObjectToRename - > GetName ( ) ) ;
2020-08-11 01:36:57 -04:00
}
2021-01-22 16:09:31 -04:00
PackagesToDelete . Add ( SubLevel - > GetPackage ( ) ) ;
2020-08-11 01:36:57 -04:00
}
}
}
// Clear streaming levels
2021-06-03 09:50:03 -04:00
for ( ULevelStreaming * LevelStreaming : MainWorld - > GetStreamingLevels ( ) )
2020-08-11 01:36:57 -04:00
{
2021-11-18 14:37:34 -05:00
LevelStreaming - > MarkAsGarbage ( ) ;
2021-01-26 14:20:22 -04:00
ULevelStreaming : : RemoveLevelAnnotation ( LevelStreaming - > GetLoadedLevel ( ) ) ;
2021-06-03 09:50:03 -04:00
MainWorld - > RemoveLevel ( LevelStreaming - > GetLoadedLevel ( ) ) ;
2020-08-11 01:36:57 -04:00
}
2021-06-03 09:50:03 -04:00
MainWorld - > ClearStreamingLevels ( ) ;
2020-08-11 01:36:57 -04:00
// Fixup SoftObjectPaths
FixupSoftObjectPaths ( MainPackage ) ;
PerformAdditionalWorldCleanup ( MainWorld ) ;
bool bForceInitializeWorld = false ;
bool bInitializedPhysicsSceneForSave = GEditor - > InitializePhysicsSceneForSaveIfNecessary ( MainWorld , bForceInitializeWorld ) ;
// After conversion, convert actors to external actors
UPackage * LevelPackage = MainLevel - > GetPackage ( ) ;
TArray < AActor * > ActorList ;
TArray < AActor * > ChildActorList ;
ActorList . Reserve ( MainLevel - > Actors . Num ( ) ) ;
// Move child actors at the end of the list
for ( AActor * Actor : MainLevel - > Actors )
{
2021-09-06 12:23:53 -04:00
if ( Actor & & IsValidChecked ( Actor ) )
2020-08-11 01:36:57 -04:00
{
check ( Actor - > GetLevel ( ) = = MainLevel ) ;
check ( Actor - > GetActorGuid ( ) . IsValid ( ) ) ;
if ( Actor - > GetParentActor ( ) )
{
ChildActorList . Add ( Actor ) ;
}
else
{
ActorList . Add ( Actor ) ;
}
}
}
ActorList . Append ( ChildActorList ) ;
ChildActorList . Empty ( ) ;
2021-12-06 16:16:42 -05:00
if ( ! bOnlyMergeSubLevels )
{
WorldPartition - > AddToRoot ( ) ;
}
2020-08-25 07:27:44 -04:00
2020-08-11 01:36:57 -04:00
if ( ! bReportOnly )
{
2022-01-07 10:01:19 -05:00
FLevelActorFoldersHelper : : SetUseActorFolders ( MainLevel , true ) ;
MainLevel - > SetUseExternalActors ( true ) ;
2020-10-15 06:31:42 -04:00
TSet < FGuid > ActorGuids ;
2020-08-11 01:36:57 -04:00
for ( AActor * Actor : ActorList )
{
2021-09-06 12:23:53 -04:00
if ( ! Actor | | ! IsValidChecked ( Actor ) | | ! Actor - > SupportsExternalPackaging ( ) )
2020-08-11 01:36:57 -04:00
{
continue ;
}
2020-10-15 06:31:42 -04:00
bool bAlreadySet = false ;
ActorGuids . Add ( Actor - > GetActorGuid ( ) , & bAlreadySet ) ;
if ( bAlreadySet )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Duplicated guid actor %s(guid:%s) can't extract actor " ) , * Actor - > GetName ( ) , * Actor - > GetActorGuid ( ) . ToString ( EGuidFormats : : Digits ) ) ;
return 1 ;
}
2020-08-11 01:36:57 -04:00
if ( Actor - > IsPackageExternal ( ) )
{
PackagesToDelete . Add ( Actor - > GetPackage ( ) ) ;
Actor - > SetPackageExternal ( false ) ;
}
2020-10-15 06:31:42 -04:00
2020-08-11 01:36:57 -04:00
Actor - > SetPackageExternal ( true ) ;
2022-01-07 10:01:19 -05:00
if ( ! Actor - > CreateOrUpdateActorFolder ( ) )
{
UE_LOG ( LogWorldPartitionConvertCommandlet , Error , TEXT ( " Failed to convert actor %s folder to persistent folder. " ) , * Actor - > GetName ( ) ) ;
}
2020-10-15 06:31:42 -04:00
2020-08-11 01:36:57 -04:00
UPackage * ActorPackage = Actor - > GetExternalPackage ( ) ;
PackagesToSave . Add ( ActorPackage ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Extracted actor %s(guid:%s) in %s " ) , * Actor - > GetName ( ) , * Actor - > GetActorGuid ( ) . ToString ( EGuidFormats : : Digits ) , * ActorPackage - > GetName ( ) ) ;
2020-08-11 01:36:57 -04:00
}
// Required to clear any deleted actors from the level
CollectGarbage ( RF_Standalone ) ;
2021-03-10 13:02:24 -04:00
for ( AActor * Actor : ActorList )
{
2021-09-06 12:23:53 -04:00
if ( ! IsValid ( Actor ) )
2021-03-10 13:02:24 -04:00
{
continue ;
}
PerformAdditionalActorChanges ( Actor ) ;
}
2022-01-07 10:01:19 -05:00
MainLevel - > ForEachActorFolder ( [ this ] ( UActorFolder * ActorFolder )
{
UPackage * ActorFolderPackage = ActorFolder - > GetExternalPackage ( ) ;
check ( ActorFolderPackage ) ;
PackagesToSave . Add ( ActorFolderPackage ) ;
return true ;
} ) ;
2020-08-26 09:26:08 -04:00
MainWorld - > WorldComposition = nullptr ;
2021-12-06 16:16:42 -05:00
MainLevel - > bIsPartitioned = ! bOnlyMergeSubLevels ;
2020-08-11 01:36:57 -04:00
if ( bDeleteSourceLevels )
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( DeleteSourceLevels ) ;
2020-08-11 01:36:57 -04:00
for ( UPackage * Package : PackagesToDelete )
{
2020-09-01 08:38:42 -04:00
if ( ! PackageHelper . Delete ( Package ) )
2020-08-11 01:36:57 -04:00
{
return 1 ;
}
}
}
2021-01-26 14:20:22 -04:00
// Checkout packages
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( CheckoutPackages ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Checking out %d packages. " ) , PackagesToSave . Num ( ) ) ;
2021-01-19 09:02:21 -04:00
for ( UPackage * Package : PackagesToSave )
2020-08-11 01:36:57 -04:00
{
2021-06-03 11:14:50 -04:00
FString PackageFileName = SourceControlHelpers : : PackageFilename ( Package ) ;
if ( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * PackageFileName ) )
2021-01-19 09:02:21 -04:00
{
2021-06-03 11:14:50 -04:00
if ( ! PackageHelper . Checkout ( Package ) )
{
return 1 ;
}
2021-01-19 09:02:21 -04:00
}
2020-08-11 01:36:57 -04:00
}
}
for ( TMap < UObject * , UObject * > : : TConstIterator It ( PrivateRefsMap ) ; It ; + + It )
{
SET_WARN_COLOR ( COLOR_YELLOW ) ;
UE_LOG ( LogWorldPartitionConvertCommandlet , Warning , TEXT ( " Renaming %s from %s to %s " ) , * It - > Key - > GetName ( ) , * It - > Key - > GetPackage ( ) - > GetName ( ) , * It - > Value - > GetPackage ( ) - > GetName ( ) ) ;
CLEAR_WARN_COLOR ( ) ;
It - > Key - > SetExternalPackage ( It - > Value - > GetPackage ( ) ) ;
}
// Save packages
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SavePackages ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " Saving %d packages. " ) , PackagesToSave . Num ( ) ) ;
2021-01-19 09:02:21 -04:00
for ( UPackage * PackageToSave : PackagesToSave )
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
FString PackageFileName = SourceControlHelpers : : PackageFilename ( PackageToSave ) ;
2021-11-23 20:56:06 -05:00
FSavePackageArgs SaveArgs ;
SaveArgs . TopLevelFlags = RF_Standalone ;
SaveArgs . SaveFlags = SAVE_Async ;
if ( ! UPackage : : SavePackage ( PackageToSave , nullptr , * PackageFileName , SaveArgs ) )
2021-01-19 09:02:21 -04:00
{
return 1 ;
}
2020-08-11 01:36:57 -04:00
}
}
2021-01-26 14:20:22 -04:00
// Add packages
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( AddPackagesToSourceControl ) ;
// Add new packages to source control
for ( UPackage * PackageToSave : PackagesToSave )
2020-08-11 01:36:57 -04:00
{
2021-01-19 09:02:21 -04:00
if ( ! PackageHelper . AddToSourceControl ( PackageToSave ) )
{
return 1 ;
}
2020-08-11 01:36:57 -04:00
}
}
if ( bInitializedPhysicsSceneForSave )
{
GEditor - > CleanupPhysicsSceneThatWasInitializedForSave ( MainWorld , bForceInitializeWorld ) ;
}
2020-09-14 13:54:21 -04:00
UPackage : : WaitForAsyncFileWrites ( ) ;
2022-05-31 11:22:14 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Log , TEXT ( " ######## CONVERSION COMPLETED SUCCESSFULLY ######## " ) ) ;
2020-08-25 07:27:44 -04:00
}
if ( bGenerateIni | | ! bReportOnly )
{
2020-10-20 13:56:19 -04:00
if ( bGenerateIni | | ! FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * LevelConfigFilename ) )
2020-08-11 01:36:57 -04:00
{
SaveConfig ( CPF_Config , * LevelConfigFilename ) ;
2021-12-06 16:16:42 -05:00
if ( ! bOnlyMergeSubLevels )
{
WorldPartition - > EditorHash - > SaveConfig ( CPF_Config , * LevelConfigFilename ) ;
WorldPartition - > RuntimeHash - > SaveConfig ( CPF_Config , * LevelConfigFilename ) ;
}
2020-08-11 01:36:57 -04:00
for ( const auto & Pair : HLODLayers )
{
Pair . Value - > SaveConfig ( CPF_Config , * LevelConfigFilename ) ;
}
2022-05-30 14:42:25 -04:00
UE_LOG ( LogWorldPartitionConvertCommandlet , Display , TEXT ( " Generated ini file: %s " ) , * LevelConfigFilename ) ;
2020-08-11 01:36:57 -04:00
}
}
UPackage : : WaitForAsyncFileWrites ( ) ;
OutputConversionReport ( ) ;
return 0 ;
}
2021-02-17 14:12:50 -04:00
2021-12-06 16:16:42 -05:00
const FString UWorldPartitionConvertCommandlet : : GetConversionSuffix ( const bool bInOnlyMergeSubLevels )
{
return bInOnlyMergeSubLevels ? TEXT ( " _OFPA " ) : TEXT ( " _WP " ) ;
}
2021-02-17 14:12:50 -04:00
bool UWorldPartitionConvertCommandlet : : ShouldConvertStreamingLevel ( ULevelStreaming * StreamingLevel )
{
return StreamingLevel & & ! ExcludedLevels . Contains ( StreamingLevel - > GetWorldAssetPackageName ( ) ) ;
}