2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
/*=============================================================================
EditorLevelUtils . cpp : Editor - specific level management routines
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "UnrealEd.h"
2014-05-21 10:00:58 -04:00
# include "EditorSupportDelegates.h"
2014-03-14 14:13:41 -04:00
# include "EditorLevelUtils.h"
# include "BusyCursor.h"
# include "LevelUtils.h"
# include "Layers/ILayers.h"
# include "LevelEditor.h"
# include "ScopedTransaction.h"
# include "ActorEditorUtils.h"
2014-06-18 07:25:31 -04:00
# include "ContentStreaming.h"
2014-09-25 17:33:22 -04:00
# include "PackageTools.h"
2014-03-14 14:13:41 -04:00
2014-05-29 17:35:33 -04:00
# include "Runtime/AssetRegistry/Public/AssetRegistryModule.h"
2014-11-04 06:12:25 -05:00
# include "Engine/LevelStreamingVolume.h"
2014-11-12 04:43:54 -05:00
# include "Engine/LevelStreaming.h"
# include "GameFramework/WorldSettings.h"
# include "Engine/Selection.h"
# include "Components/ModelComponent.h"
2014-05-29 17:35:33 -04:00
2014-03-14 14:13:41 -04:00
DEFINE_LOG_CATEGORY ( LogLevelTools ) ;
# define LOCTEXT_NAMESPACE "EditorLevelUtils"
namespace EditorLevelUtils
{
/**
* Moves the specified list of actors to the specified level
*
* @ param ActorsToMove List of actors to move
* @ param DestLevelStreaming The level streaming object associated with the destination level
* @ param OutNumMovedActors The number of actors that were successfully moved to the new level
*/
void MovesActorsToLevel ( TArray < AActor * > & ActorsToMove , ULevelStreaming * DestLevelStreaming , int32 & OutNumMovedActors )
{
// Backup the current contents of the clipboard string as we'll be using cut/paste features to move actors
// between levels and this will trample over the clipboard data.
FString OriginalClipboardContent ;
FPlatformMisc : : ClipboardPaste ( OriginalClipboardContent ) ;
check ( DestLevelStreaming ! = NULL ) ;
ULevel * DestLevel = DestLevelStreaming - > GetLoadedLevel ( ) ;
check ( DestLevel ! = NULL ) ;
// Cache a the destination world
UWorld * World = DestLevel - > OwningWorld ;
// Deselect all actors
GEditor - > Exec ( World , TEXT ( " ACTOR SELECT NONE " ) ) ;
2014-08-25 11:05:29 -04:00
const FString & NewLevelName = DestLevelStreaming - > GetWorldAssetPackageName ( ) ;
2014-03-14 14:13:41 -04:00
for ( TArray < AActor * > : : TIterator CurActorIt ( ActorsToMove ) ; CurActorIt ; + + CurActorIt )
{
AActor * CurActor = * CurActorIt ;
check ( CurActor ! = NULL ) ;
if ( ! FLevelUtils : : IsLevelLocked ( DestLevel ) & & ! FLevelUtils : : IsLevelLocked ( CurActor ) )
{
ULevelStreaming * ActorPrevLevel = FLevelUtils : : FindStreamingLevel ( CurActor - > GetLevel ( ) ) ;
2014-08-25 11:05:29 -04:00
const FString & PrevLevelName = ActorPrevLevel ! = NULL ? ActorPrevLevel - > GetWorldAssetPackageName ( ) : CurActor - > GetLevel ( ) - > GetName ( ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogLevelTools , Warning , TEXT ( " AutoLevel: Moving %s from %s to %s " ) , * CurActor - > GetName ( ) , * PrevLevelName , * NewLevelName ) ;
// Select this actor
GEditor - > SelectActor ( CurActor , true , false , true ) ;
// Cache the world the actor is in, or if we already did ensure its the same world.
check ( World = = CurActor - > GetWorld ( ) ) ;
}
else
{
// Either the source or destination level was locked!
// @todo: Display warning
}
}
OutNumMovedActors = 0 ;
if ( GEditor - > GetSelectedActorCount ( ) > 0 )
{
// @todo: Perf: Not sure if this is needed here.
GEditor - > NoteSelectionChange ( ) ;
// Move the actors!
GEditor - > MoveSelectedActorsToLevel ( DestLevel ) ;
// The moved (pasted) actors will now be selected
OutNumMovedActors + = GEditor - > GetSelectedActorCount ( ) ;
}
// Restore the original clipboard contents
FPlatformMisc : : ClipboardCopy ( * OriginalClipboardContent ) ;
}
static TArray < FString > GStreamingMethodStrings ;
static TArray < UClass * > GStreamingMethodClassList ;
/**
* Initializes the list of possible level streaming methods .
* Does nothing if the lists are already initialized .
*/
void InitializeStreamingMethods ( )
{
check ( GStreamingMethodStrings . Num ( ) = = GStreamingMethodClassList . Num ( ) ) ;
if ( GStreamingMethodClassList . Num ( ) = = 0 )
{
// Assemble a list of possible level streaming methods.
for ( TObjectIterator < UClass > It ; It ; + + It )
{
if ( It - > IsChildOf ( ULevelStreaming : : StaticClass ( ) ) & &
( It - > HasAnyClassFlags ( CLASS_EditInlineNew ) ) & &
! ( It - > HasAnyClassFlags ( CLASS_Hidden | CLASS_Abstract | CLASS_Deprecated | CLASS_Transient ) ) )
{
const FString ClassName ( It - > GetName ( ) ) ;
// Strip the leading "LevelStreaming" text from the class name.
// @todo DB: This assumes the names of all ULevelStreaming-derived types begin with the string "LevelStreaming".
GStreamingMethodStrings . Add ( ClassName . Mid ( 14 ) ) ;
GStreamingMethodClassList . Add ( * It ) ;
}
}
}
}
2014-06-30 19:03:07 -04:00
ULevel * AddLevelsToWorld ( UWorld * InWorld , const TArray < FString > & LevelPackageNames , UClass * LevelStreamingClass )
{
if ( ! ensure ( InWorld ) )
{
return nullptr ;
}
2014-10-08 04:42:34 -04:00
FScopedSlowTask SlowTask ( LevelPackageNames . Num ( ) , LOCTEXT ( " AddLevelsToWorldTask " , " Adding Levels to World " ) ) ;
SlowTask . MakeDialog ( ) ;
2014-07-22 16:48:43 -04:00
2014-06-30 19:03:07 -04:00
TArray < FString > PackageNames = LevelPackageNames ;
// Sort the level packages alphabetically by name.
PackageNames . Sort ( ) ;
// Fire ULevel::LevelDirtiedEvent when falling out of scope.
FScopedLevelDirtied LevelDirtyCallback ;
// Try to add the levels that were specified in the dialog.
ULevel * NewLevel = nullptr ;
for ( const auto & PackageName : PackageNames )
{
2014-10-08 04:42:34 -04:00
SlowTask . EnterProgressFrame ( ) ;
2014-06-30 19:03:07 -04:00
NewLevel = AddLevelToWorld ( InWorld , * PackageName , LevelStreamingClass ) ;
if ( NewLevel )
{
LevelDirtyCallback . Request ( ) ;
}
} // for each file
// Set the last loaded level to be the current level
if ( NewLevel )
{
InWorld - > SetCurrentLevel ( NewLevel ) ;
}
// For safety
if ( GLevelEditorModeTools ( ) . IsModeActive ( FBuiltinEditorModes : : EM_Landscape ) )
{
GLevelEditorModeTools ( ) . ActivateDefaultMode ( ) ;
}
// refresh editor windows
FEditorDelegates : : RefreshAllBrowsers . Broadcast ( ) ;
// Update volume actor visibility for each viewport since we loaded a level which could potentially contain volumes
GUnrealEd - > UpdateVolumeActorVisibility ( NULL ) ;
return NewLevel ;
}
2014-03-14 14:13:41 -04:00
ULevel * AddLevelToWorld ( UWorld * InWorld , const TCHAR * LevelPackageName , UClass * LevelStreamingClass )
{
ULevel * NewLevel = NULL ;
bool bIsPersistentLevel = ( InWorld - > PersistentLevel - > GetOutermost ( ) - > GetName ( ) = = FString ( LevelPackageName ) ) ;
if ( bIsPersistentLevel | | FLevelUtils : : FindStreamingLevel ( InWorld , LevelPackageName ) )
{
// Do nothing if the level already exists in the world.
FMessageDialog : : Open ( EAppMsgType : : Ok , NSLOCTEXT ( " UnrealEd " , " LevelAlreadyExistsInWorld " , " A level with that name already exists in the world. " ) ) ;
}
else
{
// If the selected class is still NULL, abort the operation.
if ( LevelStreamingClass = = NULL )
{
return NULL ;
}
const FScopedBusyCursor BusyCursor ;
2015-02-09 05:43:45 -05:00
ULevelStreaming * StreamingLevel = NewObject < ULevelStreaming > ( InWorld , LevelStreamingClass , NAME_None , RF_NoFlags , NULL ) ;
2014-03-14 14:13:41 -04:00
// Associate a package name.
2014-08-25 11:05:29 -04:00
StreamingLevel - > SetWorldAssetByPackageName ( LevelPackageName ) ;
2014-03-14 14:13:41 -04:00
// Seed the level's draw color.
2014-07-28 17:16:21 -04:00
StreamingLevel - > LevelColor = FLinearColor : : MakeRandomColor ( ) ;
2014-03-14 14:13:41 -04:00
// Add the new level to world.
InWorld - > StreamingLevels . Add ( StreamingLevel ) ;
// Refresh just the newly created level.
TArray < ULevelStreaming * > LevelsForRefresh ;
LevelsForRefresh . Add ( StreamingLevel ) ;
InWorld - > RefreshStreamingLevels ( LevelsForRefresh ) ;
InWorld - > MarkPackageDirty ( ) ;
NewLevel = StreamingLevel - > GetLoadedLevel ( ) ;
if ( NewLevel ! = NULL )
{
EditorLevelUtils : : SetLevelVisibility ( NewLevel , true , true ) ;
}
// Levels migrated from other projects may fail to load their world settings
// If so we create a new AWorldSettings actor here.
if ( NewLevel - > Actors [ 0 ] = = NULL )
{
UWorld * SubLevelWorld = CastChecked < UWorld > ( NewLevel - > GetOuter ( ) ) ;
if ( SubLevelWorld ! = NULL )
{
FActorSpawnParameters SpawnInfo ;
SpawnInfo . bNoCollisionFail = true ;
SpawnInfo . Name = GEngine - > WorldSettingsClass - > GetFName ( ) ;
AWorldSettings * NewWorldSettings = SubLevelWorld - > SpawnActor < AWorldSettings > ( GEngine - > WorldSettingsClass , SpawnInfo ) ;
NewLevel - > Actors [ 0 ] = NewWorldSettings ;
}
else
{
FMessageDialog : : Open ( EAppMsgType : : Ok , NSLOCTEXT ( " UnrealEd " , " LevelHasNoWorldSettings " , " AddLevelToWorld: The level has no World Settings. " ) ) ;
}
}
}
2015-03-10 09:44:23 -04:00
if ( NewLevel ) // if the level was successfully added
{
FEditorDelegates : : OnAddLevelToWorld . Broadcast ( NewLevel ) ;
}
2014-03-14 14:13:41 -04:00
return NewLevel ;
}
ULevelStreaming * SetStreamingClassForLevel ( ULevelStreaming * InLevel , UClass * LevelStreamingClass )
{
check ( InLevel ) ;
const FScopedBusyCursor BusyCursor ;
// Cache off the package name, as it will be lost when unloading the level
2014-08-25 11:05:29 -04:00
const FName CachedPackageName = InLevel - > GetWorldAssetPackageFName ( ) ;
2014-03-14 14:13:41 -04:00
// First hide and remove the level if it exists
ULevel * Level = InLevel - > GetLoadedLevel ( ) ;
check ( Level ) ;
SetLevelVisibility ( Level , false , false ) ;
check ( Level - > OwningWorld ) ;
UWorld * World = Level - > OwningWorld ;
World - > StreamingLevels . Remove ( InLevel ) ;
2014-07-16 02:59:19 -04:00
2014-03-14 14:13:41 -04:00
// re-add the level with the desired streaming class
AddLevelToWorld ( World , * ( CachedPackageName . ToString ( ) ) , LevelStreamingClass ) ;
2014-07-16 02:59:19 -04:00
// Transfer level streaming settings
2014-03-14 14:13:41 -04:00
ULevelStreaming * NewStreamingLevel = FLevelUtils : : FindStreamingLevel ( Level ) ;
if ( NewStreamingLevel )
{
NewStreamingLevel - > LevelTransform = InLevel - > LevelTransform ;
2014-07-16 02:59:19 -04:00
NewStreamingLevel - > EditorStreamingVolumes = InLevel - > EditorStreamingVolumes ;
NewStreamingLevel - > MinTimeBetweenVolumeUnloadRequests = InLevel - > MinTimeBetweenVolumeUnloadRequests ;
2014-07-28 17:16:21 -04:00
NewStreamingLevel - > LevelColor = InLevel - > LevelColor ;
2014-07-16 02:59:19 -04:00
NewStreamingLevel - > Keywords = InLevel - > Keywords ;
2014-03-14 14:13:41 -04:00
}
return NewStreamingLevel ;
}
void MakeLevelCurrent ( ULevel * InLevel )
{
// Locked levels can't be made current.
if ( ! FLevelUtils : : IsLevelLocked ( InLevel ) )
{
// Make current broadcast if it changed
if ( InLevel - > OwningWorld - > SetCurrentLevel ( InLevel ) )
{
FEditorDelegates : : NewCurrentLevel . Broadcast ( ) ;
}
// Deselect all selected builder brushes.
bool bDeselectedSomething = false ;
for ( FSelectionIterator It ( GEditor - > GetSelectedActorIterator ( ) ) ; It ; + + It )
{
AActor * Actor = static_cast < AActor * > ( * It ) ;
checkSlow ( Actor - > IsA ( AActor : : StaticClass ( ) ) ) ;
ABrush * Brush = Cast < ABrush > ( Actor ) ;
if ( Brush & & FActorEditorUtils : : IsABuilderBrush ( Actor ) )
{
GEditor - > SelectActor ( Actor , /*bInSelected=*/ false , /*bNotify=*/ false ) ;
bDeselectedSomething = true ;
}
}
// Send a selection change callback if necessary.
if ( bDeselectedSomething )
{
GEditor - > NoteSelectionChange ( ) ;
}
// Force the current level to be visible.
2014-07-15 04:48:45 -04:00
SetLevelVisibility ( InLevel , true , false ) ;
2014-03-14 14:13:41 -04:00
}
else
{
FMessageDialog : : Open ( EAppMsgType : : Ok , NSLOCTEXT ( " UnrealEd " , " Error_OperationDisallowedOnLockedLevelMakeLevelCurrent " , " MakeLevelCurrent: The requested operation could not be completed because the level is locked. " ) ) ;
}
}
/**
* Removes a LevelStreaming from the world . Returns true if the LevelStreaming was removed successfully .
*
* @ param InLevelStreaming The LevelStreaming to remove .
* @ return true if the LevelStreaming was removed successfully , false otherwise .
*/
bool PrivateRemoveInvalidLevelFromWorld ( ULevelStreaming * InLevelStreaming )
{
bool bRemovedLevelStreaming = false ;
if ( InLevelStreaming ! = NULL )
{
check ( InLevelStreaming - > GetLoadedLevel ( ) = = NULL ) ; // This method is designed to be used to remove left over references to null levels
InLevelStreaming - > Modify ( ) ;
// Disassociate the level from the volume.
for ( auto VolIter = InLevelStreaming - > EditorStreamingVolumes . CreateIterator ( ) ; VolIter ; VolIter + + )
{
ALevelStreamingVolume * LevelStreamingVolume = * VolIter ;
if ( LevelStreamingVolume )
{
LevelStreamingVolume - > Modify ( ) ;
2014-08-25 11:05:29 -04:00
LevelStreamingVolume - > StreamingLevelNames . Remove ( InLevelStreaming - > GetWorldAssetPackageFName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
// Disassociate the volumes from the level.
InLevelStreaming - > EditorStreamingVolumes . Empty ( ) ;
UWorld * OwningWorld = Cast < UWorld > ( InLevelStreaming - > GetOuter ( ) ) ;
if ( OwningWorld ! = NULL )
{
OwningWorld - > StreamingLevels . Remove ( InLevelStreaming ) ;
OwningWorld - > RefreshStreamingLevels ( ) ;
bRemovedLevelStreaming = true ;
}
}
return bRemovedLevelStreaming ;
}
bool RemoveInvalidLevelFromWorld ( ULevelStreaming * InLevelStreaming )
{
bool bRemoveSuccessful = PrivateRemoveInvalidLevelFromWorld ( InLevelStreaming ) ;
if ( bRemoveSuccessful )
{
// Redraw the main editor viewports.
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
// refresh editor windows
FEditorDelegates : : RefreshAllBrowsers . Broadcast ( ) ;
// Update selection for any selected actors that were in the level and are no longer valid
GEditor - > NoteSelectionChange ( ) ;
// Collect garbage to clear out the destroyed level
CollectGarbage ( GARBAGE_COLLECTION_KEEPFLAGS ) ;
}
return bRemoveSuccessful ;
}
bool RemoveLevelFromWorld ( ULevel * InLevel )
{
2015-03-17 23:20:56 -04:00
if ( GEditor - > Layers . IsValid ( ) )
{
GEditor - > Layers - > RemoveLevelLayerInformation ( InLevel ) ;
}
2014-03-14 14:13:41 -04:00
GEditor - > CloseEditedWorldAssets ( CastChecked < UWorld > ( InLevel - > GetOuter ( ) ) ) ;
2014-06-11 11:28:46 -04:00
UWorld * OwningWorld = InLevel - > OwningWorld ;
2014-06-16 05:04:05 -04:00
const FName LevelPackageName = InLevel - > GetOutermost ( ) - > GetFName ( ) ;
2015-03-31 20:12:31 -04:00
const bool bRemovingCurrentLevel = InLevel - > IsCurrentLevel ( ) ;
2014-03-14 14:13:41 -04:00
const bool bRemoveSuccessful = PrivateRemoveLevelFromWorld ( InLevel ) ;
if ( bRemoveSuccessful )
{
2014-10-20 08:14:32 -04:00
if ( bRemovingCurrentLevel )
2014-03-14 14:13:41 -04:00
{
2014-10-20 08:14:32 -04:00
MakeLevelCurrent ( OwningWorld - > PersistentLevel ) ;
2014-03-14 14:13:41 -04:00
}
2014-11-11 10:35:51 -05:00
2014-10-20 08:15:23 -04:00
EditorDestroyLevel ( InLevel ) ;
2014-03-14 14:13:41 -04:00
// Redraw the main editor viewports.
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
// refresh editor windows
FEditorDelegates : : RefreshAllBrowsers . Broadcast ( ) ;
2014-08-06 01:03:40 -04:00
// Reset transaction buffer and run GC to clear out the destroyed level
GEditor - > Cleanse ( true , false , LOCTEXT ( " RemoveLevelTransReset " , " Removing Levels from World " ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-14 07:12:39 -04:00
// Ensure that world was removed
2014-06-16 05:04:05 -04:00
UPackage * LevelPackage = FindObjectFast < UPackage > ( NULL , LevelPackageName ) ;
if ( LevelPackage ! = nullptr )
{
2014-08-14 07:12:39 -04:00
UWorld * TheWorld = UWorld : : FindWorldInPackage ( LevelPackage - > GetOutermost ( ) ) ;
if ( TheWorld ! = nullptr )
{
StaticExec ( NULL , * FString : : Printf ( TEXT ( " OBJ REFS CLASS=%s NAME=%s shortest " ) , * TheWorld - > GetClass ( ) - > GetName ( ) , * TheWorld - > GetPathName ( ) ) ) ;
TMap < UObject * , UProperty * > Route = FArchiveTraceRoute : : FindShortestRootPath ( TheWorld , true , GARBAGE_COLLECTION_KEEPFLAGS ) ;
FString ErrorString = FArchiveTraceRoute : : PrintRootPath ( Route , TheWorld ) ;
UE_LOG ( LogStreaming , Fatal , TEXT ( " %s didn't get garbage collected! " ) LINE_TERMINATOR TEXT ( " %s " ) , * TheWorld - > GetFullName ( ) , * ErrorString ) ;
}
2014-06-16 05:04:05 -04:00
}
2014-03-14 14:13:41 -04:00
}
return bRemoveSuccessful ;
}
/**
* Removes a level from the world . Returns true if the level was removed successfully .
*
2014-10-20 08:15:23 -04:00
* @ param InLevel The level to remove from the world .
2014-03-14 14:13:41 -04:00
* @ return true if the level was removed successfully , false otherwise .
*/
2014-10-20 08:15:23 -04:00
bool PrivateRemoveLevelFromWorld ( ULevel * InLevel )
2014-03-14 14:13:41 -04:00
{
2014-10-20 08:15:23 -04:00
if ( ! InLevel | | InLevel - > IsPersistentLevel ( ) )
2014-03-14 14:13:41 -04:00
{
return false ;
}
2014-10-20 08:15:23 -04:00
if ( FLevelUtils : : IsLevelLocked ( InLevel ) )
2014-03-14 14:13:41 -04:00
{
FMessageDialog : : Open ( EAppMsgType : : Ok , NSLOCTEXT ( " UnrealEd " , " Error_OperationDisallowedOnLockedLevelRemoveLevelFromWorld " , " RemoveLevelFromWorld: The requested operation could not be completed because the level is locked. " ) ) ;
return false ;
}
int32 StreamingLevelIndex = INDEX_NONE ;
2014-10-20 08:15:23 -04:00
for ( int32 LevelIndex = 0 ; LevelIndex < InLevel - > OwningWorld - > StreamingLevels . Num ( ) ; + + LevelIndex )
2014-03-14 14:13:41 -04:00
{
2014-10-20 08:15:23 -04:00
ULevelStreaming * StreamingLevel = InLevel - > OwningWorld - > StreamingLevels [ LevelIndex ] ;
if ( StreamingLevel & & StreamingLevel - > GetLoadedLevel ( ) = = InLevel )
2014-03-14 14:13:41 -04:00
{
StreamingLevelIndex = LevelIndex ;
break ;
}
}
if ( StreamingLevelIndex ! = INDEX_NONE )
{
2014-10-20 08:15:23 -04:00
InLevel - > OwningWorld - > StreamingLevels [ StreamingLevelIndex ] - > MarkPendingKill ( ) ;
InLevel - > OwningWorld - > StreamingLevels . RemoveAt ( StreamingLevelIndex ) ;
InLevel - > OwningWorld - > RefreshStreamingLevels ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-10-20 08:15:23 -04:00
else if ( InLevel - > bIsVisible )
2014-03-14 14:13:41 -04:00
{
2014-10-20 08:15:23 -04:00
InLevel - > OwningWorld - > RemoveFromWorld ( InLevel ) ;
check ( InLevel - > bIsVisible = = false ) ;
2014-03-14 14:13:41 -04:00
}
InLevel - > ReleaseRenderingResources ( ) ;
2014-05-07 09:39:27 -04:00
IStreamingManager : : Get ( ) . RemoveLevel ( InLevel ) ;
2014-03-14 14:13:41 -04:00
UWorld * World = InLevel - > OwningWorld ;
World - > RemoveLevel ( InLevel ) ;
InLevel - > ClearLevelComponents ( ) ;
2014-10-20 08:14:32 -04:00
// remove all group actors from the world in the level we are removing
// otherwise, this will cause group actors to not be garbage collected
for ( int32 GroupIndex = World - > ActiveGroupActors . Num ( ) - 1 ; GroupIndex > = 0 ; - - GroupIndex )
{
AGroupActor * GroupActor = Cast < AGroupActor > ( World - > ActiveGroupActors [ GroupIndex ] ) ;
if ( GroupActor & & GroupActor - > IsInLevel ( InLevel ) )
{
World - > ActiveGroupActors . RemoveAt ( GroupIndex ) ;
}
}
2015-03-02 04:32:26 -05:00
// Mark all model components as pending kill so GC deletes references to them.
for ( UModelComponent * ModelComponent : InLevel - > ModelComponents )
2014-03-14 14:13:41 -04:00
{
2015-03-02 04:32:26 -05:00
if ( ModelComponent ! = nullptr )
2014-03-14 14:13:41 -04:00
{
2015-03-02 04:32:26 -05:00
ModelComponent - > MarkPendingKill ( ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-02 04:32:26 -05:00
// Mark all actors and their components as pending kill so GC will delete references to them.
for ( AActor * Actor : InLevel - > Actors )
2014-03-14 14:13:41 -04:00
{
2015-03-02 04:32:26 -05:00
if ( Actor ! = nullptr )
{
Actor - > MarkComponentsAsPendingKill ( ) ;
Actor - > MarkPendingKill ( ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-10-20 08:15:23 -04:00
World - > MarkPackageDirty ( ) ;
World - > BroadcastLevelsChanged ( ) ;
return true ;
}
bool EditorDestroyLevel ( ULevel * InLevel )
{
UWorld * World = InLevel - > OwningWorld ;
2014-03-14 14:13:41 -04:00
InLevel - > GetOuter ( ) - > MarkPendingKill ( ) ;
2014-09-25 17:33:22 -04:00
InLevel - > MarkPendingKill ( ) ;
2014-10-20 08:15:23 -04:00
InLevel - > GetOuter ( ) - > ClearFlags ( RF_Public | RF_Standalone ) ;
2014-09-25 17:33:22 -04:00
UPackage * Package = Cast < UPackage > ( InLevel - > GetOutermost ( ) ) ;
2014-10-20 08:15:23 -04:00
// We want to unconditionally destroy the level, so clear the dirty flag here so it can be unloaded successfully
2014-09-25 17:33:22 -04:00
Package - > SetDirtyFlag ( false ) ;
TArray < UPackage * > Packages ;
Packages . Add ( Package ) ;
if ( ! PackageTools : : UnloadPackages ( Packages ) )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " Package " ) , FText : : FromString ( Package - > GetName ( ) ) ) ;
FMessageDialog : : Open ( EAppMsgType : : Ok , FText : : Format ( LOCTEXT ( " UnloadPackagesFail " , " Unable to unload package '{Package}'. " ) , Args ) ) ;
2014-10-20 08:15:23 -04:00
return false ;
2014-09-25 17:33:22 -04:00
}
2014-06-16 05:04:05 -04:00
2014-03-14 14:13:41 -04:00
return true ;
}
ULevel * CreateNewLevel ( UWorld * InWorld , bool bMoveSelectedActorsIntoNewLevel , UClass * LevelStreamingClass , const FString & DefaultFilename )
{
// Editor modes cannot be active when any level saving occurs.
2014-07-31 06:08:01 -04:00
GLevelEditorModeTools ( ) . DeactivateAllModes ( ) ;
2014-03-14 14:13:41 -04:00
2014-05-29 17:35:33 -04:00
UWorld * NewWorld = nullptr ;
2014-08-13 15:24:26 -04:00
if ( UEditorEngine : : IsUsingWorldAssets ( ) )
2014-05-29 17:35:33 -04:00
{
// Create a new world
2015-02-03 05:40:57 -05:00
UWorldFactory * Factory = NewObject < UWorldFactory > ( ) ;
2014-05-29 17:35:33 -04:00
Factory - > WorldType = EWorldType : : Inactive ;
UPackage * Pkg = CreatePackage ( NULL , NULL ) ;
FName WorldName ( TEXT ( " NewWorld " ) ) ;
EObjectFlags Flags = RF_Public | RF_Standalone ;
NewWorld = CastChecked < UWorld > ( Factory - > FactoryCreateNew ( UWorld : : StaticClass ( ) , Pkg , WorldName , Flags , NULL , GWarn ) ) ;
if ( NewWorld )
{
FAssetRegistryModule : : AssetCreated ( NewWorld ) ;
}
}
else
{
// Create a new world - so we can 'borrow' its level
NewWorld = UWorld : : CreateWorld ( EWorldType : : None , false ) ;
check ( NewWorld ) ;
}
2014-03-14 14:13:41 -04:00
// Save the new world to disk.
2014-05-29 17:35:33 -04:00
const bool bNewWorldSaved = FEditorFileUtils : : SaveLevel ( NewWorld - > PersistentLevel , DefaultFilename ) ;
2014-03-14 14:13:41 -04:00
FString NewPackageName ;
if ( bNewWorldSaved )
{
2014-05-29 17:35:33 -04:00
NewPackageName = NewWorld - > GetOutermost ( ) - > GetName ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-13 15:24:26 -04:00
if ( ! UEditorEngine : : IsUsingWorldAssets ( ) )
2014-05-29 17:35:33 -04:00
{
// Destroy the new world we created and collect the garbage
NewWorld - > DestroyWorld ( false ) ;
CollectGarbage ( GARBAGE_COLLECTION_KEEPFLAGS ) ;
}
2014-03-14 14:13:41 -04:00
// If the new world was saved successfully, import it as a streaming level.
ULevel * NewLevel = NULL ;
if ( bNewWorldSaved )
{
NewLevel = AddLevelToWorld ( InWorld , * NewPackageName , LevelStreamingClass ) ;
// If we are moving the selected actors to the new level move them now
if ( bMoveSelectedActorsIntoNewLevel )
{
GEditor - > MoveSelectedActorsToLevel ( NewLevel ) ;
}
// Finally make the new level the current one
InWorld - > SetCurrentLevel ( NewLevel ) ;
}
// Broadcast the levels have changed (new style)
InWorld - > BroadcastLevelsChanged ( ) ;
return NewLevel ;
}
void DeselectAllSurfacesInLevel ( ULevel * InLevel )
{
if ( InLevel )
{
UModel * Model = InLevel - > Model ;
for ( int32 SurfaceIndex = 0 ; SurfaceIndex < Model - > Surfs . Num ( ) ; + + SurfaceIndex )
{
FBspSurf & Surf = Model - > Surfs [ SurfaceIndex ] ;
if ( Surf . PolyFlags & PF_Selected )
{
Model - > ModifySurf ( SurfaceIndex , false ) ;
Surf . PolyFlags & = ~ PF_Selected ;
}
}
}
}
void SetLevelVisibility ( ULevel * Level , bool bShouldBeVisible , bool bForceLayersVisible )
{
// Nothing to do
if ( Level = = NULL )
{
return ;
}
// Handle the case of the p-level
// The p-level can't be unloaded, so its actors/BSP should just be temporarily hidden/unhidden
// Also, intentionally do not force layers visible for the p-level
if ( Level - > IsPersistentLevel ( ) )
{
//create a transaction so we can undo the visibilty toggle
const FScopedTransaction Transaction ( LOCTEXT ( " ToggleLevelVisibility " , " Toggle Level Visibility " ) ) ;
if ( Level - > bIsVisible ! = bShouldBeVisible )
{
Level - > Modify ( ) ;
}
// Set the visibility of each actor in the p-level
for ( TArray < AActor * > : : TIterator PLevelActorIter ( Level - > Actors ) ; PLevelActorIter ; + + PLevelActorIter )
{
AActor * CurActor = * PLevelActorIter ;
if ( CurActor & & ! FActorEditorUtils : : IsABuilderBrush ( CurActor ) & & CurActor - > bHiddenEdLevel = = bShouldBeVisible )
{
CurActor - > Modify ( ) ;
CurActor - > bHiddenEdLevel = ! bShouldBeVisible ;
CurActor - > RegisterAllComponents ( ) ;
CurActor - > MarkComponentsRenderStateDirty ( ) ;
}
}
// Set the visibility of each BSP surface in the p-level
UModel * CurLevelModel = Level - > Model ;
if ( CurLevelModel )
{
CurLevelModel - > Modify ( ) ;
for ( TArray < FBspSurf > : : TIterator SurfaceIterator ( CurLevelModel - > Surfs ) ; SurfaceIterator ; + + SurfaceIterator )
{
FBspSurf & CurSurf = * SurfaceIterator ;
CurSurf . bHiddenEdLevel = ! bShouldBeVisible ;
}
}
// Add/remove model components from the scene
for ( int32 ComponentIndex = 0 ; ComponentIndex < Level - > ModelComponents . Num ( ) ; ComponentIndex + + )
{
UModelComponent * CurLevelModelCmp = Level - > ModelComponents [ ComponentIndex ] ;
if ( CurLevelModelCmp )
{
2015-03-24 15:51:28 -04:00
if ( bShouldBeVisible )
2014-03-14 14:13:41 -04:00
{
CurLevelModelCmp - > RegisterComponentWithWorld ( Level - > OwningWorld ) ;
}
else if ( ! bShouldBeVisible & & CurLevelModelCmp - > IsRegistered ( ) )
{
CurLevelModelCmp - > UnregisterComponent ( ) ;
}
}
}
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
}
else
{
ULevelStreaming * StreamingLevel = NULL ;
if ( Level - > OwningWorld = = NULL | | Level - > OwningWorld - > PersistentLevel ! = Level )
{
StreamingLevel = FLevelUtils : : FindStreamingLevel ( Level ) ;
}
//create a transaction so we can undo the visibilty toggle
const FScopedTransaction Transaction ( LOCTEXT ( " ToggleLevelVisibility " , " Toggle Level Visibility " ) ) ;
// Handle the case of a streaming level
if ( StreamingLevel )
{
// We need to set the RF_Transactional to make a streaming level serialize itself. so store the original ones, set the flag, and put the original flags back when done
EObjectFlags cachedFlags = StreamingLevel - > GetFlags ( ) ;
StreamingLevel - > SetFlags ( RF_Transactional ) ;
StreamingLevel - > Modify ( ) ;
StreamingLevel - > SetFlags ( cachedFlags ) ;
// Set the visibility state for this streaming level.
StreamingLevel - > bShouldBeVisibleInEditor = bShouldBeVisible ;
}
2015-03-17 23:20:56 -04:00
if ( ! bShouldBeVisible & & GEditor - > Layers . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
GEditor - > Layers - > RemoveLevelLayerInformation ( Level ) ;
}
// UpdateLevelStreaming sets Level->bIsVisible directly, so we need to make sure it gets saved to the transaction buffer.
if ( Level - > bIsVisible ! = bShouldBeVisible )
{
Level - > Modify ( ) ;
}
if ( StreamingLevel )
{
Level - > OwningWorld - > FlushLevelStreaming ( ) ;
// In the Editor we expect this operation will complete in a single call
check ( Level - > bIsVisible = = bShouldBeVisible ) ;
}
else if ( Level - > OwningWorld ! = NULL )
{
// In case we level has no associated StreamingLevel, remove or add to world directly
if ( bShouldBeVisible )
{
if ( ! Level - > bIsVisible )
{
Level - > OwningWorld - > AddToWorld ( Level ) ;
}
}
else
{
Level - > OwningWorld - > RemoveFromWorld ( Level ) ;
}
// In the Editor we expect this operation will complete in a single call
check ( Level - > bIsVisible = = bShouldBeVisible ) ;
}
2015-03-17 23:20:56 -04:00
if ( bShouldBeVisible & & GEditor - > Layers . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
GEditor - > Layers - > AddLevelLayerInformation ( Level ) ;
}
// Force the level's layers to be visible, if desired
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
// Iterate over the level's actors, making a list of their layers and unhiding the layers.
TTransArray < AActor * > & Actors = Level - > Actors ;
for ( int32 ActorIndex = 0 ; ActorIndex < Actors . Num ( ) ; + + ActorIndex )
{
AActor * Actor = Actors [ ActorIndex ] ;
if ( Actor )
{
bool bModified = false ;
2015-03-17 23:20:56 -04:00
if ( bShouldBeVisible & & bForceLayersVisible & &
GEditor - > Layers . IsValid ( ) & &
GEditor - > Layers - > IsActorValidForLayer ( Actor ) )
2014-03-14 14:13:41 -04:00
{
// Make the actor layer visible, if it's not already.
if ( Actor - > bHiddenEdLayer )
{
bModified = Actor - > Modify ( ) ;
Actor - > bHiddenEdLayer = false ;
}
const bool bIsVisible = true ;
GEditor - > Layers - > SetLayersVisibility ( Actor - > Layers , bIsVisible ) ;
}
// Set the visibility of each actor in the streaming level
if ( ! FActorEditorUtils : : IsABuilderBrush ( Actor ) & & Actor - > bHiddenEdLevel = = bShouldBeVisible )
{
if ( ! bModified )
{
bModified = Actor - > Modify ( ) ;
}
Actor - > bHiddenEdLevel = ! bShouldBeVisible ;
if ( bShouldBeVisible )
{
Actor - > ReregisterAllComponents ( ) ;
}
else
{
Actor - > UnregisterAllComponents ( ) ;
}
}
}
}
}
FEditorDelegates : : RefreshLayerBrowser . Broadcast ( ) ;
// Notify the Scene Outliner, as new Actors may be present in the world.
GEngine - > BroadcastLevelActorListChanged ( ) ;
// If the level is being hidden, deselect actors and surfaces that belong to this level.
if ( ! bShouldBeVisible )
{
USelection * SelectedActors = GEditor - > GetSelectedActors ( ) ;
SelectedActors - > Modify ( ) ;
TTransArray < AActor * > & Actors = Level - > Actors ;
for ( int32 ActorIndex = 0 ; ActorIndex < Actors . Num ( ) ; + + ActorIndex )
{
AActor * Actor = Actors [ ActorIndex ] ;
if ( Actor )
{
SelectedActors - > Deselect ( Actor ) ;
}
}
DeselectAllSurfacesInLevel ( Level ) ;
// Tell the editor selection status was changed.
GEditor - > NoteSelectionChange ( ) ;
}
Level - > bIsVisible = bShouldBeVisible ;
}
/**
* Assembles the set of all referenced worlds .
*
* @ param OutWorlds [ out ] The set of referenced worlds .
* @ param bIncludeGWorld If true , include GWorld in the output list .
* @ param bOnlyEditorVisible If true , only sub - levels that should be visible in - editor are included
*/
void GetWorlds ( UWorld * InWorld , TArray < UWorld * > & OutWorlds , bool bIncludeInWorld , bool bOnlyEditorVisible )
{
OutWorlds . Empty ( ) ;
2015-06-25 10:17:25 -04:00
if ( ! InWorld )
{
return ;
}
2014-03-14 14:13:41 -04:00
if ( bIncludeInWorld )
{
OutWorlds . AddUnique ( InWorld ) ;
}
// Iterate over the world's level array to find referenced levels ("worlds"). We don't
for ( int32 LevelIndex = 0 ; LevelIndex < InWorld - > StreamingLevels . Num ( ) ; + + LevelIndex )
{
ULevelStreaming * StreamingLevel = InWorld - > StreamingLevels [ LevelIndex ] ;
if ( StreamingLevel )
{
// If we asked for only sub-levels that are editor-visible, then limit our results appropriately
bool bShouldAlwaysBeLoaded = false ; // Cast< ULevelStreamingAlwaysLoaded >( StreamingLevel ) != NULL;
if ( ! bOnlyEditorVisible | | bShouldAlwaysBeLoaded | | StreamingLevel - > bShouldBeVisibleInEditor )
{
const ULevel * Level = StreamingLevel - > GetLoadedLevel ( ) ;
// This should always be the case for valid level names as the Editor preloads all packages.
if ( Level ! = NULL )
{
// Newer levels have their packages' world as the outer.
UWorld * World = Cast < UWorld > ( Level - > GetOuter ( ) ) ;
if ( World ! = NULL )
{
OutWorlds . AddUnique ( World ) ;
}
}
}
}
}
// Levels can be loaded directly without StreamingLevel facilities
for ( int32 LevelIndex = 0 ; LevelIndex < InWorld - > GetLevels ( ) . Num ( ) ; + + LevelIndex )
{
ULevel * Level = InWorld - > GetLevel ( LevelIndex ) ;
if ( Level )
{
// Newer levels have their packages' world as the outer.
UWorld * World = Cast < UWorld > ( Level - > GetOuter ( ) ) ;
if ( World ! = NULL )
{
OutWorlds . AddUnique ( World ) ;
}
}
}
}
}
# undef LOCTEXT_NAMESPACE