2020-08-25 06:31:46 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LevelInstanceEditorModule.h"
# include "LevelInstanceActorDetails.h"
2021-01-18 12:50:54 -04:00
# include "LevelInstancePivotDetails.h"
2024-04-17 11:01:35 -04:00
# include "LevelInstanceSceneOutlinerColumn.h"
2023-06-14 06:25:37 -04:00
# include "PackedLevelActorUtils.h"
2023-03-08 12:02:09 -05:00
# include "LevelInstanceFilterPropertyTypeCustomization.h"
2020-08-25 06:31:46 -04:00
# include "LevelInstance/LevelInstanceSubsystem.h"
2022-03-29 09:19:22 -04:00
# include "LevelInstance/LevelInstanceInterface.h"
2020-08-25 06:31:46 -04:00
# include "LevelInstance/LevelInstanceActor.h"
2024-02-22 08:26:27 -05:00
# include "LevelInstance/LevelInstanceSettings.h"
2021-12-09 08:09:34 -05:00
# include "PackedLevelActor/PackedLevelActor.h"
2023-06-22 11:32:48 -04:00
# include "PackedLevelActor/PackedLevelActorBuilder.h"
2020-08-25 06:31:46 -04:00
# include "LevelInstanceEditorSettings.h"
# include "ToolMenus.h"
# include "Editor.h"
2021-11-29 14:47:15 -05:00
# include "EditorModeManager.h"
# include "EditorModeRegistry.h"
2022-08-31 08:51:11 -04:00
# include "FileHelpers.h"
2021-11-29 14:47:15 -05:00
# include "LevelInstanceEditorMode.h"
# include "LevelInstanceEditorModeCommands.h"
2020-08-25 06:31:46 -04:00
# include "LevelEditorMenuContext.h"
# include "ContentBrowserMenuContexts.h"
# include "ContentBrowserModule.h"
# include "IContentBrowserSingleton.h"
# include "LevelEditor.h"
# include "Engine/Selection.h"
# include "PropertyEditorModule.h"
# include "EditorLevelUtils.h"
# include "Modules/ModuleManager.h"
# include "Misc/MessageDialog.h"
# include "NewLevelDialogModule.h"
# include "Interfaces/IMainFrameModule.h"
# include "Editor/EditorEngine.h"
# include "AssetToolsModule.h"
# include "IAssetTools.h"
# include "Factories/BlueprintFactory.h"
# include "ClassViewerModule.h"
# include "ClassViewerFilter.h"
# include "Kismet2/BlueprintEditorUtils.h"
# include "Misc/ScopeExit.h"
# include "Widgets/Input/SNumericEntryBox.h"
2020-08-31 23:09:34 -04:00
# include "Widgets/Input/SButton.h"
2021-01-18 12:50:54 -04:00
# include "Widgets/SWindow.h"
# include "SNewLevelInstanceDialog.h"
2020-11-16 08:50:22 -04:00
# include "MessageLogModule.h"
2022-01-07 11:45:52 -05:00
# include "Settings/EditorExperimentalSettings.h"
2024-06-19 15:10:16 -04:00
# include "WorldPartition/HLOD/HLODLayer.h"
2022-08-31 08:51:11 -04:00
# include "WorldPartition/WorldPartitionConverter.h"
2023-03-08 12:02:09 -05:00
# include "WorldPartition/WorldPartitionActorLoaderInterface.h"
2024-02-22 08:26:27 -05:00
# include "ScopedTransaction.h"
2024-04-08 07:37:24 -04:00
# include "ISCSEditorUICustomization.h"
2024-04-11 13:47:04 -04:00
# include "EdModeInteractiveToolsContext.h"
2024-04-17 11:01:35 -04:00
# include "SceneOutlinerModule.h"
# include "SceneOutlinerFwd.h"
2020-08-25 06:31:46 -04:00
IMPLEMENT_MODULE ( FLevelInstanceEditorModule , LevelInstanceEditor ) ;
# define LOCTEXT_NAMESPACE "LevelInstanceEditor"
2022-09-14 07:32:55 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogLevelInstanceEditor , Log , All ) ;
2024-02-22 08:26:27 -05:00
struct FLevelInstanceMenuUtils
2020-08-25 06:31:46 -04:00
{
2024-02-22 08:26:27 -05:00
static FToolMenuSection & CreateLevelSection ( UToolMenu * Menu )
2020-08-25 06:31:46 -04:00
{
2024-04-19 15:13:28 -04:00
return CreateSection ( Menu , FName ( " Level " ) , LOCTEXT ( " LevelSectionLabel " , " Level " ) ) ;
}
static FToolMenuSection & CreateCurrentEditSection ( UToolMenu * Menu )
{
return CreateSection ( Menu , FName ( " CurrentEdit " ) , LOCTEXT ( " CurrentEditSectionLabel " , " Current Edit " ) ) ;
}
static FToolMenuSection & CreateSection ( UToolMenu * Menu , FName SectionName , const FText & SectionText )
{
FToolMenuSection * SectionPtr = Menu - > FindSection ( SectionName ) ;
2021-03-19 18:18:42 -04:00
if ( ! SectionPtr )
{
2024-04-19 15:13:28 -04:00
SectionPtr = & ( Menu - > AddSection ( SectionName , SectionText ) ) ;
2021-03-19 18:18:42 -04:00
}
FToolMenuSection & Section = * SectionPtr ;
2020-08-25 06:31:46 -04:00
return Section ;
}
2024-02-22 08:26:27 -05:00
static void CreateEditMenuEntry ( FToolMenuSection & Section , ILevelInstanceInterface * LevelInstance , AActor * ContextActor , bool bSingleEntry )
2021-12-01 12:13:41 -05:00
{
FToolUIAction LevelInstanceEditAction ;
FText EntryDesc ;
2022-03-29 09:19:22 -04:00
AActor * LevelInstanceActor = CastChecked < AActor > ( LevelInstance ) ;
const bool bCanEdit = LevelInstance - > CanEnterEdit ( & EntryDesc ) ;
2021-12-01 12:13:41 -05:00
LevelInstanceEditAction . ExecuteAction . BindLambda ( [ LevelInstance , ContextActor ] ( const FToolMenuContext & )
{
2022-03-29 09:19:22 -04:00
LevelInstance - > EnterEdit ( ContextActor ) ;
2021-12-01 12:13:41 -05:00
} ) ;
LevelInstanceEditAction . CanExecuteAction . BindLambda ( [ bCanEdit ] ( const FToolMenuContext & )
{
return bCanEdit ;
} ) ;
FText EntryLabel = bSingleEntry ? LOCTEXT ( " EditLevelInstances " , " Edit " ) : FText : : FromString ( LevelInstance - > GetWorldAsset ( ) . GetAssetName ( ) ) ;
if ( bCanEdit )
{
2024-04-19 15:13:28 -04:00
FText EntryActionDesc = LOCTEXT ( " EditLevelInstancesPropertyTooltip " , " Edit this level. Your changes will be applied to the level asset and to all other level instances based on it. " ) ;
EntryDesc = FText : : Format ( LOCTEXT ( " LevelInstanceName " , " {0} \n \n Actor name: {1} \n Asset path: {2} " ) , EntryActionDesc , FText : : FromString ( LevelInstanceActor - > GetActorLabel ( ) ) , FText : : FromString ( LevelInstance - > GetWorldAssetPackage ( ) ) ) ;
2021-12-01 12:13:41 -05:00
}
Section . AddMenuEntry ( NAME_None , EntryLabel , EntryDesc , FSlateIcon ( ) , LevelInstanceEditAction ) ;
}
2024-02-22 08:26:27 -05:00
static void CreateEditSubMenu ( UToolMenu * Menu , TArray < ILevelInstanceInterface * > LevelInstanceHierarchy , AActor * ContextActor )
2020-08-25 06:31:46 -04:00
{
FToolMenuSection & Section = Menu - > AddSection ( NAME_None , LOCTEXT ( " LevelInstanceContextEditSection " , " Context " ) ) ;
2022-03-29 09:19:22 -04:00
for ( ILevelInstanceInterface * LevelInstance : LevelInstanceHierarchy )
2020-08-25 06:31:46 -04:00
{
2021-12-01 12:13:41 -05:00
CreateEditMenuEntry ( Section , LevelInstance , ContextActor , false ) ;
2020-08-25 06:31:46 -04:00
}
}
2022-03-29 09:19:22 -04:00
2024-02-22 08:26:27 -05:00
static void CreateEditPropertyOverridesMenuEntry ( FToolMenuSection & Section , ILevelInstanceInterface * LevelInstance , AActor * ContextActor , bool bSingleEntry )
{
FToolUIAction LevelInstanceEditAction ;
FText EntryDesc ;
AActor * LevelInstanceActor = CastChecked < AActor > ( LevelInstance ) ;
const bool bCanEdit = LevelInstance - > CanEnterEditPropertyOverrides ( & EntryDesc ) ;
LevelInstanceEditAction . ExecuteAction . BindLambda ( [ LevelInstance , ContextActor ] ( const FToolMenuContext & )
{
LevelInstance - > EnterEditPropertyOverrides ( ContextActor ) ;
} ) ;
LevelInstanceEditAction . CanExecuteAction . BindLambda ( [ bCanEdit ] ( const FToolMenuContext & )
{
return bCanEdit ;
} ) ;
2024-02-26 12:00:45 -05:00
FText EntryLabel = bSingleEntry ? LOCTEXT ( " OverrideLevelInstances " , " Override " ) : FText : : FromString ( LevelInstance - > GetWorldAsset ( ) . GetAssetName ( ) ) ;
2024-02-22 08:26:27 -05:00
if ( bCanEdit )
{
2024-04-19 15:13:28 -04:00
FText EntryActionDesc = LOCTEXT ( " EditLevelInstancesPropertyOverridesTooltip " , " Edit only this level instance, without changing the level asset or any other level instances. " ) ;
EntryDesc = FText : : Format ( LOCTEXT ( " OverrideLevelInstanceName " , " {0} \n \n Actor name: {1} \n Asset path: {2} " ) , EntryActionDesc , FText : : FromString ( LevelInstanceActor - > GetActorLabel ( ) ) , FText : : FromString ( LevelInstance - > GetWorldAssetPackage ( ) ) ) ;
2024-02-22 08:26:27 -05:00
}
Section . AddMenuEntry ( NAME_None , EntryLabel , EntryDesc , FSlateIcon ( ) , LevelInstanceEditAction ) ;
}
static void CreateEditPropertyOverridesSubMenu ( UToolMenu * Menu , TArray < ILevelInstanceInterface * > LevelInstanceHierarchy , AActor * ContextActor )
{
FToolMenuSection & Section = Menu - > AddSection ( NAME_None , LOCTEXT ( " LevelInstanceContextEditSection " , " Context " ) ) ;
for ( ILevelInstanceInterface * LevelInstance : LevelInstanceHierarchy )
{
CreateEditPropertyOverridesMenuEntry ( Section , LevelInstance , ContextActor , false ) ;
}
}
static void MoveSelectionToLevelInstance ( ILevelInstanceInterface * DestinationLevelInstance , const TArray < AActor * > & ActorsToMove )
{
2022-03-29 09:19:22 -04:00
DestinationLevelInstance - > MoveActorsTo ( ActorsToMove ) ;
2020-08-25 06:31:46 -04:00
}
2021-11-25 11:13:02 -05:00
2024-02-22 08:26:27 -05:00
static void CreateEditMenu ( UToolMenu * Menu , AActor * ContextActor )
2020-08-25 06:31:46 -04:00
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = ContextActor - > GetWorld ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
2022-03-29 09:19:22 -04:00
TArray < ILevelInstanceInterface * > LevelInstanceHierarchy ;
LevelInstanceSubsystem - > ForEachLevelInstanceAncestorsAndSelf ( ContextActor , [ & LevelInstanceHierarchy ] ( ILevelInstanceInterface * AncestorLevelInstance )
2020-08-25 06:31:46 -04:00
{
2024-02-22 08:26:27 -05:00
LevelInstanceHierarchy . Add ( AncestorLevelInstance ) ;
2020-08-25 06:31:46 -04:00
return true ;
} ) ;
2021-12-01 12:13:41 -05:00
// Don't create sub menu if only one Level Instance is available to edit
if ( LevelInstanceHierarchy . Num ( ) = = 1 )
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
2021-12-01 12:13:41 -05:00
CreateEditMenuEntry ( Section , LevelInstanceHierarchy [ 0 ] , ContextActor , true ) ;
}
else if ( LevelInstanceHierarchy . Num ( ) > 1 )
2020-08-25 06:31:46 -04:00
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
2020-08-25 06:31:46 -04:00
Section . AddSubMenu (
" EditLevelInstances " ,
LOCTEXT ( " EditLevelInstances " , " Edit " ) ,
2024-04-19 15:13:28 -04:00
LOCTEXT ( " EditLevelInstancesPropertyTooltip " , " Edit this level. Your changes will be applied to the level asset and to all other level instances based on it. " ) ,
2020-08-25 06:31:46 -04:00
FNewToolMenuDelegate : : CreateStatic ( & CreateEditSubMenu , MoveTemp ( LevelInstanceHierarchy ) , ContextActor )
) ;
}
}
}
2022-06-08 12:14:52 -04:00
2024-02-22 08:26:27 -05:00
static void CreateEditPropertyOverridesMenu ( UToolMenu * Menu , AActor * ContextActor )
{
if ( ! ULevelInstanceSettings : : Get ( ) - > IsPropertyOverrideEnabled ( ) )
{
return ;
}
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = ContextActor - > GetWorld ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
TArray < ILevelInstanceInterface * > LevelInstanceHierarchy ;
LevelInstanceSubsystem - > ForEachLevelInstanceAncestorsAndSelf ( ContextActor , [ & LevelInstanceHierarchy ] ( ILevelInstanceInterface * AncestorLevelInstance )
{
LevelInstanceHierarchy . Add ( AncestorLevelInstance ) ;
return true ;
} ) ;
// Don't create sub menu if only one Level Instance is available to edit
if ( LevelInstanceHierarchy . Num ( ) = = 1 )
{
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
CreateEditPropertyOverridesMenuEntry ( Section , LevelInstanceHierarchy [ 0 ] , ContextActor , true ) ;
}
else if ( LevelInstanceHierarchy . Num ( ) > 1 )
{
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
Section . AddSubMenu (
" PropertyOverrideLevelInstances " ,
LOCTEXT ( " EditLevelInstancesPropertyOverrides " , " Override " ) ,
2024-04-19 15:13:28 -04:00
LOCTEXT ( " EditLevelInstancesPropertyOverridesTooltip " , " Edit only this level instance, without changing the level asset or any other level instances. " ) ,
2024-02-22 08:26:27 -05:00
FNewToolMenuDelegate : : CreateStatic ( & CreateEditPropertyOverridesSubMenu , MoveTemp ( LevelInstanceHierarchy ) , ContextActor )
) ;
}
}
}
2024-04-19 15:13:28 -04:00
static void CreateSaveCancelMenu ( UToolMenu * Menu , AActor * ContextActor )
2020-08-25 06:31:46 -04:00
{
2022-03-29 09:19:22 -04:00
ILevelInstanceInterface * LevelInstanceEdit = nullptr ;
2020-08-25 06:31:46 -04:00
if ( ContextActor )
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = ContextActor - > GetWorld ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
2024-02-22 08:26:27 -05:00
// Commit Property Overrides has priority
LevelInstanceEdit = LevelInstanceSubsystem - > GetEditingPropertyOverridesLevelInstance ( ) ;
if ( ! LevelInstanceEdit )
{
LevelInstanceEdit = LevelInstanceSubsystem - > GetEditingLevelInstance ( ) ;
}
2020-08-25 06:31:46 -04:00
}
}
2024-02-22 08:26:27 -05:00
// Commmit Property Overrides has priority
if ( ! LevelInstanceEdit )
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = GEditor - > GetEditorWorldContext ( ) . World ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
LevelInstanceEdit = LevelInstanceSubsystem - > GetEditingPropertyOverridesLevelInstance ( ) ;
}
}
// If no Property Overrides found try to find a regular Edit
2021-11-25 11:13:02 -05:00
if ( ! LevelInstanceEdit )
2020-08-25 06:31:46 -04:00
{
2021-11-25 11:13:02 -05:00
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = GEditor - > GetEditorWorldContext ( ) . World ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
2020-08-25 06:31:46 -04:00
{
2021-11-25 11:13:02 -05:00
LevelInstanceEdit = LevelInstanceSubsystem - > GetEditingLevelInstance ( ) ;
}
2020-08-25 06:31:46 -04:00
}
2024-02-22 08:26:27 -05:00
2021-11-25 11:13:02 -05:00
if ( LevelInstanceEdit )
2020-08-25 06:31:46 -04:00
{
2024-04-19 15:13:28 -04:00
FToolMenuSection & Section = CreateCurrentEditSection ( Menu ) ;
2024-02-22 08:26:27 -05:00
if ( LevelInstanceEdit - > IsEditingPropertyOverrides ( ) )
{
2024-04-19 15:13:28 -04:00
FText CommitTooltip = LOCTEXT ( " LevelInstanceCommitPropertyOverridesTooltip " , " Stop overriding this level instance and save any changes you've made. " ) ;
2024-02-22 08:26:27 -05:00
const bool bCanCommit = LevelInstanceEdit - > CanExitEditPropertyOverrides ( /*bDiscardEdits=*/ false , & CommitTooltip ) ;
2021-11-25 11:13:02 -05:00
2024-02-22 08:26:27 -05:00
FToolUIAction CommitAction ;
CommitAction . ExecuteAction . BindLambda ( [ LevelInstanceEdit ] ( const FToolMenuContext & ) { LevelInstanceEdit - > ExitEditPropertyOverrides ( /*bDiscardEdits=*/ false ) ; } ) ;
CommitAction . CanExecuteAction . BindLambda ( [ bCanCommit ] ( const FToolMenuContext & ) { return bCanCommit ; } ) ;
2024-04-19 15:13:28 -04:00
Section . AddMenuEntry ( NAME_None , LOCTEXT ( " LevelInstanceSavePropertyOverridesLabel " , " Save Override(s) " ) , CommitTooltip , FSlateIcon ( ) , CommitAction ) ;
2021-11-25 11:13:02 -05:00
2024-04-19 15:13:28 -04:00
FText DiscardTooltip = LOCTEXT ( " LevelInstanceDiscardPropertyOverridesTooltip " , " Stop overriding this level instance and discard any changes you've made. " ) ;
2024-02-22 08:26:27 -05:00
const bool bCanDiscard = LevelInstanceEdit - > CanExitEditPropertyOverrides ( /*bDiscardEdits=*/ true , & DiscardTooltip ) ;
2021-11-25 11:13:02 -05:00
2024-02-22 08:26:27 -05:00
FToolUIAction DiscardAction ;
DiscardAction . ExecuteAction . BindLambda ( [ LevelInstanceEdit ] ( const FToolMenuContext & ) { LevelInstanceEdit - > ExitEditPropertyOverrides ( /*bDiscardEdits=*/ true ) ; } ) ;
DiscardAction . CanExecuteAction . BindLambda ( [ bCanDiscard ] ( const FToolMenuContext & ) { return bCanDiscard ; } ) ;
2024-04-19 15:13:28 -04:00
Section . AddMenuEntry ( NAME_None , LOCTEXT ( " LevelInstanceCancelPropertyOverridesLabel " , " Cancel Override(s) " ) , DiscardTooltip , FSlateIcon ( ) , DiscardAction ) ;
2024-02-22 08:26:27 -05:00
}
else
{
2024-04-19 15:13:28 -04:00
FText CommitTooltip = LOCTEXT ( " LevelInstanceCommitTooltip " , " Stop editing this level and save any changes you've made. " ) ;
2024-02-22 08:26:27 -05:00
const bool bCanCommit = LevelInstanceEdit - > CanExitEdit ( /*bDiscardEdits=*/ false , & CommitTooltip ) ;
2022-01-04 07:28:59 -05:00
2024-02-22 08:26:27 -05:00
FToolUIAction CommitAction ;
CommitAction . ExecuteAction . BindLambda ( [ LevelInstanceEdit ] ( const FToolMenuContext & ) { LevelInstanceEdit - > ExitEdit ( /*bDiscardEdits=*/ false ) ; } ) ;
CommitAction . CanExecuteAction . BindLambda ( [ bCanCommit ] ( const FToolMenuContext & ) { return bCanCommit ; } ) ;
2024-04-19 15:13:28 -04:00
Section . AddMenuEntry ( NAME_None , LOCTEXT ( " LevelInstanceSaveLabel " , " Save " ) , CommitTooltip , FSlateIcon ( ) , CommitAction ) ;
2024-02-22 08:26:27 -05:00
2024-04-19 15:13:28 -04:00
FText DiscardTooltip = LOCTEXT ( " LevelInstanceDiscardTooltip " , " Stop editing this level and discard any changes you've made. " ) ;
2024-02-22 08:26:27 -05:00
const bool bCanDiscard = LevelInstanceEdit - > CanExitEdit ( /*bDiscardEdits=*/ true , & DiscardTooltip ) ;
FToolUIAction DiscardAction ;
DiscardAction . ExecuteAction . BindLambda ( [ LevelInstanceEdit ] ( const FToolMenuContext & ) { LevelInstanceEdit - > ExitEdit ( /*bDiscardEdits=*/ true ) ; } ) ;
DiscardAction . CanExecuteAction . BindLambda ( [ bCanDiscard ] ( const FToolMenuContext & ) { return bCanDiscard ; } ) ;
2024-04-19 15:13:28 -04:00
Section . AddMenuEntry ( NAME_None , LOCTEXT ( " LevelInstanceCancelLabel " , " Cancel " ) , DiscardTooltip , FSlateIcon ( ) , DiscardAction ) ;
2020-08-25 06:31:46 -04:00
}
}
}
2024-02-22 08:26:27 -05:00
static UClass * GetDefaultLevelInstanceClass ( ELevelInstanceCreationType CreationType )
2023-05-19 13:51:16 -04:00
{
if ( CreationType = = ELevelInstanceCreationType : : PackedLevelActor )
{
return APackedLevelActor : : StaticClass ( ) ;
}
ULevelInstanceEditorSettings * LevelInstanceEditorSettings = GetMutableDefault < ULevelInstanceEditorSettings > ( ) ;
if ( ! LevelInstanceEditorSettings - > LevelInstanceClassName . IsEmpty ( ) )
{
UClass * LevelInstanceClass = LoadClass < AActor > ( nullptr , * LevelInstanceEditorSettings - > LevelInstanceClassName , nullptr , LOAD_NoWarn ) ;
if ( LevelInstanceClass & & LevelInstanceClass - > ImplementsInterface ( ULevelInstanceInterface : : StaticClass ( ) ) )
{
return LevelInstanceClass ;
}
}
return ALevelInstance : : StaticClass ( ) ;
}
2024-02-22 08:26:27 -05:00
static bool AreAllSelectedLevelInstancesRootSelections ( const TArray < ILevelInstanceInterface * > & SelectedLevelInstances )
2023-12-04 11:18:06 -05:00
{
2024-02-22 08:26:27 -05:00
for ( ILevelInstanceInterface * LevelInstance : SelectedLevelInstances )
2023-12-04 11:18:06 -05:00
{
2024-02-22 08:26:27 -05:00
if ( CastChecked < AActor > ( LevelInstance ) - > GetSelectionParent ( ) ! = nullptr )
2023-12-04 11:18:06 -05:00
{
2024-02-22 08:26:27 -05:00
return false ;
2023-12-04 11:18:06 -05:00
}
}
return true ;
}
2024-02-22 08:26:27 -05:00
static void CreateLevelInstanceFromSelection ( ULevelInstanceSubsystem * LevelInstanceSubsystem , ELevelInstanceCreationType CreationType , const TArray < AActor * > & ActorsToMove )
2020-08-25 06:31:46 -04:00
{
IMainFrameModule & MainFrameModule = FModuleManager : : GetModuleChecked < IMainFrameModule > ( " MainFrame " ) ;
2021-01-18 12:50:54 -04:00
TSharedPtr < SWindow > NewLevelInstanceWindow =
SNew ( SWindow )
2021-12-09 08:09:34 -05:00
. Title ( FText : : Format ( LOCTEXT ( " NewLevelInstanceWindowTitle " , " New {0} " ) , StaticEnum < ELevelInstanceCreationType > ( ) - > GetDisplayNameTextByValue ( ( int64 ) CreationType ) ) )
2021-01-18 12:50:54 -04:00
. SupportsMinimize ( false )
. SupportsMaximize ( false )
2021-12-09 08:09:34 -05:00
. SizingRule ( ESizingRule : : Autosized ) ;
2020-08-25 06:31:46 -04:00
2021-01-18 12:50:54 -04:00
TSharedRef < SNewLevelInstanceDialog > NewLevelInstanceDialog =
SNew ( SNewLevelInstanceDialog )
. ParentWindow ( NewLevelInstanceWindow )
. PivotActors ( ActorsToMove ) ;
2021-11-25 13:29:54 -05:00
const bool bForceExternalActors = LevelInstanceSubsystem - > GetWorld ( ) - > IsPartitionedWorld ( ) ;
FNewLevelInstanceParams & DialogParams = NewLevelInstanceDialog - > GetCreationParams ( ) ;
2021-12-09 08:09:34 -05:00
DialogParams . Type = CreationType ;
2022-06-13 18:38:57 -04:00
DialogParams . bAlwaysShowDialog = GetDefault < ULevelInstanceEditorPerProjectUserSettings > ( ) - > bAlwaysShowDialog ;
DialogParams . PivotType = GetDefault < ULevelInstanceEditorPerProjectUserSettings > ( ) - > PivotType ;
DialogParams . PivotActor = DialogParams . PivotType = = ELevelInstancePivotType : : Actor ? ActorsToMove [ 0 ] : nullptr ;
2021-12-09 08:09:34 -05:00
DialogParams . HideCreationType ( ) ;
2021-11-25 13:29:54 -05:00
DialogParams . SetForceExternalActors ( bForceExternalActors ) ;
2021-01-18 12:50:54 -04:00
NewLevelInstanceWindow - > SetContent ( NewLevelInstanceDialog ) ;
2022-06-13 18:38:57 -04:00
if ( GetDefault < ULevelInstanceEditorPerProjectUserSettings > ( ) - > bAlwaysShowDialog )
{
FSlateApplication : : Get ( ) . AddModalWindow ( NewLevelInstanceWindow . ToSharedRef ( ) , MainFrameModule . GetParentWindow ( ) ) ;
}
if ( ! GetDefault < ULevelInstanceEditorPerProjectUserSettings > ( ) - > bAlwaysShowDialog | | NewLevelInstanceDialog - > ClickedOk ( ) )
2020-11-16 08:50:22 -04:00
{
2021-01-20 12:26:28 -04:00
FNewLevelInstanceParams CreationParams ( NewLevelInstanceDialog - > GetCreationParams ( ) ) ;
2022-06-13 18:38:57 -04:00
ULevelInstanceEditorPerProjectUserSettings : : UpdateFrom ( CreationParams ) ;
2021-01-18 12:50:54 -04:00
FNewLevelDialogModule & NewLevelDialogModule = FModuleManager : : LoadModuleChecked < FNewLevelDialogModule > ( " NewLevelDialog " ) ;
FString TemplateMapPackage ;
2021-09-29 12:29:37 -04:00
bool bOutIsPartitionedWorld = false ;
const bool bShowPartitionedTemplates = false ;
2022-05-16 09:27:00 -04:00
ULevelInstanceEditorSettings * LevelInstanceEditorSettings = GetMutableDefault < ULevelInstanceEditorSettings > ( ) ;
if ( ! LevelInstanceEditorSettings - > TemplateMapInfos . Num ( ) | | NewLevelDialogModule . CreateAndShowTemplateDialog ( MainFrameModule . GetParentWindow ( ) , LOCTEXT ( " LevelInstanceTemplateDialog " , " Choose Level Instance Template... " ) , GetMutableDefault < ULevelInstanceEditorSettings > ( ) - > TemplateMapInfos , TemplateMapPackage , bShowPartitionedTemplates , bOutIsPartitionedWorld ) )
2020-11-16 08:50:22 -04:00
{
2021-01-18 12:50:54 -04:00
UPackage * TemplatePackage = ! TemplateMapPackage . IsEmpty ( ) ? LoadPackage ( nullptr , * TemplateMapPackage , LOAD_None ) : nullptr ;
2021-01-20 12:26:28 -04:00
CreationParams . TemplateWorld = TemplatePackage ? UWorld : : FindWorldInPackage ( TemplatePackage ) : nullptr ;
2023-05-19 13:51:16 -04:00
CreationParams . LevelInstanceClass = GetDefaultLevelInstanceClass ( CreationType ) ;
2023-06-12 07:30:42 -04:00
CreationParams . bEnableStreaming = LevelInstanceEditorSettings - > bEnableStreaming ;
2021-01-18 12:50:54 -04:00
2021-01-20 12:26:28 -04:00
if ( ! LevelInstanceSubsystem - > CreateLevelInstanceFrom ( ActorsToMove , CreationParams ) )
2020-11-16 08:50:22 -04:00
{
2023-04-15 19:49:32 -04:00
FMessageDialog : : Open ( EAppMsgType : : Ok , LOCTEXT ( " CreateFromSelectionFailMsg " , " Failed to create from selection. Check log for details. " ) , LOCTEXT ( " CreateFromSelectionFailTitle " , " Create from selection failed " ) ) ;
2021-01-18 12:50:54 -04:00
}
2020-11-16 08:50:22 -04:00
}
}
}
2021-12-09 08:09:34 -05:00
2024-02-22 08:26:27 -05:00
static void CreateCreateMenu ( UToolMenu * ToolMenu , const TArray < AActor * > & ActorsToMove )
2020-08-25 06:31:46 -04:00
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = GEditor - > GetEditorWorldContext ( ) . World ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
2024-02-22 08:26:27 -05:00
if ( LevelInstanceSubsystem - > CanCreateLevelInstanceFrom ( ActorsToMove ) )
2021-01-18 12:50:54 -04:00
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = ToolMenu - > AddSection ( " ActorSelectionSectionName " , LOCTEXT ( " ActorSelectionSectionLabel " , " Actor Selection " ) ) ;
2024-02-22 08:26:27 -05:00
Section . AddMenuEntry (
TEXT ( " CreateLevelInstance " ) ,
FText : : Format ( LOCTEXT ( " CreateFromSelectionLabel " , " Create {0}... " ) , StaticEnum < ELevelInstanceCreationType > ( ) - > GetDisplayNameTextByValue ( ( int64 ) ELevelInstanceCreationType : : LevelInstance ) ) ,
TAttribute < FText > ( ) ,
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " ClassIcon.LevelInstance " ) ,
FExecuteAction : : CreateLambda ( [ LevelInstanceSubsystem , CopyActorsToMove = ActorsToMove ]
{
CreateLevelInstanceFromSelection ( LevelInstanceSubsystem , ELevelInstanceCreationType : : LevelInstance , CopyActorsToMove ) ;
} ) ) ;
Section . AddMenuEntry (
TEXT ( " CreatePackedLevelBlueprint " ) ,
FText : : Format ( LOCTEXT ( " CreateFromSelectionLabel " , " Create {0}... " ) , StaticEnum < ELevelInstanceCreationType > ( ) - > GetDisplayNameTextByValue ( ( int64 ) ELevelInstanceCreationType : : PackedLevelActor ) ) ,
TAttribute < FText > ( ) ,
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " ClassIcon.PackedLevelActor " ) ,
FExecuteAction : : CreateLambda ( [ LevelInstanceSubsystem , CopyActorsToMove = ActorsToMove ]
{
CreateLevelInstanceFromSelection ( LevelInstanceSubsystem , ELevelInstanceCreationType : : PackedLevelActor , CopyActorsToMove ) ;
} ) ) ;
2021-12-09 08:09:34 -05:00
}
2020-08-25 06:31:46 -04:00
}
}
2021-12-09 08:09:34 -05:00
2024-02-22 08:26:27 -05:00
static void CreateBreakSubMenu ( UToolMenu * Menu , const TArray < ILevelInstanceInterface * > & BreakableLevelInstances )
2020-08-25 06:31:46 -04:00
{
static int32 BreakLevels = 1 ;
2024-01-10 11:05:38 -05:00
ULevelInstanceEditorPerProjectUserSettings * Settings = GetMutableDefault < ULevelInstanceEditorPerProjectUserSettings > ( ) ;
2020-08-25 06:31:46 -04:00
2022-06-17 14:13:33 -04:00
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = GEditor - > GetEditorWorldContext ( ) . World ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
2020-08-25 06:31:46 -04:00
{
2024-01-10 11:05:38 -05:00
FToolMenuSection & Section = Menu - > AddSection ( " Options " , LOCTEXT ( " LevelInstanceBreakOptionsSection " , " Options " ) ) ;
2020-08-25 06:31:46 -04:00
2024-01-10 11:05:38 -05:00
FToolMenuEntry OrganizeInFoldersEntry = FToolMenuEntry : : InitMenuEntry (
" OrganizeInFolders " ,
LOCTEXT ( " OrganizeActorsInFolders " , " Keep Folders " ) ,
LOCTEXT (
" OrganizeActorsInFoldersTooltip " ,
2024-04-19 15:13:28 -04:00
" When checked, actors remain in the same folder as the level instance "
" and use the same folder structure. "
" \n When unchecked, actors are placed at the root of the current level's hierarchy. "
2024-01-10 11:05:38 -05:00
) ,
FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateLambda ( [ Settings ] ( )
2022-06-17 14:13:33 -04:00
{
2024-01-10 11:05:38 -05:00
Settings - > bKeepFoldersDuringBreak = ! Settings - > bKeepFoldersDuringBreak ;
} ) ,
FCanExecuteAction ( ) ,
FGetActionCheckState : : CreateLambda ( [ Settings ]
{
return Settings - > bKeepFoldersDuringBreak ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2022-06-17 14:13:33 -04:00
} )
2024-01-10 11:05:38 -05:00
) ,
EUserInterfaceActionType : : ToggleButton
) ;
OrganizeInFoldersEntry . bShouldCloseWindowAfterMenuSelection = false ;
Section . AddEntry ( OrganizeInFoldersEntry ) ;
TSharedRef < SWidget > MenuWidget =
SNew ( SBox )
. Padding ( FMargin ( 5 , 2 , 5 , 0 ) )
[
SNew ( SNumericEntryBox < int32 > )
. MinValue ( 1 )
. Value_Lambda ( [ ] ( ) { return BreakLevels ; } )
. OnValueChanged_Lambda ( [ ] ( int32 InValue ) { BreakLevels = InValue ; } )
2024-04-19 15:13:28 -04:00
. ToolTipText ( LOCTEXT ( " BreakLevelsTooltip " , " Determines the depth of nested instances to break apart. Use 1 to break only the top level instance. " ) )
2024-01-10 11:05:38 -05:00
. Label ( )
[
2024-04-19 15:13:28 -04:00
SNumericEntryBox < int32 > : : BuildLabel ( LOCTEXT ( " BreakDepthLabel " , " Depth " ) , FLinearColor : : White , FLinearColor : : Transparent )
2024-01-10 11:05:38 -05:00
]
2020-08-25 06:31:46 -04:00
] ;
Section . AddEntry ( FToolMenuEntry : : InitWidget ( " SetBreakLevels " , MenuWidget , FText : : GetEmpty ( ) , false ) ) ;
2024-01-10 11:05:38 -05:00
Section . AddSeparator ( NAME_None ) ;
FToolMenuEntry ExecuteEntry = FToolMenuEntry : : InitMenuEntry (
" ExecuteBreak " ,
LOCTEXT ( " BreakLevelInstances_BreakLevelInstanceButton " , " Break Level Instance(s) " ) ,
2024-04-19 15:13:28 -04:00
LOCTEXT ( " BreakLevelInstances_BreakLevelInstanceButtonTooltip " , " Break apart the selected level instances using the settings above. " ) ,
2024-01-10 11:05:38 -05:00
FSlateIcon ( ) ,
FUIAction (
2024-02-22 08:26:27 -05:00
FExecuteAction : : CreateLambda ( [ CopyBreakableLevelInstances = BreakableLevelInstances , LevelInstanceSubsystem , Settings ] ( )
2024-01-10 11:05:38 -05:00
{
const FText LevelInstanceBreakWarning = FText : : Format (
LOCTEXT (
" BreakingLevelInstance " ,
" You are about to break {0} level instance(s). This action cannot be undone. Are you sure ? "
) ,
2024-02-22 08:26:27 -05:00
FText : : AsNumber ( CopyBreakableLevelInstances . Num ( ) )
2024-01-10 11:05:38 -05:00
) ;
2024-04-19 15:13:28 -04:00
if ( FMessageDialog : : Open ( EAppMsgType : : YesNo , LevelInstanceBreakWarning , LOCTEXT ( " BreakingLevelInstanceTitle " , " Break Level Instances " ) ) = = EAppReturnType : : Yes )
2024-01-10 11:05:38 -05:00
{
ELevelInstanceBreakFlags Flags = ELevelInstanceBreakFlags : : None ;
if ( Settings - > bKeepFoldersDuringBreak )
{
Flags | = ELevelInstanceBreakFlags : : KeepFolders ;
}
2024-02-22 08:26:27 -05:00
for ( ILevelInstanceInterface * LevelInstance : CopyBreakableLevelInstances )
2024-01-10 11:05:38 -05:00
{
LevelInstanceSubsystem - > BreakLevelInstance ( LevelInstance , BreakLevels , nullptr , Flags ) ;
}
}
} )
) ,
EUserInterfaceActionType : : Button
) ;
Section . AddEntry ( ExecuteEntry ) ;
2020-08-25 06:31:46 -04:00
}
}
2024-02-22 08:26:27 -05:00
static void CreateBreakMenu ( UToolMenu * Menu , const TArray < ILevelInstanceInterface * > & SelectedLevelInstances )
2020-08-25 06:31:46 -04:00
{
2022-06-17 14:13:33 -04:00
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = GEditor - > GetEditorWorldContext ( ) . World ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
2020-08-25 06:31:46 -04:00
{
2022-06-17 14:13:33 -04:00
TArray < ILevelInstanceInterface * > BreakableLevelInstances ;
2024-02-22 08:26:27 -05:00
for ( ILevelInstanceInterface * SelectedLevelInstance : SelectedLevelInstances )
2022-03-29 09:19:22 -04:00
{
2024-02-22 08:26:27 -05:00
if ( LevelInstanceSubsystem - > CanBreakLevelInstance ( SelectedLevelInstance ) )
2020-08-25 06:31:46 -04:00
{
2024-02-22 08:26:27 -05:00
BreakableLevelInstances . Add ( SelectedLevelInstance ) ;
}
2022-06-17 14:13:33 -04:00
}
2024-02-22 08:26:27 -05:00
2022-06-17 14:13:33 -04:00
if ( BreakableLevelInstances . Num ( ) )
2020-08-25 06:31:46 -04:00
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
2020-08-25 06:31:46 -04:00
Section . AddSubMenu (
" BreakLevelInstances " ,
2024-04-19 15:13:28 -04:00
LOCTEXT ( " BreakLevelInstances " , " Break " ) ,
LOCTEXT ( " BreakLevelInstancesTooltip " , " Break apart the selected level instances into their individual actors. " ) ,
2024-02-22 08:26:27 -05:00
FNewToolMenuDelegate : : CreateLambda ( [ CopyOfBreakableLevelInstances = BreakableLevelInstances ] ( UToolMenu * Menu )
{
CreateBreakSubMenu ( Menu , CopyOfBreakableLevelInstances ) ;
} ) ) ;
2020-08-25 06:31:46 -04:00
}
}
2022-06-17 14:13:33 -04:00
2020-08-25 06:31:46 -04:00
}
2024-02-22 08:26:27 -05:00
static void CreatePackedBlueprintMenu ( UToolMenu * Menu , AActor * ContextActor )
2020-11-16 08:50:22 -04:00
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = ContextActor - > GetWorld ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
2022-03-29 09:19:22 -04:00
ILevelInstanceInterface * ContextLevelInstance = nullptr ;
2020-11-16 08:50:22 -04:00
// Find the top level LevelInstance
2022-03-29 09:19:22 -04:00
LevelInstanceSubsystem - > ForEachLevelInstanceAncestorsAndSelf ( ContextActor , [ LevelInstanceSubsystem , ContextActor , & ContextLevelInstance ] ( ILevelInstanceInterface * Ancestor )
2020-11-16 08:50:22 -04:00
{
2022-03-29 09:19:22 -04:00
if ( CastChecked < AActor > ( Ancestor ) - > GetLevel ( ) = = ContextActor - > GetWorld ( ) - > GetCurrentLevel ( ) )
2020-11-16 08:50:22 -04:00
{
ContextLevelInstance = Ancestor ;
return false ;
}
return true ;
} ) ;
2024-02-22 08:26:27 -05:00
if ( ContextLevelInstance & & ! ContextLevelInstance - > IsEditing ( ) )
2020-11-16 08:50:22 -04:00
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
;
if ( APackedLevelActor * PackedLevelActor = Cast < APackedLevelActor > ( ContextLevelInstance ) )
2020-11-16 08:50:22 -04:00
{
2023-05-16 10:52:49 -04:00
if ( TSoftObjectPtr < UBlueprint > BlueprintAsset = PackedLevelActor - > GetClass ( ) - > ClassGeneratedBy . Get ( ) )
2021-12-09 08:09:34 -05:00
{
FToolUIAction UIAction ;
UIAction . ExecuteAction . BindLambda ( [ ContextLevelInstance , BlueprintAsset ] ( const FToolMenuContext & MenuContext )
2023-06-14 06:25:37 -04:00
{
FPackedLevelActorUtils : : CreateOrUpdateBlueprint ( ContextLevelInstance - > GetWorldAsset ( ) , BlueprintAsset ) ;
} ) ;
2021-12-09 08:09:34 -05:00
UIAction . CanExecuteAction . BindLambda ( [ ] ( const FToolMenuContext & MenuContext )
2023-06-14 06:25:37 -04:00
{
return FPackedLevelActorUtils : : CanPack ( ) & & GEditor - > GetSelectedActorCount ( ) > 0 ;
} ) ;
2020-11-16 08:50:22 -04:00
2021-12-09 08:09:34 -05:00
Section . AddMenuEntry (
" UpdatePackedBlueprint " ,
LOCTEXT ( " UpdatePackedBlueprint " , " Update Packed Blueprint " ) ,
TAttribute < FText > ( ) ,
TAttribute < FSlateIcon > ( ) ,
UIAction ) ;
}
2020-11-16 08:50:22 -04:00
}
}
}
}
2024-02-22 08:26:27 -05:00
static void CreateResetPropertyOverridesMenu ( UToolMenu * Menu , const TArray < AActor * > & SelectedActors , const TArray < ILevelInstanceInterface * > & SelectedLevelInstances )
{
if ( ! ULevelInstanceSettings : : Get ( ) - > IsPropertyOverrideEnabled ( ) )
{
return ;
}
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = UWorld : : GetSubsystem < ULevelInstanceSubsystem > ( GEditor - > GetEditorWorldContext ( ) . World ( ) ) )
{
if ( SelectedLevelInstances . Num ( ) > 0 & & SelectedActors . Num ( ) = = SelectedLevelInstances . Num ( ) )
{
bool bCanResetAllLevelInstances = true ;
for ( ILevelInstanceInterface * SelectedLevelInstance : SelectedLevelInstances )
{
if ( ! LevelInstanceSubsystem - > CanResetPropertyOverrides ( SelectedLevelInstance ) )
{
2024-04-17 11:01:35 -04:00
bCanResetAllLevelInstances = false ;
break ;
2024-02-22 08:26:27 -05:00
}
}
2024-04-17 11:01:35 -04:00
if ( bCanResetAllLevelInstances )
2024-02-22 08:26:27 -05:00
{
2024-04-17 11:01:35 -04:00
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
FToolUIAction UIAction ;
UIAction . ExecuteAction . BindLambda ( [ LevelInstanceSubsystem , CopySelectedLevelInstance = SelectedLevelInstances ] ( const FToolMenuContext & MenuContext )
{
for ( ILevelInstanceInterface * LevelInstanceInterface : CopySelectedLevelInstance )
{
LevelInstanceSubsystem - > ResetPropertyOverrides ( LevelInstanceInterface ) ;
}
} ) ;
2024-02-22 08:26:27 -05:00
2024-04-17 11:01:35 -04:00
Section . AddMenuEntry (
" ResetLevelInstancePropertyOverrides " ,
2024-04-19 15:13:28 -04:00
LOCTEXT ( " ResetLevelInstancePropertyOverrides " , " Reset Overrides " ) ,
2024-04-17 11:01:35 -04:00
TAttribute < FText > ( ) ,
TAttribute < FSlateIcon > ( ) ,
UIAction ) ;
2024-02-22 08:26:27 -05:00
2024-04-17 11:01:35 -04:00
return ;
}
2024-02-22 08:26:27 -05:00
}
if ( SelectedActors . Num ( ) > 0 )
{
bool bCanResetAllActors = true ;
for ( AActor * SelectedActor : SelectedActors )
{
if ( ! LevelInstanceSubsystem - > CanResetPropertyOverridesForActor ( SelectedActor ) )
{
bCanResetAllActors = false ;
break ;
}
}
if ( bCanResetAllActors )
{
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
FToolUIAction UIAction ;
UIAction . ExecuteAction . BindLambda ( [ LevelInstanceSubsystem , CopySelectedActors = SelectedActors ] ( const FToolMenuContext & MenuContext )
{
FScopedTransaction ResetPropertyOverridesTransaction ( LOCTEXT ( " ResetPropertyOverrides " , " Reset Property Override(s) " )) ;
for ( AActor * SelectedActor : CopySelectedActors )
{
LevelInstanceSubsystem - > ResetPropertyOverridesForActor ( SelectedActor ) ;
}
} ) ;
Section . AddMenuEntry (
" ResetLevelInstancePropertyOverrides " ,
2024-04-19 15:13:28 -04:00
LOCTEXT ( " ResetLevelInstancePropertyOverrides " , " Reset Overrides " ) ,
LOCTEXT ( " ResetLevelInstancePropertyOverridesTooltip " , " Discard all overrides on the selected level instances, restoring them to match the level assets. " ) ,
2024-02-22 08:26:27 -05:00
TAttribute < FSlateIcon > ( ) ,
UIAction ) ;
}
}
}
}
2020-08-25 06:31:46 -04:00
class FLevelInstanceClassFilter : public IClassViewerFilter
{
public :
2024-02-22 08:26:27 -05:00
virtual bool IsClassAllowed ( const FClassViewerInitializationOptions & InInitOptions , const UClass * InClass , TSharedRef < FClassViewerFilterFuncs > InFilterFuncs ) override
2020-08-25 06:31:46 -04:00
{
2023-05-19 13:51:16 -04:00
return InClass & & InClass - > ImplementsInterface ( ULevelInstanceInterface : : StaticClass ( ) ) & & InClass - > IsNative ( ) & & ! InClass - > HasAnyClassFlags ( CLASS_Deprecated ) ;
2020-08-25 06:31:46 -04:00
}
2024-02-22 08:26:27 -05:00
virtual bool IsUnloadedClassAllowed ( const FClassViewerInitializationOptions & InInitOptions , const TSharedRef < const IUnloadedBlueprintData > InUnloadedClassData , TSharedRef < FClassViewerFilterFuncs > InFilterFuncs ) override
2020-08-25 06:31:46 -04:00
{
2023-05-19 13:51:16 -04:00
return false ;
2020-08-25 06:31:46 -04:00
}
} ;
2024-02-22 08:26:27 -05:00
static void CreateBlueprintFromWorld ( UWorld * WorldAsset )
2020-08-25 06:31:46 -04:00
{
TSoftObjectPtr < UWorld > LevelInstancePtr ( WorldAsset ) ;
int32 LastSlashIndex = 0 ;
FString LongPackageName = LevelInstancePtr . GetLongPackageName ( ) ;
LongPackageName . FindLastChar ( ' / ' , LastSlashIndex ) ;
FString PackagePath = LongPackageName . Mid ( 0 , LastSlashIndex = = INDEX_NONE ? MAX_int32 : LastSlashIndex ) ;
2023-05-19 13:51:16 -04:00
FString AssetName = " BP_ " + LevelInstancePtr . GetAssetName ( ) ;
2020-08-25 06:31:46 -04:00
IAssetTools & AssetTools = FAssetToolsModule : : GetModule ( ) . Get ( ) ;
UBlueprintFactory * BlueprintFactory = NewObject < UBlueprintFactory > ( ) ;
BlueprintFactory - > AddToRoot ( ) ;
BlueprintFactory - > OnConfigurePropertiesDelegate . BindLambda ( [ ] ( FClassViewerInitializationOptions * Options )
{
Options - > bShowDefaultClasses = false ;
Options - > bIsBlueprintBaseOnly = false ;
Options - > InitiallySelectedClass = ALevelInstance : : StaticClass ( ) ;
Options - > bIsActorsOnly = true ;
2021-06-10 10:40:50 -04:00
Options - > ClassFilters . Add ( MakeShareable ( new FLevelInstanceClassFilter ) ) ;
2020-08-25 06:31:46 -04:00
} ) ;
ON_SCOPE_EXIT
{
BlueprintFactory - > OnConfigurePropertiesDelegate . Unbind ( ) ;
BlueprintFactory - > RemoveFromRoot ( ) ;
} ;
if ( UBlueprint * NewBlueprint = Cast < UBlueprint > ( AssetTools . CreateAssetWithDialog ( AssetName , PackagePath , UBlueprint : : StaticClass ( ) , BlueprintFactory , FName ( " Create LevelInstance Blueprint " ) ) ) )
{
2022-03-29 09:19:22 -04:00
AActor * CDO = NewBlueprint - > GeneratedClass - > GetDefaultObject < AActor > ( ) ;
ILevelInstanceInterface * LevelInstanceCDO = CastChecked < ILevelInstanceInterface > ( CDO ) ;
LevelInstanceCDO - > SetWorldAsset ( LevelInstancePtr ) ;
2020-08-25 06:31:46 -04:00
FBlueprintEditorUtils : : MarkBlueprintAsModified ( NewBlueprint ) ;
2023-05-19 13:51:16 -04:00
if ( NewBlueprint - > GeneratedClass - > IsChildOf < APackedLevelActor > ( ) )
{
2023-06-14 06:25:37 -04:00
FPackedLevelActorUtils : : UpdateBlueprint ( NewBlueprint ) ;
2023-05-19 13:51:16 -04:00
}
2020-08-25 06:31:46 -04:00
FContentBrowserModule & ContentBrowserModule = FModuleManager : : LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) ;
TArray < UObject * > Assets ;
Assets . Add ( NewBlueprint ) ;
ContentBrowserModule . Get ( ) . SyncBrowserToAssets ( Assets ) ;
}
}
2024-02-22 08:26:27 -05:00
static void CreateBlueprintFromMenu ( UToolMenu * Menu , FAssetData WorldAsset )
2020-08-25 06:31:46 -04:00
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
2020-08-25 06:31:46 -04:00
FToolUIAction UIAction ;
UIAction . ExecuteAction . BindLambda ( [ WorldAsset ] ( const FToolMenuContext & MenuContext )
{
2022-10-14 16:59:41 -04:00
if ( UWorld * World = Cast < UWorld > ( WorldAsset . GetAsset ( ) ) )
{
CreateBlueprintFromWorld ( World ) ;
}
2020-08-25 06:31:46 -04:00
} ) ;
Section . AddMenuEntry (
" CreateLevelInstanceBlueprint " ,
LOCTEXT ( " CreateLevelInstanceBlueprint " , " New Blueprint... " ) ,
TAttribute < FText > ( ) ,
2023-06-14 06:25:37 -04:00
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " ClassIcon.LevelInstance " ) ,
2020-08-25 06:31:46 -04:00
UIAction ) ;
}
2022-08-31 08:51:11 -04:00
2024-02-22 08:26:27 -05:00
static void AddPartitionedStreamingSupportFromWorld ( UWorld * WorldAsset )
2022-08-31 08:51:11 -04:00
{
2022-09-14 07:32:55 -04:00
if ( WorldAsset - > GetStreamingLevels ( ) . Num ( ) )
{
FMessageDialog : : Open ( EAppMsgType : : Ok , LOCTEXT ( " AddPartitionedLevelInstanceStreamingSupportError_SubLevels " , " Cannot convert this world has it contains sublevels. " ) ) ;
return ;
}
2022-08-31 08:51:11 -04:00
2022-09-14 07:32:55 -04:00
if ( WorldAsset - > WorldType ! = EWorldType : : Inactive )
{
FMessageDialog : : Open ( EAppMsgType : : Ok , LOCTEXT ( " AddPartitionedLevelInstanceStreamingSupportError_Loaded " , " Cannot convert this world has it's already loaded in the editor. " ) ) ;
return ;
}
bool bSuccess = false ;
2022-08-31 08:51:11 -04:00
UWorld * World = GEditor - > GetEditorWorldContext ( ) . World ( ) ;
2022-09-15 18:06:19 -04:00
ULevelInstanceSubsystem : : ResetLoadersForWorldAsset ( WorldAsset - > GetPackage ( ) - > GetName ( ) ) ;
FWorldPartitionConverter : : FParameters Parameters ;
Parameters . bConvertSubLevels = false ;
Parameters . bEnableStreaming = false ;
Parameters . bUseActorFolders = true ;
if ( FWorldPartitionConverter : : Convert ( WorldAsset , Parameters ) )
2022-08-31 08:51:11 -04:00
{
2022-09-15 18:06:19 -04:00
TArray < UPackage * > PackagesToSave = WorldAsset - > PersistentLevel - > GetLoadedExternalObjectPackages ( ) ;
TSet < UPackage * > PackagesToSaveSet ( PackagesToSave ) ;
2022-08-31 08:51:11 -04:00
2022-09-15 18:06:19 -04:00
PackagesToSaveSet . Add ( WorldAsset - > GetPackage ( ) ) ;
2024-06-19 15:10:16 -04:00
UHLODLayer * NewHLODLayer = WorldAsset - > GetWorldPartition ( ) - > GetDefaultHLODLayer ( ) ;
while ( NewHLODLayer & & NewHLODLayer - > GetPackage ( ) )
{
if ( NewHLODLayer - > GetPackage ( ) - > IsDirty ( ) )
{
PackagesToSaveSet . Emplace ( NewHLODLayer - > GetPackage ( ) ) ;
}
NewHLODLayer = NewHLODLayer - > GetParentLayer ( ) ;
}
2022-08-31 08:51:11 -04:00
2022-09-15 18:06:19 -04:00
const bool bPromptUserToSave = false ;
const bool bSaveMapPackages = true ;
const bool bSaveContentPackages = true ;
const bool bFastSave = false ;
const bool bNotifyNoPackagesSaved = false ;
const bool bCanBeDeclined = true ;
if ( FEditorFileUtils : : SaveDirtyPackages ( bPromptUserToSave , bSaveMapPackages , bSaveContentPackages , bFastSave , bNotifyNoPackagesSaved , bCanBeDeclined , nullptr , [ & PackagesToSaveSet ] ( UPackage * PackageToSave ) { return ! PackagesToSaveSet . Contains ( PackageToSave ) ; } ) )
2022-08-31 08:51:11 -04:00
{
2022-09-15 18:06:19 -04:00
bSuccess = true ;
for ( UPackage * PackageToSave : PackagesToSave )
2022-08-31 08:51:11 -04:00
{
2022-09-15 18:06:19 -04:00
if ( PackageToSave - > IsDirty ( ) )
2022-08-31 08:51:11 -04:00
{
2022-09-15 18:06:19 -04:00
UE_LOG ( LogLevelInstanceEditor , Error , TEXT ( " Package '%s' failed to save " ) , * PackageToSave - > GetName ( ) ) ;
bSuccess = false ;
break ;
2022-08-31 08:51:11 -04:00
}
}
}
}
if ( ! bSuccess )
{
FMessageDialog : : Open ( EAppMsgType : : Ok , LOCTEXT ( " AddPartitionedLevelInstanceStreamingSupportError " , " An error occured when adding partitioned level instance streaming support, check logs for details.. " ) ) ;
}
}
2024-02-22 08:26:27 -05:00
static void UpdatePackedBlueprintsFromMenu ( UToolMenu * Menu , FAssetData WorldAsset )
2023-06-14 06:25:37 -04:00
{
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
FToolUIAction UIAction ;
UIAction . CanExecuteAction . BindLambda ( [ ] ( const FToolMenuContext & MenuContext )
{
return FPackedLevelActorUtils : : CanPack ( ) ;
} ) ;
UIAction . ExecuteAction . BindLambda ( [ WorldAsset ] ( const FToolMenuContext & MenuContext )
{
FScopedSlowTask SlowTask ( 0.0f , LOCTEXT ( " UpdatePackedBlueprintsProgress " , " Updating Packed Blueprints... " ) ) ;
TSet < TSoftObjectPtr < UBlueprint > > BlueprintAssets ;
FPackedLevelActorUtils : : GetPackedBlueprintsForWorldAsset ( TSoftObjectPtr < UWorld > ( WorldAsset . GetSoftObjectPath ( ) ) , BlueprintAssets , false ) ;
2023-06-22 11:32:48 -04:00
TSharedPtr < FPackedLevelActorBuilder > Builder = FPackedLevelActorBuilder : : CreateDefaultBuilder ( ) ;
2023-06-14 06:25:37 -04:00
for ( TSoftObjectPtr < UBlueprint > BlueprintAsset : BlueprintAssets )
{
if ( UBlueprint * Blueprint = BlueprintAsset . Get ( ) )
{
2023-06-22 11:32:48 -04:00
Builder - > UpdateBlueprint ( Blueprint , false ) ;
2023-06-14 06:25:37 -04:00
}
}
} ) ;
Section . AddMenuEntry (
" UpdatePackedBlueprintsFromMenu " ,
LOCTEXT ( " UpdatePackedBlueprintsFromMenu " , " Update Packed Blueprints " ) ,
TAttribute < FText > ( ) ,
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " ClassIcon.PackedLevelActor " ) ,
UIAction
) ;
}
2024-02-22 08:26:27 -05:00
static void AddPartitionedStreamingSupportFromMenu ( UToolMenu * Menu , FAssetData WorldAsset )
2022-08-31 08:51:11 -04:00
{
2022-10-14 16:59:41 -04:00
FName WorldAssetName = WorldAsset . PackageName ;
2023-06-12 07:30:42 -04:00
if ( ! ULevel : : GetIsLevelPartitionedFromPackage ( WorldAssetName ) )
2022-08-31 08:51:11 -04:00
{
FToolMenuSection & Section = CreateLevelSection ( Menu ) ;
FToolUIAction UIAction ;
UIAction . ExecuteAction . BindLambda ( [ WorldAsset ] ( const FToolMenuContext & MenuContext )
{
2022-10-14 16:59:41 -04:00
if ( UWorld * World = Cast < UWorld > ( WorldAsset . GetAsset ( ) ) )
{
AddPartitionedStreamingSupportFromWorld ( World ) ;
}
2022-08-31 08:51:11 -04:00
} ) ;
Section . AddMenuEntry (
" AddPartitionedStreamingSupportFromMenu " ,
LOCTEXT ( " AddPartitionedStreamingSupportFromMenu " , " Add Partitioned Streaming Support " ) ,
TAttribute < FText > ( ) ,
TAttribute < FSlateIcon > ( ) ,
UIAction
) ;
}
}
2020-08-25 06:31:46 -04:00
} ;
2024-04-08 07:37:24 -04:00
class FLevelInstanceActorDetailsSCSEditorUICustomization : public ISCSEditorUICustomization
{
public :
static TSharedPtr < FLevelInstanceActorDetailsSCSEditorUICustomization > GetInstance ( )
{
if ( ! Instance )
{
Instance = MakeShareable ( new FLevelInstanceActorDetailsSCSEditorUICustomization ( ) ) ;
}
return Instance ;
}
virtual bool HideComponentsTree ( TArrayView < UObject * > Context ) const override { return false ; }
virtual bool HideComponentsFilterBox ( TArrayView < UObject * > Context ) const override { return false ; }
virtual bool HideAddComponentButton ( TArrayView < UObject * > Context ) const override { return ShouldHide ( Context ) ; }
virtual bool HideBlueprintButtons ( TArrayView < UObject * > Context ) const override { return ShouldHide ( Context ) ; }
private :
bool ShouldHide ( TArrayView < UObject * > Context ) const
{
for ( const UObject * ContextObject : Context )
{
if ( const AActor * ActorContext = Cast < AActor > ( ContextObject ) )
{
if ( ActorContext - > IsInLevelInstance ( ) & & ! ActorContext - > IsInEditLevelInstance ( ) )
{
return true ;
}
}
}
return false ;
}
static TSharedPtr < FLevelInstanceActorDetailsSCSEditorUICustomization > Instance ;
bool bShouldHide = false ;
} ;
TSharedPtr < FLevelInstanceActorDetailsSCSEditorUICustomization > FLevelInstanceActorDetailsSCSEditorUICustomization : : Instance ;
void FLevelInstanceEditorModule : : OnLevelEditorCreated ( TSharedPtr < ILevelEditor > InLevelEditor )
{
RegisterToFirstLevelEditor ( ) ;
}
void FLevelInstanceEditorModule : : RegisterToFirstLevelEditor ( )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
TSharedPtr < ILevelEditor > FirstLevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) ;
if ( FirstLevelEditor . IsValid ( ) )
{
FirstLevelEditor - > AddActorDetailsSCSEditorUICustomization ( FLevelInstanceActorDetailsSCSEditorUICustomization : : GetInstance ( ) ) ;
2024-05-17 16:28:49 -04:00
FEditorModeTools & LevelEditorModeManager = FirstLevelEditor - > GetEditorModeManager ( ) ;
LevelEditorModeManager . OnEditorModeIDChanged ( ) . AddRaw ( this , & FLevelInstanceEditorModule : : OnEditorModeIDChanged ) ;
// Create a Behavior source for the default EdModeTools (when we aren't in the LevelInstanceEditorMode)
DefaultBehaviorSource = ULevelInstanceEditorMode : : CreateDefaultModeBehaviorSource ( LevelEditorModeManager . GetInteractiveToolsContext ( ) ) ;
LevelEditorModeManager . GetInteractiveToolsContext ( ) - > InputRouter - > RegisterSource ( DefaultBehaviorSource . GetInterface ( ) ) ;
RegisterLevelInstanceColumn ( ) ;
2024-04-08 07:37:24 -04:00
}
}
2020-08-25 06:31:46 -04:00
void FLevelInstanceEditorModule : : StartupModule ( )
{
2024-04-08 07:37:24 -04:00
FLevelEditorModule & LevelEditorModule = FModuleManager : : LoadModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
if ( TSharedPtr < ILevelEditor > FirstLevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) )
{
RegisterToFirstLevelEditor ( ) ;
}
else
{
LevelEditorModule . OnLevelEditorCreated ( ) . AddRaw ( this , & FLevelInstanceEditorModule : : OnLevelEditorCreated ) ;
}
2020-08-25 06:31:46 -04:00
ExtendContextMenu ( ) ;
FPropertyEditorModule & PropertyModule = FModuleManager : : LoadModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
2020-09-11 17:06:48 -04:00
PropertyModule . RegisterCustomClassLayout ( " LevelInstance " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FLevelInstanceActorDetails : : MakeInstance ) ) ;
2023-03-08 12:02:09 -05:00
PropertyModule . RegisterCustomClassLayout ( " LevelInstancePivot " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FLevelInstancePivotDetails : : MakeInstance ) ) ;
2023-06-08 10:14:43 -04:00
PropertyModule . RegisterCustomPropertyTypeLayout ( " WorldPartitionActorFilter " , FOnGetPropertyTypeCustomizationInstance : : CreateStatic ( & FLevelInstanceFilterPropertyTypeCustomization : : MakeInstance , false ) , MakeShared < FLevelInstancePropertyTypeIdentifier > ( false ) ) ;
PropertyModule . RegisterCustomPropertyTypeLayout ( " WorldPartitionActorFilter " , FOnGetPropertyTypeCustomizationInstance : : CreateStatic ( & FLevelInstanceFilterPropertyTypeCustomization : : MakeInstance , true ) , MakeShared < FLevelInstancePropertyTypeIdentifier > ( true ) ) ;
2020-08-25 06:31:46 -04:00
PropertyModule . NotifyCustomizationModuleChanged ( ) ;
// GEditor needs to be set before this module is loaded
check ( GEditor ) ;
GEditor - > OnLevelActorDeleted ( ) . AddRaw ( this , & FLevelInstanceEditorModule : : OnLevelActorDeleted ) ;
EditorLevelUtils : : CanMoveActorToLevelDelegate . AddRaw ( this , & FLevelInstanceEditorModule : : CanMoveActorToLevel ) ;
2023-03-08 12:02:09 -05:00
// Register actor descriptor loading filter
2023-03-10 11:01:34 -05:00
class FLevelInstanceActorDescFilter : public IWorldPartitionActorLoaderInterface : : FActorDescFilter
{
public :
bool PassFilter ( class UWorld * InWorld , const FWorldPartitionHandle & InHandle ) override
2023-03-08 12:02:09 -05:00
{
2023-03-10 11:01:34 -05:00
if ( UWorld * OwningWorld = InWorld - > PersistentLevel - > GetWorld ( ) )
2023-03-08 12:02:09 -05:00
{
2023-03-10 11:01:34 -05:00
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = OwningWorld - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
return LevelInstanceSubsystem - > PassLevelInstanceFilter ( InWorld , InHandle ) ;
}
2023-03-08 12:02:09 -05:00
}
2023-03-10 11:01:34 -05:00
return true ;
2023-03-08 12:02:09 -05:00
}
2023-03-10 11:01:34 -05:00
// Leave [0, 19] for Game code
virtual uint32 GetFilterPriority ( ) const override { return 20 ; }
virtual FText * GetFilterReason ( ) const override
{
static FText UnloadedReason ( LOCTEXT ( " LevelInstanceActorDescFilterReason " , " Filtered " ) ) ;
return & UnloadedReason ;
}
} ;
IWorldPartitionActorLoaderInterface : : RegisterActorDescFilter ( MakeShareable < IWorldPartitionActorLoaderInterface : : FActorDescFilter > ( new FLevelInstanceActorDescFilter ( ) ) ) ;
2023-03-08 12:02:09 -05:00
2020-11-16 08:50:22 -04:00
FMessageLogModule & MessageLogModule = FModuleManager : : LoadModuleChecked < FMessageLogModule > ( " MessageLog " ) ;
FMessageLogInitializationOptions InitOptions ;
InitOptions . bShowFilters = true ;
InitOptions . bShowPages = false ;
InitOptions . bAllowClear = true ;
2022-01-31 10:19:20 -05:00
MessageLogModule . RegisterLogListing ( " PackedLevelActor " , LOCTEXT ( " PackedLevelActorLog " , " Packed Level Actor Log " ) , InitOptions ) ;
2021-11-29 14:47:15 -05:00
FLevelInstanceEditorModeCommands : : Register ( ) ;
2024-04-09 08:42:54 -04:00
ULevelInstanceSubsystem : : RegisterPrimitiveColorHandler ( ) ;
2020-08-25 06:31:46 -04:00
}
void FLevelInstanceEditorModule : : ShutdownModule ( )
{
2024-04-09 08:42:54 -04:00
ULevelInstanceSubsystem : : UnregisterPrimitiveColorHandler ( ) ;
2024-04-08 07:37:24 -04:00
if ( FModuleManager : : Get ( ) . IsModuleLoaded ( " LevelEditor " ) )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
LevelEditorModule . OnLevelEditorCreated ( ) . RemoveAll ( this ) ;
if ( TSharedPtr < ILevelEditor > FirstLevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) )
{
FirstLevelEditor - > RemoveActorDetailsSCSEditorUICustomization ( FLevelInstanceActorDetailsSCSEditorUICustomization : : GetInstance ( ) ) ;
2024-05-17 16:28:49 -04:00
FirstLevelEditor - > GetEditorModeManager ( ) . OnEditorModeIDChanged ( ) . RemoveAll ( this ) ;
FirstLevelEditor - > GetEditorModeManager ( ) . GetInteractiveToolsContext ( ) - > InputRouter - > DeregisterSource ( DefaultBehaviorSource . GetInterface ( ) ) ;
2024-04-08 07:37:24 -04:00
}
2024-05-17 16:28:49 -04:00
DefaultBehaviorSource = nullptr ;
UnregisterLevelInstanceColumn ( ) ;
2024-04-08 07:37:24 -04:00
}
2020-08-25 06:31:46 -04:00
if ( GEditor )
{
GEditor - > OnLevelActorDeleted ( ) . RemoveAll ( this ) ;
}
EditorLevelUtils : : CanMoveActorToLevelDelegate . RemoveAll ( this ) ;
2024-04-17 11:01:35 -04:00
}
TSharedRef < ISceneOutlinerColumn > FLevelInstanceEditorModule : : CreateLevelInstanceColumn ( ISceneOutliner & SceneOutliner ) const
{
return MakeShareable ( new FLevelInstanceSceneOutlinerColumn ( SceneOutliner ) ) ;
}
void FLevelInstanceEditorModule : : RegisterLevelInstanceColumn ( )
{
if ( GetDefault < ULevelInstanceSettings > ( ) - > IsPropertyOverrideEnabled ( ) )
{
FSceneOutlinerModule & SceneOutlinerModule = FModuleManager : : LoadModuleChecked < FSceneOutlinerModule > ( " SceneOutliner " ) ;
FSceneOutlinerColumnInfo ColumnInfo ( ESceneOutlinerColumnVisibility : : Invisible , 8 ,
FCreateSceneOutlinerColumn : : CreateRaw ( this , & FLevelInstanceEditorModule : : CreateLevelInstanceColumn ) ,
2024-04-19 15:13:28 -04:00
true , TOptional < float > ( ) , LOCTEXT ( " LevelInstanceColumnName " , " Level Instance Overrides " ) ) ;
2024-04-17 11:01:35 -04:00
SceneOutlinerModule . RegisterDefaultColumnType < FLevelInstanceSceneOutlinerColumn > ( ColumnInfo ) ;
}
}
void FLevelInstanceEditorModule : : UnregisterLevelInstanceColumn ( )
{
if ( FSceneOutlinerModule * SceneOutlinerModulePtr = FModuleManager : : GetModulePtr < FSceneOutlinerModule > ( " SceneOutliner " ) )
{
SceneOutlinerModulePtr - > UnRegisterColumnType < FLevelInstanceSceneOutlinerColumn > ( ) ;
2021-11-29 14:47:15 -05:00
}
}
void FLevelInstanceEditorModule : : OnEditorModeIDChanged ( const FEditorModeID & InModeID , bool bIsEnteringMode )
{
if ( InModeID = = ULevelInstanceEditorMode : : EM_LevelInstanceEditorModeId & & ! bIsEnteringMode )
{
ExitEditorModeEvent . Broadcast ( ) ;
}
}
2022-01-13 11:53:38 -05:00
void FLevelInstanceEditorModule : : BroadcastTryExitEditorMode ( )
{
TryExitEditorModeEvent . Broadcast ( ) ;
}
2024-02-22 08:26:27 -05:00
void FLevelInstanceEditorModule : : UpdateEditorMode ( bool bActivated )
2021-11-29 14:47:15 -05:00
{
2024-05-17 16:28:49 -04:00
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
if ( TSharedPtr < ILevelEditor > FirstLevelEditor = LevelEditorModule . GetFirstLevelEditor ( ) )
2021-11-29 14:47:15 -05:00
{
2024-05-17 16:28:49 -04:00
if ( bActivated & & ! FirstLevelEditor - > GetEditorModeManager ( ) . IsModeActive ( ULevelInstanceEditorMode : : EM_LevelInstanceEditorModeId ) )
2024-02-22 18:51:06 -05:00
{
2024-05-17 16:28:49 -04:00
FirstLevelEditor - > GetEditorModeManager ( ) . ActivateMode ( ULevelInstanceEditorMode : : EM_LevelInstanceEditorModeId ) ;
2024-02-22 18:51:06 -05:00
}
2024-05-17 16:28:49 -04:00
else if ( ! bActivated & & FirstLevelEditor - > GetEditorModeManager ( ) . IsModeActive ( ULevelInstanceEditorMode : : EM_LevelInstanceEditorModeId ) )
2024-02-22 18:51:06 -05:00
{
2024-05-17 16:28:49 -04:00
FirstLevelEditor - > GetEditorModeManager ( ) . DeactivateMode ( ULevelInstanceEditorMode : : EM_LevelInstanceEditorModeId ) ;
2024-02-22 18:51:06 -05:00
}
2020-08-25 06:31:46 -04:00
}
}
void FLevelInstanceEditorModule : : OnLevelActorDeleted ( AActor * Actor )
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = Actor - > GetWorld ( ) - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
LevelInstanceSubsystem - > OnActorDeleted ( Actor ) ;
}
}
void FLevelInstanceEditorModule : : CanMoveActorToLevel ( const AActor * ActorToMove , const ULevel * DestLevel , bool & bOutCanMove )
{
if ( UWorld * World = ActorToMove - > GetWorld ( ) )
{
if ( ULevelInstanceSubsystem * LevelInstanceSubsystem = World - > GetSubsystem < ULevelInstanceSubsystem > ( ) )
{
if ( ! LevelInstanceSubsystem - > CanMoveActorToLevel ( ActorToMove ) )
{
bOutCanMove = false ;
return ;
}
}
}
}
void FLevelInstanceEditorModule : : ExtendContextMenu ( )
{
2020-11-16 08:50:22 -04:00
if ( UToolMenu * BuildMenu = UToolMenus : : Get ( ) - > ExtendMenu ( " LevelEditor.MainMenu.Build " ) )
{
2021-12-09 08:09:34 -05:00
FToolMenuSection & Section = BuildMenu - > AddSection ( " LevelEditorLevelInstance " , LOCTEXT ( " PackedLevelActorsHeading " , " Packed Level Actor " ) ) ;
2020-11-16 08:50:22 -04:00
FUIAction PackAction (
FExecuteAction : : CreateLambda ( [ ] ( )
{
2023-06-14 06:25:37 -04:00
FPackedLevelActorUtils : : PackAllLoadedActors ( ) ;
2020-11-16 08:50:22 -04:00
} ) ,
FCanExecuteAction : : CreateLambda ( [ ] ( )
{
2023-06-14 06:25:37 -04:00
return FPackedLevelActorUtils : : CanPack ( ) ;
2022-01-07 11:45:52 -05:00
} ) ,
FIsActionChecked ( ) ,
2024-02-22 08:26:27 -05:00
FIsActionButtonVisible ( ) ) ;
2020-11-16 08:50:22 -04:00
2021-12-09 08:09:34 -05:00
FToolMenuEntry & Entry = Section . AddMenuEntry ( NAME_None , LOCTEXT ( " PackLevelActorsTitle " , " Pack Level Actors " ) ,
LOCTEXT ( " PackLevelActorsTooltip " , " Update packed level actor blueprints " ) , FSlateIcon ( ) , PackAction , EUserInterfaceActionType : : Button ) ;
2020-11-16 08:50:22 -04:00
}
2021-12-09 08:09:34 -05:00
auto AddDynamicSection = [ ] ( UToolMenu * ToolMenu )
{
2023-06-14 06:25:37 -04:00
if ( GEditor - > GetPIEWorldContext ( ) )
{
return ;
}
2024-02-22 08:26:27 -05:00
if ( GetDefault < ULevelInstanceSettings > ( ) - > IsLevelInstanceDisabled ( ) )
{
return ;
}
// Build Selection for Menus
TArray < AActor * > SelectedActors ;
TArray < ILevelInstanceInterface * > SelectedLevelInstances ;
SelectedActors . Reserve ( GEditor - > GetSelectedActorCount ( ) ) ;
SelectedLevelInstances . Reserve ( GEditor - > GetSelectedActorCount ( ) ) ;
for ( FSelectionIterator It ( GEditor - > GetSelectedActorIterator ( ) ) ; It ; + + It )
{
if ( AActor * Actor = Cast < AActor > ( * It ) ; IsValid ( Actor ) )
{
SelectedActors . Add ( Actor ) ;
if ( ILevelInstanceInterface * LevelInstance = Cast < ILevelInstanceInterface > ( Actor ) )
{
SelectedLevelInstances . Add ( LevelInstance ) ;
}
}
}
2023-12-04 11:18:06 -05:00
// Some actions aren't allowed on non root selection Level Instances (Readonly Level Instances)
2024-02-22 08:26:27 -05:00
const bool bAreAllSelectedLevelInstancesRootSelections = FLevelInstanceMenuUtils : : AreAllSelectedLevelInstancesRootSelections ( SelectedLevelInstances ) ;
2023-12-04 11:18:06 -05:00
2021-12-09 08:09:34 -05:00
if ( ULevelEditorContextMenuContext * LevelEditorMenuContext = ToolMenu - > Context . FindContext < ULevelEditorContextMenuContext > ( ) )
2020-08-25 06:31:46 -04:00
{
2021-12-09 08:09:34 -05:00
// Use the actor under the cursor if available (e.g. right-click menu).
// Otherwise use the first selected actor if there's one (e.g. Actor pulldown menu or outliner).
2022-06-29 16:22:54 -04:00
AActor * ContextActor = LevelEditorMenuContext - > HitProxyActor . Get ( ) ;
2024-02-22 08:26:27 -05:00
if ( ! ContextActor & & SelectedActors . Num ( ) > 0 )
2020-08-25 06:31:46 -04:00
{
2024-02-22 08:26:27 -05:00
ContextActor = SelectedActors [ 0 ] ;
2020-08-25 06:31:46 -04:00
}
2021-12-09 08:09:34 -05:00
if ( ContextActor )
{
2023-12-04 11:18:06 -05:00
// Allow Edit/Commmit on non root selected Level Instance
2024-02-22 08:26:27 -05:00
FLevelInstanceMenuUtils : : CreateEditMenu ( ToolMenu , ContextActor ) ;
FLevelInstanceMenuUtils : : CreateEditPropertyOverridesMenu ( ToolMenu , ContextActor ) ;
2024-04-19 15:13:28 -04:00
FLevelInstanceMenuUtils : : CreateSaveCancelMenu ( ToolMenu , ContextActor ) ;
2023-12-04 11:18:06 -05:00
if ( bAreAllSelectedLevelInstancesRootSelections )
{
2024-02-22 08:26:27 -05:00
FLevelInstanceMenuUtils : : CreatePackedBlueprintMenu ( ToolMenu , ContextActor ) ;
2023-12-04 11:18:06 -05:00
}
2021-12-09 08:09:34 -05:00
}
}
2023-12-04 11:18:06 -05:00
if ( bAreAllSelectedLevelInstancesRootSelections )
{
2024-02-22 08:26:27 -05:00
FLevelInstanceMenuUtils : : CreateBreakMenu ( ToolMenu , SelectedLevelInstances ) ;
FLevelInstanceMenuUtils : : CreateCreateMenu ( ToolMenu , SelectedActors ) ;
FLevelInstanceMenuUtils : : CreateResetPropertyOverridesMenu ( ToolMenu , SelectedActors , SelectedLevelInstances ) ;
2023-12-04 11:18:06 -05:00
}
2021-12-09 08:09:34 -05:00
} ;
if ( UToolMenu * ToolMenu = UToolMenus : : Get ( ) - > ExtendMenu ( " LevelEditor.ActorContextMenu.LevelSubMenu " ) )
{
ToolMenu - > AddDynamicSection ( " LevelInstanceEditorModuleDynamicSection " , FNewToolMenuDelegate : : CreateLambda ( AddDynamicSection ) ) ;
2020-08-25 06:31:46 -04:00
}
2021-12-09 08:09:34 -05:00
if ( UToolMenu * ToolMenu = UToolMenus : : Get ( ) - > ExtendMenu ( " LevelEditor.LevelEditorSceneOutliner.ContextMenu.LevelSubMenu " ) )
{
ToolMenu - > AddDynamicSection ( " LevelInstanceEditorModuleDynamicSection " , FNewToolMenuDelegate : : CreateLambda ( AddDynamicSection ) ) ;
}
2020-08-25 06:31:46 -04:00
if ( UToolMenu * WorldAssetMenu = UToolMenus : : Get ( ) - > ExtendMenu ( " ContentBrowser.AssetContextMenu.World " ) )
{
FToolMenuSection & Section = WorldAssetMenu - > AddDynamicSection ( " ActorLevelInstance " , FNewToolMenuDelegate : : CreateLambda ( [ this ] ( UToolMenu * ToolMenu )
{
2023-06-14 06:25:37 -04:00
if ( GEditor - > GetPIEWorldContext ( ) )
{
return ;
}
2024-02-22 08:26:27 -05:00
if ( GetDefault < ULevelInstanceSettings > ( ) - > IsLevelInstanceDisabled ( ) )
2022-01-07 11:45:52 -05:00
{
return ;
}
2020-08-25 06:31:46 -04:00
if ( ToolMenu )
{
if ( UContentBrowserAssetContextMenuContext * AssetMenuContext = ToolMenu - > Context . FindContext < UContentBrowserAssetContextMenuContext > ( ) )
{
2022-10-14 16:59:41 -04:00
if ( AssetMenuContext - > SelectedAssets . Num ( ) ! = 1 )
2020-08-25 06:31:46 -04:00
{
return ;
}
2022-10-14 16:59:41 -04:00
const FAssetData & WorldAsset = AssetMenuContext - > SelectedAssets [ 0 ] ;
if ( AssetMenuContext - > SelectedAssets [ 0 ] . IsInstanceOf < UWorld > ( ) )
2020-08-25 06:31:46 -04:00
{
2024-02-22 08:26:27 -05:00
FLevelInstanceMenuUtils : : CreateBlueprintFromMenu ( ToolMenu , WorldAsset ) ;
FLevelInstanceMenuUtils : : UpdatePackedBlueprintsFromMenu ( ToolMenu , WorldAsset ) ;
FLevelInstanceMenuUtils : : AddPartitionedStreamingSupportFromMenu ( ToolMenu , WorldAsset ) ;
2020-08-25 06:31:46 -04:00
}
}
}
} ) , FToolMenuInsert ( NAME_None , EToolMenuInsertType : : Default ) ) ;
}
}
2023-11-16 13:35:30 -05:00
bool FLevelInstanceEditorModule : : IsEditInPlaceStreamingEnabled ( ) const
{
return GetDefault < ULevelInstanceEditorSettings > ( ) - > bIsEditInPlaceStreamingEnabled ;
}
2020-08-25 06:31:46 -04:00
2024-04-11 13:47:04 -04:00
bool FLevelInstanceEditorModule : : IsSubSelectionEnabled ( ) const
{
return GetDefault < ULevelInstanceEditorPerProjectUserSettings > ( ) - > bIsSubSelectionEnabled ;
}
void FLevelInstanceEditorModule : : AddReferencedObjects ( FReferenceCollector & Collector )
{
DefaultBehaviorSource . AddReferencedObjects ( Collector ) ;
}
2023-11-16 13:35:30 -05:00
# undef LOCTEXT_NAMESPACE