2020-07-23 13:29:05 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LevelEditorSubsystem.h"
2021-09-27 19:54:25 -04:00
# include "Editor.h"
2020-07-23 13:29:05 -04:00
# include "Editor/UnrealEdEngine.h"
# include "EditorScriptingHelpers.h"
2021-01-11 09:19:43 -04:00
# include "Elements/Framework/TypedElementSelectionSet.h"
2021-09-27 19:54:25 -04:00
# include "Engine/MapBuildDataRegistry.h"
# include "FileHelpers.h"
# include "IAssetViewport.h"
# include "LevelEditor.h"
# include "LevelEditorMenuContext.h"
# include "Modules/ModuleManager.h"
# include "SLevelViewport.h"
# include "Subsystems/UnrealEditorSubsystem.h"
2021-01-11 09:19:43 -04:00
# include "ToolMenuDelegates.h"
2021-09-27 19:54:25 -04:00
# include "ToolMenus.h"
# include "UnrealEdGlobals.h"
2021-10-12 21:21:22 -04:00
# include "EditorModeManager.h"
2022-03-08 09:40:27 -05:00
# include "Styling/SlateIconFinder.h"
# include "Subsystems/ActorEditorContextSubsystem.h"
# include "LevelInstance/LevelInstanceSubsystem.h"
2022-03-29 09:19:22 -04:00
# include "LevelInstance/LevelInstanceInterface.h"
2022-03-08 09:40:27 -05:00
# include "ClassIconFinder.h"
2022-05-17 14:36:34 -04:00
# include "LightingBuildOptions.h"
2022-10-26 12:57:32 -04:00
# include "Widgets/Images/SImage.h"
# include "Widgets/Input/SComboButton.h"
2020-07-23 13:29:05 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LevelEditorSubsystem , Log , All ) ;
2021-01-11 09:19:43 -04:00
# define LOCTEXT_NAMESPACE "LevelEditorSubsystem"
2021-02-24 17:53:02 -04:00
namespace InternalEditorLevelLibrary
{
TSharedPtr < SLevelViewport > GetLevelViewport ( const FName & ViewportConfigKey )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < ILevelEditor > LevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) ;
if ( LevelEditor . IsValid ( ) )
{
for ( TSharedPtr < SLevelViewport > LevelViewport : LevelEditor - > GetViewports ( ) )
{
if ( LevelViewport . IsValid ( ) & & LevelViewport - > GetConfigKey ( ) = = ViewportConfigKey )
{
return LevelViewport ;
}
}
TSharedPtr < SLevelViewport > ActiveLevelViewport = LevelEditor - > GetActiveViewportInterface ( ) ;
return ActiveLevelViewport ;
}
return nullptr ;
}
2023-05-30 06:44:15 -04:00
bool IsEditingLevelInstanceCurrentLevel ( UWorld * InWorld )
{
if ( InWorld )
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = InWorld - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
if ( ILevelInstanceInterface * LevelInstance = LevelInstanceSubsystem - > GetEditingLevelInstance ( ) )
{
return LevelInstanceSubsystem - > GetLevelInstanceLevel ( LevelInstance ) = = InWorld - > GetCurrentLevel ( ) ;
}
}
}
return false ;
}
AActor * GetEditingLevelInstance ( UWorld * InWorld )
{
ULevelInstanceSubsystem * LevelInstanceSubsystem = InWorld ? InWorld - > GetSubsystem < ULevelInstanceSubsystem > ( ) : nullptr ;
return LevelInstanceSubsystem ? Cast < AActor > ( LevelInstanceSubsystem - > GetEditingLevelInstance ( ) ) : nullptr ;
}
bool IsActorEditorContextVisible ( UWorld * InWorld )
{
return InWorld & & ( InWorld - > GetCurrentLevel ( ) - > OwningWorld - > GetLevels ( ) . Num ( ) > 1 & & ( ! InWorld - > IsPartitionedWorld ( ) | | GetEditingLevelInstance ( InWorld ) ! = nullptr ) ) ;
}
2021-02-24 17:53:02 -04:00
}
2021-01-11 09:19:43 -04:00
void ULevelEditorSubsystem : : Initialize ( FSubsystemCollectionBase & Collection )
{
2022-03-08 09:40:27 -05:00
Collection . InitializeDependency < UActorEditorContextSubsystem > ( ) ;
2021-01-11 09:19:43 -04:00
UToolMenus : : RegisterStartupCallback ( FSimpleMulticastDelegate : : FDelegate : : CreateUObject ( this , & ULevelEditorSubsystem : : ExtendQuickActionMenu ) ) ;
2022-03-08 09:40:27 -05:00
UActorEditorContextSubsystem : : Get ( ) - > RegisterClient ( this ) ;
FWorldDelegates : : LevelAddedToWorld . AddUObject ( this , & ULevelEditorSubsystem : : OnLevelAddedOrRemoved ) ;
FWorldDelegates : : LevelRemovedFromWorld . AddUObject ( this , & ULevelEditorSubsystem : : OnLevelAddedOrRemoved ) ;
2022-06-22 10:26:53 -04:00
FWorldDelegates : : OnCurrentLevelChanged . AddUObject ( this , & ULevelEditorSubsystem : : OnCurrentLevelChanged ) ;
2022-11-07 13:33:27 -05:00
FEditorDelegates : : PreSaveWorldWithContext . AddUObject ( this , & ULevelEditorSubsystem : : HandleOnPreSaveWorldWithContext ) ;
FEditorDelegates : : PostSaveWorldWithContext . AddUObject ( this , & ULevelEditorSubsystem : : HandleOnPostSaveWorldWithContext ) ;
FEditorDelegates : : OnEditorCameraMoved . AddUObject ( this , & ULevelEditorSubsystem : : HandleOnEditorCameraMoved ) ;
FEditorDelegates : : MapChange . AddUObject ( this , & ULevelEditorSubsystem : : HandleOnMapChanged ) ;
FEditorDelegates : : OnMapOpened . AddUObject ( this , & ULevelEditorSubsystem : : HandleOnMapOpened ) ;
2021-01-11 09:19:43 -04:00
}
void ULevelEditorSubsystem : : Deinitialize ( )
{
2022-03-08 09:40:27 -05:00
UActorEditorContextSubsystem : : Get ( ) - > UnregisterClient ( this ) ;
FWorldDelegates : : LevelAddedToWorld . RemoveAll ( this ) ;
FWorldDelegates : : LevelRemovedFromWorld . RemoveAll ( this ) ;
2022-06-22 10:26:53 -04:00
FWorldDelegates : : OnCurrentLevelChanged . RemoveAll ( this ) ;
2021-01-11 09:19:43 -04:00
UToolMenus : : UnRegisterStartupCallback ( this ) ;
UToolMenus : : UnregisterOwner ( this ) ;
2022-11-07 13:33:27 -05:00
FEditorDelegates : : PreSaveWorldWithContext . RemoveAll ( this ) ;
FEditorDelegates : : PostSaveWorldWithContext . RemoveAll ( this ) ;
FEditorDelegates : : OnEditorCameraMoved . RemoveAll ( this ) ;
FEditorDelegates : : MapChange . RemoveAll ( this ) ;
FEditorDelegates : : OnMapOpened . RemoveAll ( this ) ;
2021-01-11 09:19:43 -04:00
}
void ULevelEditorSubsystem : : ExtendQuickActionMenu ( )
{
FToolMenuOwnerScoped MenuOwner ( this ) ;
UToolMenu * Menu = UToolMenus : : Get ( ) - > ExtendMenu ( " LevelEditor.InViewportPanel " ) ;
{
FToolMenuSection & Section = Menu - > FindOrAddSection ( " QuickActions " ) ;
FToolMenuEntry & Entry = Section . AddDynamicEntry ( " LevelActors " , FNewToolMenuSectionDelegate : : CreateLambda ( [ this ] ( FToolMenuSection & InSection )
{
UQuickActionMenuContext * Context = InSection . FindContext < UQuickActionMenuContext > ( ) ;
if ( Context & & Context - > CurrentSelection & & Context - > CurrentSelection - > GetElementList ( ) - > Num ( ) = = 1 )
{
FToolUIAction PilotActorAction ;
PilotActorAction . ExecuteAction = FToolMenuExecuteAction : : CreateUObject ( this , & ULevelEditorSubsystem : : PilotLevelActor ) ;
FToolMenuEntry & PilotActorEntry = InSection . AddEntry ( FToolMenuEntry : : InitToolBarButton (
" PilotActor " ,
PilotActorAction ,
LOCTEXT ( " PilotSelectedActor " , " Pilot Selected Actor " ) ,
LOCTEXT ( " PilotSelectedActorToolTip " , " Move the selected actor around using the viewport controls, and bind the viewport to the actor's location and orientation. " ) ,
FSlateIcon ( FAppStyle : : Get ( ) . GetStyleSetName ( ) , " LevelViewport.PilotSelectedActor " )
) ) ;
// LevelEditorSubsystem.AddKeybindFromCommand(FLightEditingCommands::Get().SwapLightType);
}
} ) ) ;
}
}
void ULevelEditorSubsystem : : PilotLevelActor ( const FToolMenuContext & InContext )
{
UQuickActionMenuContext * QuickMenuContext = InContext . FindContext < UQuickActionMenuContext > ( ) ;
AActor * SelectedActor = QuickMenuContext - > CurrentSelection - > GetTopSelectedObject < AActor > ( ) ;
PilotLevelActor ( SelectedActor ) ;
}
2021-02-24 17:53:02 -04:00
void ULevelEditorSubsystem : : PilotLevelActor ( AActor * ActorToPilot , FName ViewportConfigKey )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( LevelViewport . IsValid ( ) )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
FLevelEditorViewportClient & LevelViewportClient = LevelViewport - > GetLevelViewportClient ( ) ;
2020-07-23 13:29:05 -04:00
LevelViewportClient . SetActorLock ( ActorToPilot ) ;
if ( LevelViewportClient . IsPerspective ( ) & & LevelViewportClient . GetActiveActorLock ( ) . IsValid ( ) )
{
LevelViewportClient . MoveCameraToLockedActor ( ) ;
}
}
}
2021-02-24 17:53:02 -04:00
void ULevelEditorSubsystem : : EjectPilotLevelActor ( FName ViewportConfigKey )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( LevelViewport . IsValid ( ) )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
FLevelEditorViewportClient & LevelViewportClient = LevelViewport - > GetLevelViewportClient ( ) ;
2020-07-23 13:29:05 -04:00
if ( AActor * LockedActor = LevelViewportClient . GetActiveActorLock ( ) . Get ( ) )
{
//// Check to see if the locked actor was previously overriding the camera settings
//if (CanGetCameraInformationFromActor(LockedActor))
//{
// // Reset the settings
// LevelViewportClient.ViewFOV = LevelViewportClient.FOVAngle;
//}
LevelViewportClient . SetActorLock ( nullptr ) ;
// remove roll and pitch from camera when unbinding from actors
GEditor - > RemovePerspectiveViewRotation ( true , true , false ) ;
}
}
}
2022-02-04 17:41:47 -05:00
AActor * ULevelEditorSubsystem : : GetPilotLevelActor ( FName ViewportConfigKey )
{
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( ! LevelViewport . IsValid ( ) )
{
return nullptr ;
}
FLevelEditorViewportClient & LevelViewportClient = LevelViewport - > GetLevelViewportClient ( ) ;
if ( AActor * CinematicActorLock = LevelViewportClient . GetCinematicActorLock ( ) . GetLockedActor ( ) )
{
return CinematicActorLock ;
}
return LevelViewportClient . GetActiveActorLock ( ) . Get ( ) ;
}
2020-07-23 13:29:05 -04:00
void ULevelEditorSubsystem : : EditorPlaySimulate ( )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < IAssetViewport > ActiveLevelViewport = LevelEditorModule . GetFirstActiveViewport ( ) ;
if ( ActiveLevelViewport . IsValid ( ) )
{
FRequestPlaySessionParams SessionParams ;
SessionParams . WorldType = EPlaySessionWorldType : : SimulateInEditor ;
SessionParams . DestinationSlateViewport = ActiveLevelViewport ;
GUnrealEd - > RequestPlaySession ( SessionParams ) ;
}
}
void ULevelEditorSubsystem : : EditorInvalidateViewports ( )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < SLevelViewport > ActiveLevelViewport = LevelEditorModule . GetFirstActiveLevelViewport ( ) ;
if ( ActiveLevelViewport . IsValid ( ) )
{
FLevelEditorViewportClient & LevelViewportClient = ActiveLevelViewport - > GetLevelViewportClient ( ) ;
LevelViewportClient . Invalidate ( ) ;
}
}
2021-02-24 17:53:02 -04:00
void ULevelEditorSubsystem : : EditorSetGameView ( bool bGameView , FName ViewportConfigKey )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( LevelViewport . IsValid ( ) )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
if ( LevelViewport - > IsInGameView ( ) ! = bGameView )
2020-07-23 13:29:05 -04:00
{
2021-02-24 17:53:02 -04:00
LevelViewport - > ToggleGameView ( ) ;
2020-07-23 13:29:05 -04:00
}
}
}
2021-02-24 17:53:02 -04:00
bool ULevelEditorSubsystem : : EditorGetGameView ( FName ViewportConfigKey )
{
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( LevelViewport . IsValid ( ) )
{
return LevelViewport - > IsInGameView ( ) ;
}
return false ;
}
2021-01-19 12:29:58 -04:00
void ULevelEditorSubsystem : : EditorRequestEndPlay ( )
{
GUnrealEd - > RequestEndPlayMap ( ) ;
}
bool ULevelEditorSubsystem : : IsInPlayInEditor ( ) const
{
return GUnrealEd - > IsPlayingSessionInEditor ( ) ;
}
2021-02-24 17:53:02 -04:00
TArray < FName > ULevelEditorSubsystem : : GetViewportConfigKeys ( )
{
TArray < FName > ViewportConfigKeys ;
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < ILevelEditor > LevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) ;
if ( LevelEditor . IsValid ( ) )
{
for ( TSharedPtr < SLevelViewport > LevelViewport : LevelEditor - > GetViewports ( ) )
{
if ( LevelViewport . IsValid ( ) )
{
ViewportConfigKeys . Add ( LevelViewport - > GetConfigKey ( ) ) ;
}
}
}
return ViewportConfigKeys ;
}
FName ULevelEditorSubsystem : : GetActiveViewportConfigKey ( )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < ILevelEditor > LevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) ;
if ( LevelEditor . IsValid ( ) )
{
TSharedPtr < SLevelViewport > ActiveLevelViewport = LevelEditor - > GetActiveViewportInterface ( ) ;
if ( ActiveLevelViewport . IsValid ( ) )
{
return ActiveLevelViewport - > GetConfigKey ( ) ;
}
}
return NAME_None ;
}
void ULevelEditorSubsystem : : SetAllowsCinematicControl ( bool bAllow , FName ViewportConfigKey )
{
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( LevelViewport . IsValid ( ) )
{
return LevelViewport - > SetAllowsCinematicControl ( bAllow ) ;
}
}
bool ULevelEditorSubsystem : : GetAllowsCinematicControl ( FName ViewportConfigKey )
{
TSharedPtr < SLevelViewport > LevelViewport = InternalEditorLevelLibrary : : GetLevelViewport ( ViewportConfigKey ) ;
if ( LevelViewport . IsValid ( ) )
{
return LevelViewport - > GetAllowsCinematicControl ( ) ;
}
return false ;
}
2020-07-23 13:29:05 -04:00
/**
*
* Editor Scripting | Level
*
* */
bool ULevelEditorSubsystem : : NewLevel ( const FString & AssetPath )
{
TGuardValue < bool > UnattendedScriptGuard ( GIsRunningUnattendedScript , true ) ;
if ( ! EditorScriptingHelpers : : CheckIfInEditorAndPIE ( ) )
{
return false ;
}
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
FString FailureReason ;
FString ObjectPath = EditorScriptingHelpers : : ConvertAnyPathToObjectPath ( AssetPath , FailureReason ) ;
if ( ObjectPath . IsEmpty ( ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevel. Failed to create the level. %s " ) , * FailureReason ) ;
return false ;
}
if ( ! EditorScriptingHelpers : : IsAValidPathForCreateNewAsset ( ObjectPath , FailureReason ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevel. Failed to validate the destination. %s " ) , * FailureReason ) ;
return false ;
}
2021-11-07 23:43:01 -05:00
if ( FPackageName : : DoesPackageExist ( ObjectPath ) )
2020-07-23 13:29:05 -04:00
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevel. Failed to validate the destination '%s'. There's alreay an asset at the destination. " ) , * ObjectPath ) ;
return false ;
}
UWorld * World = GEditor - > NewMap ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevel. Failed to create the new level. " ) ) ;
return false ;
}
FString DestinationLongPackagePath = FPackageName : : ObjectPathToPackageName ( ObjectPath ) ;
if ( ! UEditorLoadingAndSavingUtils : : SaveMap ( World , DestinationLongPackagePath ) )
{
UE_LOG ( LevelEditorSubsystem , Warning , TEXT ( " NewLevel. Failed to save the new level. " ) ) ;
return false ;
}
return true ;
}
bool ULevelEditorSubsystem : : NewLevelFromTemplate ( const FString & AssetPath , const FString & TemplateAssetPath )
{
TGuardValue < bool > UnattendedScriptGuard ( GIsRunningUnattendedScript , true ) ;
if ( ! EditorScriptingHelpers : : CheckIfInEditorAndPIE ( ) )
{
return false ;
}
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
FString FailureReason ;
FString ObjectPath = EditorScriptingHelpers : : ConvertAnyPathToObjectPath ( AssetPath , FailureReason ) ;
if ( ObjectPath . IsEmpty ( ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to create the level. %s " ) , * FailureReason ) ;
return false ;
}
if ( ! EditorScriptingHelpers : : IsAValidPathForCreateNewAsset ( ObjectPath , FailureReason ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to validate the destination. %s " ) , * FailureReason ) ;
return false ;
}
// DuplicateAsset does it, but failed with a Modal
2021-11-07 23:43:01 -05:00
if ( FPackageName : : DoesPackageExist ( ObjectPath ) )
2020-07-23 13:29:05 -04:00
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to validate the destination '%s'. There's alreay an asset at the destination. " ) , * ObjectPath ) ;
return false ;
}
FString TemplateObjectPath = EditorScriptingHelpers : : ConvertAnyPathToObjectPath ( TemplateAssetPath , FailureReason ) ;
if ( TemplateObjectPath . IsEmpty ( ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to create the level. %s " ) , * FailureReason ) ;
return false ;
}
const bool bLoadAsTemplate = true ;
// Load the template map file - passes LoadAsTemplate==true making the
// level load into an untitled package that won't save over the template
if ( ! FEditorFileUtils : : LoadMap ( * TemplateObjectPath , bLoadAsTemplate ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to create the new level from template. " ) ) ;
return false ;
}
UWorld * World = GEditor - > GetEditorWorldContext ( ) . World ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to find the new created world. " ) ) ;
return false ;
}
FString DestinationLongPackagePath = FPackageName : : ObjectPathToPackageName ( ObjectPath ) ;
if ( ! UEditorLoadingAndSavingUtils : : SaveMap ( World , DestinationLongPackagePath ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " NewLevelFromTemplate. Failed to save the new level. " ) ) ;
return false ;
}
return true ;
}
bool ULevelEditorSubsystem : : LoadLevel ( const FString & AssetPath )
{
TGuardValue < bool > UnattendedScriptGuard ( GIsRunningUnattendedScript , true ) ;
if ( ! EditorScriptingHelpers : : CheckIfInEditorAndPIE ( ) )
{
return false ;
}
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
FString FailureReason ;
FString ObjectPath = EditorScriptingHelpers : : ConvertAnyPathToObjectPath ( AssetPath , FailureReason ) ;
if ( ObjectPath . IsEmpty ( ) )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " LoadLevel. Failed to load level: %s " ) , * FailureReason ) ;
return false ;
}
return UEditorLoadingAndSavingUtils : : LoadMap ( ObjectPath ) ! = nullptr ;
}
bool ULevelEditorSubsystem : : SaveCurrentLevel ( )
{
TGuardValue < bool > UnattendedScriptGuard ( GIsRunningUnattendedScript , true ) ;
if ( ! EditorScriptingHelpers : : CheckIfInEditorAndPIE ( ) )
{
return false ;
}
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
UWorld * World = UnrealEditorSubsystem - > GetEditorWorld ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " SaveCurrentLevel. Can't save the current level because there is no world. " ) ) ;
return false ;
}
ULevel * Level = World - > GetCurrentLevel ( ) ;
if ( ! Level )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " SaveCurrentLevel. Can't save the level because there is no current level. " ) ) ;
return false ;
}
FString Filename = FEditorFileUtils : : GetFilename ( Level - > OwningWorld ) ;
if ( Filename . Len ( ) = = 0 )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " SaveCurrentLevel. Can't save the level because it doesn't have a filename. Use EditorLoadingAndSavingUtils. " ) ) ;
return false ;
}
TArray < UPackage * > MapPackages ;
MapPackages . Add ( Level - > GetOutermost ( ) ) ;
if ( Level - > MapBuildData )
{
MapPackages . AddUnique ( Level - > MapBuildData - > GetOutermost ( ) ) ;
}
// Checkout without a prompt
TArray < UPackage * > * PackagesCheckedOut = nullptr ;
const bool bErrorIfAlreadyCheckedOut = false ;
FEditorFileUtils : : CheckoutPackages ( MapPackages , PackagesCheckedOut , bErrorIfAlreadyCheckedOut ) ;
return FEditorFileUtils : : SaveLevel ( Level ) ;
}
bool ULevelEditorSubsystem : : SaveAllDirtyLevels ( )
{
TGuardValue < bool > UnattendedScriptGuard ( GIsRunningUnattendedScript , true ) ;
if ( ! EditorScriptingHelpers : : CheckIfInEditorAndPIE ( ) )
{
return false ;
}
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
UWorld * World = UnrealEditorSubsystem - > GetEditorWorld ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " SaveAllDirtyLevels. Can't save the current level because there is no world. " ) ) ;
return false ;
}
TArray < UPackage * > DirtyMapPackages ;
TArray < ULevel * > DirtyLevels ;
for ( ULevel * Level : World - > GetLevels ( ) )
{
if ( Level )
{
UPackage * OutermostPackage = Level - > GetOutermost ( ) ;
if ( OutermostPackage - > IsDirty ( ) )
{
FString Filename = FEditorFileUtils : : GetFilename ( Level - > OwningWorld ) ;
if ( Filename . Len ( ) = = 0 )
{
UE_LOG ( LevelEditorSubsystem , Warning , TEXT ( " SaveAllDirtyLevels. Can't save the level '%s' because it doesn't have a filename. Use EditorLoadingAndSavingUtils. " ) , * OutermostPackage - > GetName ( ) ) ;
continue ;
}
DirtyLevels . Add ( Level ) ;
DirtyMapPackages . Add ( OutermostPackage ) ;
if ( Level - > MapBuildData )
{
UPackage * BuiltDataPackage = Level - > MapBuildData - > GetOutermost ( ) ;
if ( BuiltDataPackage - > IsDirty ( ) & & BuiltDataPackage ! = OutermostPackage )
{
DirtyMapPackages . Add ( BuiltDataPackage ) ;
}
}
}
}
}
bool bAllSaved = true ;
if ( DirtyMapPackages . Num ( ) > 0 )
{
// Checkout without a prompt
TArray < UPackage * > * PackagesCheckedOut = nullptr ;
const bool bErrorIfAlreadyCheckedOut = false ;
FEditorFileUtils : : CheckoutPackages ( DirtyMapPackages , PackagesCheckedOut , bErrorIfAlreadyCheckedOut ) ;
for ( ULevel * Level : DirtyLevels )
{
bool bSaved = FEditorFileUtils : : SaveLevel ( Level ) ;
if ( ! bSaved )
{
UE_LOG ( LevelEditorSubsystem , Warning , TEXT ( " SaveAllDirtyLevels. Can't save the level '%s'. " ) , * World - > GetOutermost ( ) - > GetName ( ) ) ;
bAllSaved = false ;
}
}
}
else
{
UE_LOG ( LevelEditorSubsystem , Log , TEXT ( " SaveAllDirtyLevels. There is no dirty level. " ) ) ;
}
return bAllSaved ;
}
bool ULevelEditorSubsystem : : SetCurrentLevelByName ( FName LevelName )
{
TGuardValue < bool > UnattendedScriptGuard ( GIsRunningUnattendedScript , true ) ;
if ( ! EditorScriptingHelpers : : CheckIfInEditorAndPIE ( ) )
{
return false ;
}
if ( LevelName = = NAME_None )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " SetCurrentLevel. LevelName is invalid. " ) ) ;
return false ;
}
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
UWorld * World = UnrealEditorSubsystem - > GetEditorWorld ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Warning , TEXT ( " SetCurrentLevel. Can't set the current level because there is no world. " ) ) ;
return false ;
}
bool bLevelFound = false ;
const TArray < ULevel * > & AllLevels = World - > GetLevels ( ) ;
if ( AllLevels . Num ( ) > 0 )
{
FString LevelNameStr = LevelName . ToString ( ) ;
for ( ULevel * Level : AllLevels )
{
if ( FPackageName : : GetShortName ( Level - > GetOutermost ( ) ) = = LevelNameStr )
{
// SetCurrentLevel return true only if the level is changed and it's not the same as the current.
//For UEditorLevelLibrary, always return true.
World - > SetCurrentLevel ( Level ) ;
bLevelFound = true ;
break ;
}
}
}
return bLevelFound ;
2020-07-30 12:22:57 -04:00
}
ULevel * ULevelEditorSubsystem : : GetCurrentLevel ( )
{
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return nullptr ;
}
UWorld * World = UnrealEditorSubsystem - > GetEditorWorld ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " GetCurrentLevel. Can't Get the current level because there is no world. " ) ) ;
return nullptr ;
}
return World - > GetCurrentLevel ( ) ;
2021-01-11 09:19:43 -04:00
}
2021-09-27 19:54:25 -04:00
UTypedElementSelectionSet * ULevelEditorSubsystem : : GetSelectionSet ( )
{
2021-10-12 21:21:22 -04:00
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < ILevelEditor > LevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) ;
if ( LevelEditor . IsValid ( ) )
2021-09-27 19:54:25 -04:00
{
return LevelEditor - > GetMutableElementSelectionSet ( ) ;
}
return nullptr ;
}
2022-05-17 14:36:34 -04:00
bool ULevelEditorSubsystem : : BuildLightMaps ( ELightingBuildQuality Quality , bool bWithReflectionCaptures )
{
FLightingBuildOptions LightingOptions ;
LightingOptions . QualityLevel = Quality ;
UUnrealEditorSubsystem * UnrealEditorSubsystem = GEditor - > GetEditorSubsystem < UUnrealEditorSubsystem > ( ) ;
if ( ! UnrealEditorSubsystem )
{
return false ;
}
UWorld * World = UnrealEditorSubsystem - > GetEditorWorld ( ) ;
if ( ! World )
{
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " BuildLightMaps. Can't build the light maps of the current level because there is no world. " ) ) ;
return false ;
}
bool Success = false ;
auto BuildFailedDelegate = [ & World , & Success ] ( ) {
UE_LOG ( LevelEditorSubsystem , Error , TEXT ( " BuildLightMaps. Failed building lighting for %s " ) , * World - > GetOutermost ( ) - > GetName ( ) ) ;
Success = false ;
} ;
FDelegateHandle BuildFailedDelegateHandle = FEditorDelegates : : OnLightingBuildFailed . AddLambda ( BuildFailedDelegate ) ;
auto BuildSucceededDelegate = [ & World , & Success ] ( ) {
UE_LOG ( LevelEditorSubsystem , Log , TEXT ( " BuildLightMaps. Successfully built lighting for %s " ) , * World - > GetOutermost ( ) - > GetName ( ) ) ;
Success = true ;
} ;
FDelegateHandle BuildSucceededDelegateHandle = FEditorDelegates : : OnLightingBuildSucceeded . AddLambda ( BuildSucceededDelegate ) ;
UE_LOG ( LevelEditorSubsystem , Log , TEXT ( " BuildLightMaps. Start building lighting for %s " ) , * World - > GetOutermost ( ) - > GetName ( ) ) ;
GEditor - > BuildLighting ( LightingOptions ) ;
while ( GEditor - > IsLightingBuildCurrentlyRunning ( ) )
{
GEditor - > UpdateBuildLighting ( ) ;
}
if ( bWithReflectionCaptures )
{
GEditor - > BuildReflectionCaptures ( ) ;
}
FEditorDelegates : : OnLightingBuildFailed . Remove ( BuildFailedDelegateHandle ) ;
2023-03-30 16:18:32 -04:00
FEditorDelegates : : OnLightingBuildSucceeded . Remove ( BuildSucceededDelegateHandle ) ;
2022-05-17 14:36:34 -04:00
return Success ;
}
2021-10-12 21:21:22 -04:00
FEditorModeTools * ULevelEditorSubsystem : : GetLevelEditorModeManager ( )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < ILevelEditor > LevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) ;
if ( LevelEditor . IsValid ( ) & & ! IsRunningCommandlet ( ) )
{
return & LevelEditor - > GetEditorModeManager ( ) ;
}
return nullptr ;
}
2022-03-08 09:40:27 -05:00
// Widget used to show current level in viewport
class SCurrentLevelWidget : public SCompoundWidget
{
public :
SLATE_BEGIN_ARGS ( SCurrentLevelWidget ) { }
SLATE_ARGUMENT ( UWorld * , World )
SLATE_END_ARGS ( )
~ SCurrentLevelWidget ( )
{
GEditor - > GetEditorWorldContext ( ) . RemoveRef ( World ) ;
}
void Construct ( const FArguments & InArgs )
{
World = ( InArgs . _World ) ;
GEditor - > GetEditorWorldContext ( ) . AddRef ( World ) ;
CommandList = MakeShareable ( new FUICommandList ) ;
2023-05-30 06:44:15 -04:00
ChildSlot
[
SNew ( SComboButton )
. Cursor ( EMouseCursor : : Default )
. VAlign ( VAlign_Center )
. ComboButtonStyle ( FAppStyle : : Get ( ) , " SimpleComboButton " )
. Visibility ( this , & SCurrentLevelWidget : : GetCurrentLevelButtonVisibility )
. OnGetMenuContent ( this , & SCurrentLevelWidget : : GenerateLevelMenu )
. ButtonContent ( )
2022-03-08 09:40:27 -05:00
[
// Current Level
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
2022-05-02 11:00:12 -04:00
. Padding ( 0.0f , 0.0f , 2.0f , 0.0f )
2022-03-08 09:40:27 -05:00
. AutoHeight ( )
[
SNew ( STextBlock )
. Visibility ( this , & SCurrentLevelWidget : : GetCurrentLevelTextVisibility )
. Text ( this , & SCurrentLevelWidget : : GetCurrentLevelText )
]
// Referencing Level Instance (if any)
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
2023-05-30 06:44:15 -04:00
. Visibility_Lambda ( [ this ] ( ) { return IsEditingLevelInstanceCurrentLevel ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ; } )
2022-03-08 09:40:27 -05:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " FromBegin " , " ( " ) )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 1.f , 1.f , 1.f , 1.f )
[
SNew ( SBox )
. WidthOverride ( 16 )
. HeightOverride ( 16 )
[
SNew ( SImage )
. Image_Lambda ( [ this ] ( ) { return FClassIconFinder : : FindIconForActor ( GetEditingLevelInstance ( ) ) ; } )
. ColorAndOpacity ( FAppStyle : : Get ( ) . GetSlateColor ( " Colors.AccentGreen " ) )
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( STextBlock )
2023-05-30 06:44:15 -04:00
. Text_Lambda ( [ this ] ( )
2022-03-08 09:40:27 -05:00
{
2022-03-29 09:19:22 -04:00
AActor * LevelInstance = GetEditingLevelInstance ( ) ;
2022-03-08 09:40:27 -05:00
return LevelInstance ? FText : : FromString ( LevelInstance - > GetActorLabel ( ) ) : FText : : GetEmpty ( ) ;
} )
. ColorAndOpacity ( FAppStyle : : Get ( ) . GetSlateColor ( " Colors.AccentGreen " ) )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 0.f , 0.f , 4.f , 0.f )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " FromEnd " , " ) " ) )
]
]
2023-05-30 06:44:15 -04:00
]
] ;
2022-03-08 09:40:27 -05:00
}
private :
2022-03-29 09:19:22 -04:00
AActor * GetEditingLevelInstance ( ) const
2022-03-08 09:40:27 -05:00
{
2023-05-30 06:44:15 -04:00
return InternalEditorLevelLibrary : : GetEditingLevelInstance ( GetWorld ( ) ) ;
}
bool IsEditingLevelInstanceCurrentLevel ( ) const
{
return InternalEditorLevelLibrary : : IsEditingLevelInstanceCurrentLevel ( GetWorld ( ) ) ;
2022-03-08 09:40:27 -05:00
}
FText GetCurrentLevelText ( ) const
{
if ( GetWorld ( ) & & GetWorld ( ) - > GetCurrentLevel ( ) )
{
// Get the level name
const FText ActualLevelName = FText : : FromName ( FPackageName : : GetShortFName ( GetWorld ( ) - > GetCurrentLevel ( ) - > GetOutermost ( ) - > GetFName ( ) ) ) ;
if ( GetWorld ( ) - > GetCurrentLevel ( ) = = GetWorld ( ) - > PersistentLevel )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ActualLevelName " ) , ActualLevelName ) ;
return FText : : Format ( LOCTEXT ( " LevelName " , " {0} (Persistent) " ) , ActualLevelName ) ;
}
return ActualLevelName ;
}
return FText : : GetEmpty ( ) ;
}
bool IsVisible ( ) const
{
2023-05-30 06:44:15 -04:00
return InternalEditorLevelLibrary : : IsActorEditorContextVisible ( GetWorld ( ) ) ;
2022-03-08 09:40:27 -05:00
}
EVisibility GetCurrentLevelTextVisibility ( ) const
{
return IsVisible ( ) ? EVisibility : : SelfHitTestInvisible : EVisibility : : Collapsed ;
}
EVisibility GetCurrentLevelButtonVisibility ( ) const
{
return IsVisible ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
TSharedRef < SWidget > GenerateLevelMenu ( ) const
{
// Get all menu extenders for this context menu from the level editor module
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
TSharedRef < FUICommandList > InCommandList = CommandList . ToSharedRef ( ) ;
TSharedPtr < FExtender > MenuExtender = LevelEditorModule . AssembleExtenders ( InCommandList , LevelEditorModule . GetAllLevelEditorLevelMenuExtenders ( ) ) ;
// Create the menu
FMenuBuilder LevelMenuBuilder ( /*bShouldCloseWindowAfterMenuSelection*/ true , InCommandList , MenuExtender ) ;
LevelMenuBuilder . BeginSection ( " LevelListing " , LOCTEXT ( " Levels " , " Levels " ) ) ;
LevelMenuBuilder . EndSection ( ) ;
return LevelMenuBuilder . MakeWidget ( ) ;
}
UWorld * GetWorld ( ) const
{
return World ;
}
TSharedPtr < FUICommandList > CommandList ;
UWorld * World ;
} ;
bool ULevelEditorSubsystem : : GetActorEditorContextDisplayInfo ( UWorld * InWorld , FActorEditorContextClientDisplayInfo & OutDiplayInfo ) const
{
2023-05-30 06:44:15 -04:00
if ( InternalEditorLevelLibrary : : IsActorEditorContextVisible ( InWorld ) )
2022-03-08 09:40:27 -05:00
{
2022-05-02 11:00:12 -04:00
OutDiplayInfo . Title = TEXT ( " Level " ) ;
2022-03-08 09:40:27 -05:00
OutDiplayInfo . Brush = FSlateIconFinder : : FindIconBrushForClass ( UWorld : : StaticClass ( ) ) ;
return true ;
}
return false ;
}
void ULevelEditorSubsystem : : OnLevelAddedOrRemoved ( ULevel * InLevel , UWorld * InWorld )
{
2023-06-05 07:08:49 -04:00
if ( ! InWorld - > IsGameWorld ( ) )
{
ActorEditorContextClientChanged . Broadcast ( this ) ;
}
2022-03-08 09:40:27 -05:00
}
2022-06-22 10:26:53 -04:00
void ULevelEditorSubsystem : : OnCurrentLevelChanged ( ULevel * InNewLevel , ULevel * InOldLevel , UWorld * InWorld )
{
2023-06-05 07:08:49 -04:00
if ( ! InWorld - > IsGameWorld ( ) )
{
ActorEditorContextClientChanged . Broadcast ( this ) ;
}
2022-06-22 10:26:53 -04:00
}
2022-11-07 13:33:27 -05:00
void ULevelEditorSubsystem : : HandleOnPreSaveWorldWithContext ( class UWorld * World , FObjectPreSaveContext ObjectSaveContext )
{
OnPreSaveWorld . Broadcast ( ObjectSaveContext . GetSaveFlags ( ) , World ) ;
}
void ULevelEditorSubsystem : : HandleOnPostSaveWorldWithContext ( class UWorld * World , FObjectPostSaveContext ObjectSaveContext )
{
OnPostSaveWorld . Broadcast ( ObjectSaveContext . GetSaveFlags ( ) , World , ObjectSaveContext . SaveSucceeded ( ) ) ;
}
void ULevelEditorSubsystem : : HandleOnEditorCameraMoved ( const FVector & Location , const FRotator & Rotation , ELevelViewportType ViewportType , int32 ViewIndex )
{
OnEditorCameraMoved . Broadcast ( Location , Rotation , ViewportType , ViewIndex ) ;
}
void ULevelEditorSubsystem : : HandleOnMapChanged ( uint32 MapChangeFlags )
{
OnMapChanged . Broadcast ( MapChangeFlags ) ;
}
void ULevelEditorSubsystem : : HandleOnMapOpened ( const FString & Filename , bool bAsTemplate )
{
OnMapOpened . Broadcast ( Filename , bAsTemplate ) ;
}
2022-03-08 09:40:27 -05:00
TSharedRef < SWidget > ULevelEditorSubsystem : : GetActorEditorContextWidget ( UWorld * InWorld ) const
{
return SNew ( SCurrentLevelWidget ) . World ( InWorld ) ;
}
2021-01-11 09:19:43 -04:00
# undef LOCTEXT_NAMESPACE