2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "UnrealEd.h"
2014-05-22 06:52:28 -04:00
# include "Matinee/InterpData.h"
# include "Matinee/MatineeActor.h"
2014-05-29 17:01:48 -04:00
# include "Animation/AnimCompress.h"
2014-05-22 06:52:28 -04:00
2014-05-21 10:00:58 -04:00
# include "EditorSupportDelegates.h"
2014-03-14 14:13:41 -04:00
# include "SoundDefinitions.h"
# include "BusyCursor.h"
# include "EditorLevelUtils.h"
# include "AVIWriter.h"
# include "Editor/PropertyEditor/Public/PropertyEditorModule.h"
# include "Editor/LevelEditor/Public/LevelEditor.h"
# include "Editor/MainFrame/Public/MainFrame.h"
# include "CrashTracker.h"
# include "AssetToolsModule.h"
# include "EditorLoadingSavingSettingsCustomization.h"
# include "GameMapsSettingsCustomization.h"
# include "LevelEditorPlaySettingsCustomization.h"
2014-05-12 17:10:39 -04:00
# include "ProjectPackagingSettingsCustomization.h"
2014-03-14 14:13:41 -04:00
# include "Editor/StatsViewer/Public/StatsViewerModule.h"
# include "SnappingUtils.h"
# include "PackageAutoSaver.h"
2014-06-26 14:47:39 -04:00
# include "PerformanceMonitor.h"
2014-03-14 14:13:41 -04:00
# include "BSPOps.h"
# include "ComponentVisualizer.h"
2014-06-24 12:11:51 -04:00
# include "Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h"
2014-11-14 02:05:33 -05:00
# include "SourceCodeNavigation.h"
2015-01-26 18:20:53 -05:00
# include "AutoReimport/AutoReimportManager.h"
2015-01-12 11:19:17 -05:00
# include "NotificationManager.h"
# include "SNotificationList.h"
2015-05-27 16:16:21 -04:00
# include "AutoReimport/AssetSourceFilenameCache.h"
2015-04-01 03:03:18 -04:00
# include "UObject/UObjectThreadContext.h"
2015-04-10 03:30:54 -04:00
# include "Components/BillboardComponent.h"
# include "Components/ArrowComponent.h"
# include "Engine/Selection.h"
# include "EngineUtils.h"
2014-03-14 14:13:41 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogUnrealEdEngine , Log , All ) ;
void UUnrealEdEngine : : Init ( IEngineLoop * InEngineLoop )
{
Super : : Init ( InEngineLoop ) ;
2014-11-14 02:05:33 -05:00
// Build databases used by source code navigation
FSourceCodeNavigation : : Initialize ( ) ;
2014-03-14 14:13:41 -04:00
PackageAutoSaver . Reset ( new FPackageAutoSaver ) ;
PackageAutoSaver - > LoadRestoreFile ( ) ;
2014-07-01 09:18:15 -04:00
# if !UE_BUILD_DEBUG
2015-04-20 10:12:55 -04:00
if ( ! GEditorSettingsIni . IsEmpty ( ) )
2014-07-07 05:24:55 -04:00
{
// We need the game agnostic ini for this code
PerformanceMonitor = new FPerformanceMonitor ;
}
2014-07-01 09:18:15 -04:00
# endif
2014-06-26 14:47:39 -04:00
2014-03-14 14:13:41 -04:00
// Register for the package dirty state updated callback to catch packages that have been modified and need to be checked out.
2014-06-18 11:26:28 -04:00
UPackage : : PackageDirtyStateChangedEvent . AddUObject ( this , & UUnrealEdEngine : : OnPackageDirtyStateUpdated ) ;
2014-03-14 14:13:41 -04:00
// Register to the PostGarbageCollect delegate, as we want to use this to trigger the RefreshAllBroweser delegate from
// here rather then from Core
2014-10-02 06:13:35 -04:00
FCoreUObjectDelegates : : PostGarbageCollect . AddUObject ( this , & UUnrealEdEngine : : OnPostGarbageCollect ) ;
2014-03-14 14:13:41 -04:00
// register to color picker changed event and trigger RedrawAllViewports when that happens */
FCoreDelegates : : ColorPickerChanged . AddUObject ( this , & UUnrealEdEngine : : OnColorPickerChanged ) ;
// register windows message pre and post handler
FEditorSupportDelegates : : PreWindowsMessage . AddUObject ( this , & UUnrealEdEngine : : OnPreWindowsMessage ) ;
FEditorSupportDelegates : : PostWindowsMessage . AddUObject ( this , & UUnrealEdEngine : : OnPostWindowsMessage ) ;
// Initialize the snap manager
FSnappingUtils : : InitEditorSnappingTools ( ) ;
2014-11-14 02:45:36 -05:00
// Register for notification of volume changes
2014-03-14 14:13:41 -04:00
AVolume : : GetOnVolumeShapeChangedDelegate ( ) . AddStatic ( & FBSPOps : : HandleVolumeShapeChanged ) ;
//
InitBuilderBrush ( GWorld ) ;
// Iterate over all always fully loaded packages and load them.
if ( ! IsRunningCommandlet ( ) )
{
for ( int32 PackageNameIndex = 0 ; PackageNameIndex < PackagesToBeFullyLoadedAtStartup . Num ( ) ; PackageNameIndex + + )
{
const FString & PackageName = PackagesToBeFullyLoadedAtStartup [ PackageNameIndex ] ;
// Load package if it's found in the package file cache.
if ( FPackageName : : DoesPackageExist ( PackageName ) )
{
LoadPackage ( NULL , * PackageName , LOAD_None ) ;
}
}
}
// Populate the data structures related to the sprite category visibility feature for use elsewhere in the editor later
TArray < FSpriteCategoryInfo > SortedSpriteInfo ;
2014-11-11 19:58:48 -05:00
UUnrealEdEngine : : MakeSortedSpriteInfo ( SortedSpriteInfo ) ;
2014-03-14 14:13:41 -04:00
// Iterate over the sorted list, constructing a mapping of unlocalized categories to the index the localized category
// resides in. This is an optimization to prevent having to localize values repeatedly.
for ( int32 InfoIndex = 0 ; InfoIndex < SortedSpriteInfo . Num ( ) ; + + InfoIndex )
{
const FSpriteCategoryInfo & SpriteInfo = SortedSpriteInfo [ InfoIndex ] ;
SpriteIDToIndexMap . Add ( SpriteInfo . Category , InfoIndex ) ;
}
2015-02-02 06:39:48 -05:00
if ( FPaths : : IsProjectFilePathSet ( ) )
{
2015-02-03 05:40:57 -05:00
AutoReimportManager = NewObject < UAutoReimportManager > ( ) ;
2015-02-02 06:39:48 -05:00
AutoReimportManager - > Initialize ( ) ;
2015-04-02 07:42:21 -04:00
GetMutableDefault < UEditorLoadingSavingSettings > ( ) - > CheckSourceControlCompatability ( ) ;
2015-02-02 06:39:48 -05:00
}
2014-03-14 14:13:41 -04:00
// register details panel customizations
if ( ! HasAnyFlags ( RF_ClassDefaultObject ) )
{
FPropertyEditorModule & PropertyModule = FModuleManager : : LoadModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
2014-06-04 12:11:33 -04:00
PropertyModule . RegisterCustomClassLayout ( " EditorLoadingSavingSettings " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FEditorLoadingSavingSettingsCustomization : : MakeInstance ) ) ;
PropertyModule . RegisterCustomClassLayout ( " GameMapsSettings " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FGameMapsSettingsCustomization : : MakeInstance ) ) ;
PropertyModule . RegisterCustomClassLayout ( " LevelEditorPlaySettings " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FLevelEditorPlaySettingsCustomization : : MakeInstance ) ) ;
PropertyModule . RegisterCustomClassLayout ( " ProjectPackagingSettings " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FProjectPackagingSettingsCustomization : : MakeInstance ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:33:25 -04:00
2015-06-16 12:43:26 -04:00
if ( ! IsRunningCommandlet ( ) )
2014-04-23 18:33:25 -04:00
{
2015-06-16 12:43:26 -04:00
UEditorExperimentalSettings const * ExperimentalSettings = GetDefault < UEditorExperimentalSettings > ( ) ;
ECookInitializationFlags BaseCookingFlags = ECookInitializationFlags : : AutoTick | ECookInitializationFlags : : AsyncSave | ECookInitializationFlags : : Compressed ;
BaseCookingFlags | = ExperimentalSettings - > bIterativeCookingForLaunchOn ? ECookInitializationFlags : : Iterative : ECookInitializationFlags : : None ;
2014-05-02 10:44:16 -04:00
2015-06-16 12:43:26 -04:00
bool bEnableCookOnTheSide = false ;
GConfig - > GetBool ( TEXT ( " /Script/UnrealEd.CookerSettings " ) , TEXT ( " bEnableCookOnTheSide " ) , bEnableCookOnTheSide , GEngineIni ) ;
2015-01-19 10:58:46 -05:00
2015-06-16 12:43:26 -04:00
if ( bEnableCookOnTheSide )
{
CookServer = NewObject < UCookOnTheFlyServer > ( ) ;
CookServer - > Initialize ( ECookMode : : CookOnTheFlyFromTheEditor , BaseCookingFlags ) ;
CookServer - > StartNetworkFileServer ( false ) ;
}
else if ( ! ExperimentalSettings - > bDisableCookInEditor )
{
CookServer = NewObject < UCookOnTheFlyServer > ( ) ;
CookServer - > Initialize ( ECookMode : : CookByTheBookFromTheEditor , BaseCookingFlags ) ;
}
2014-09-16 12:15:46 -04:00
}
}
2015-01-29 17:25:52 -05:00
bool CanCookForPlatformInThisProcess ( const FString & PlatformName )
{
////////////////////////////////////////
// hack remove this hack when we properly support changing the mobileHDR setting
// check if our mobile hdr setting in memory is different from the one which is saved in the config file
2015-03-13 12:27:30 -04:00
FConfigFile PlatformEngineIni ;
GConfig - > LoadLocalIniFile ( PlatformEngineIni , TEXT ( " Engine " ) , true , * PlatformName ) ;
FString IniValueString ;
2015-01-29 17:25:52 -05:00
bool ConfigSetting = false ;
2015-03-13 12:27:30 -04:00
if ( PlatformEngineIni . GetString ( TEXT ( " /Script/Engine.RendererSettings " ) , TEXT ( " r.MobileHDR " ) , IniValueString ) = = false )
2015-01-29 17:25:52 -05:00
{
2015-03-13 12:27:30 -04:00
// must always match the RSetting setting because we don't have a config setting
return true ;
2015-01-29 17:25:52 -05:00
}
2015-03-13 12:27:30 -04:00
ConfigSetting = IniValueString . ToBool ( ) ;
2015-01-29 17:25:52 -05:00
// this was stolen from void IsMobileHDR()
static auto * MobileHDRCvar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.MobileHDR " ) ) ;
const bool CurrentRSetting = MobileHDRCvar - > GetValueOnAnyThread ( ) = = 1 ;
if ( CurrentRSetting ! = ConfigSetting )
{
2015-03-13 12:27:30 -04:00
UE_LOG ( LogUnrealEdEngine , Warning , TEXT ( " Unable to use cook in editor because r.MobileHDR from Engine ini doesn't match console value r.MobileHDR " ) ) ;
2015-01-29 17:25:52 -05:00
return false ;
}
////////////////////////////////////////
return true ;
}
bool UUnrealEdEngine : : CanCookByTheBookInEditor ( const FString & PlatformName ) const
{
if ( CanCookForPlatformInThisProcess ( PlatformName ) = = false )
{
return false ;
}
2014-09-16 12:15:46 -04:00
if ( CookServer )
{
return CookServer - > GetCookMode ( ) = = ECookMode : : CookByTheBookFromTheEditor ;
}
return false ;
}
2015-01-29 17:25:52 -05:00
bool UUnrealEdEngine : : CanCookOnTheFlyInEditor ( const FString & PlatformName ) const
2015-01-19 10:58:46 -05:00
{
2015-01-29 17:25:52 -05:00
if ( CanCookForPlatformInThisProcess ( PlatformName ) = = false )
{
return false ;
}
2015-01-19 10:58:46 -05:00
if ( CookServer )
{
return CookServer - > GetCookMode ( ) = = ECookMode : : CookOnTheFlyFromTheEditor ;
}
return false ;
}
2014-09-16 12:15:46 -04:00
void UUnrealEdEngine : : StartCookByTheBookInEditor ( const TArray < ITargetPlatform * > & TargetPlatforms , const TArray < FString > & CookMaps , const TArray < FString > & CookDirectories , const TArray < FString > & CookCultures , const TArray < FString > & IniMapSections )
{
2014-12-10 10:12:47 -05:00
UCookOnTheFlyServer : : FCookByTheBookStartupOptions StartupOptions ;
StartupOptions . CookMaps = CookMaps ;
StartupOptions . TargetPlatforms = TargetPlatforms ;
StartupOptions . CookDirectories = CookDirectories ;
StartupOptions . CookCultures = CookCultures ;
StartupOptions . IniMapSections = IniMapSections ;
CookServer - > StartCookByTheBook ( StartupOptions ) ;
2014-09-16 12:15:46 -04:00
}
bool UUnrealEdEngine : : IsCookByTheBookInEditorFinished ( ) const
{
return ! CookServer - > IsCookByTheBookRunning ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-22 14:29:26 -04:00
void UUnrealEdEngine : : CancelCookByTheBookInEditor ( )
{
CookServer - > QueueCancelCookByTheBook ( ) ;
}
2014-11-11 19:58:48 -05:00
void UUnrealEdEngine : : MakeSortedSpriteInfo ( TArray < FSpriteCategoryInfo > & OutSortedSpriteInfo )
2014-03-14 14:13:41 -04:00
{
struct Local
{
static void AddSortedSpriteInfo ( TArray < FSpriteCategoryInfo > & InOutSortedSpriteInfo , const FSpriteCategoryInfo & InSpriteInfo )
{
const FSpriteCategoryInfo * ExistingSpriteInfo = InOutSortedSpriteInfo . FindByPredicate ( [ & InSpriteInfo ] ( const FSpriteCategoryInfo & SpriteInfo ) { return InSpriteInfo . Category = = SpriteInfo . Category ; } ) ;
if ( ExistingSpriteInfo ! = NULL )
{
//Already present
checkSlow ( ExistingSpriteInfo - > DisplayName . EqualTo ( InSpriteInfo . DisplayName ) ) ; //Catch mismatches between DisplayNames
}
else
{
// Add the category to the correct position in the array to keep it sorted
const int32 CatIndex = InOutSortedSpriteInfo . IndexOfByPredicate ( [ & InSpriteInfo ] ( const FSpriteCategoryInfo & SpriteInfo ) { return InSpriteInfo . DisplayName . CompareTo ( SpriteInfo . DisplayName ) < 0 ; } ) ;
if ( CatIndex ! = INDEX_NONE )
{
InOutSortedSpriteInfo . Insert ( InSpriteInfo , CatIndex ) ;
}
else
{
InOutSortedSpriteInfo . Add ( InSpriteInfo ) ;
}
}
}
} ;
// Iterate over all classes searching for those which derive from AActor and are neither deprecated nor abstract.
// It would be nice to only check placeable classes here, but we cannot do that as some non-placeable classes
// still end up in the editor (with sprites) procedurally, such as prefab instances and landscape actors.
for ( auto * Class : TObjectRange < UClass > ( ) )
{
if ( Class - > IsChildOf ( AActor : : StaticClass ( ) )
& & ! ( Class - > HasAnyClassFlags ( CLASS_Abstract | CLASS_Deprecated ) ) )
{
// Check if the class default actor has billboard components or arrow components that should be treated as
// sprites, and if so, add their categories to the array
const AActor * CurDefaultClassActor = Class - > GetDefaultObject < AActor > ( ) ;
if ( CurDefaultClassActor )
{
2014-12-18 17:02:31 -05:00
TInlineComponentArray < UActorComponent * > Components ;
2014-03-14 14:13:41 -04:00
CurDefaultClassActor - > GetComponents ( Components ) ;
for ( auto * Comp : Components )
{
const UBillboardComponent * CurSpriteComponent = Cast < UBillboardComponent > ( Comp ) ;
const UArrowComponent * CurArrowComponent = ( CurSpriteComponent ? NULL : Cast < UArrowComponent > ( Comp ) ) ;
if ( CurSpriteComponent )
{
Local : : AddSortedSpriteInfo ( OutSortedSpriteInfo , CurSpriteComponent - > SpriteInfo ) ;
}
else if ( CurArrowComponent & & CurArrowComponent - > bTreatAsASprite )
{
Local : : AddSortedSpriteInfo ( OutSortedSpriteInfo , CurArrowComponent - > SpriteInfo ) ;
}
}
}
}
}
// It wont find sounds, but we want it to be there
{
FSpriteCategoryInfo SpriteInfo ;
SpriteInfo . Category = TEXT ( " Sounds " ) ;
SpriteInfo . DisplayName = NSLOCTEXT ( " SpriteCategory " , " Sounds " , " Sounds " ) ;
Local : : AddSortedSpriteInfo ( OutSortedSpriteInfo , SpriteInfo ) ;
}
}
void UUnrealEdEngine : : PreExit ( )
{
2015-05-27 16:16:21 -04:00
FAssetSourceFilenameCache : : Get ( ) . Shutdown ( ) ;
2014-03-14 14:13:41 -04:00
// Notify edit modes we're mode at exit
2014-06-18 10:16:16 -04:00
FEditorModeRegistry : : Get ( ) . Shutdown ( ) ;
2014-03-14 14:13:41 -04:00
FAVIWriter * AVIWriter = FAVIWriter : : GetInstance ( ) ;
if ( AVIWriter )
{
AVIWriter - > Close ( ) ;
}
Super : : PreExit ( ) ;
}
UUnrealEdEngine : : ~ UUnrealEdEngine ( )
{
if ( this = = GUnrealEd )
{
GUnrealEd = NULL ;
}
}
void UUnrealEdEngine : : FinishDestroy ( )
{
2014-05-02 10:44:16 -04:00
if ( CookServer )
{
2014-10-02 06:13:35 -04:00
FCoreUObjectDelegates : : OnObjectPropertyChanged . RemoveAll ( CookServer ) ;
FCoreUObjectDelegates : : OnObjectModified . RemoveAll ( CookServer ) ;
2014-05-02 10:44:16 -04:00
}
2014-03-14 14:13:41 -04:00
if ( PackageAutoSaver . Get ( ) )
{
// We've finished shutting down, so disable the auto-save restore
PackageAutoSaver - > UpdateRestoreFile ( false ) ;
PackageAutoSaver . Reset ( ) ;
}
2014-07-01 09:18:15 -04:00
if ( PerformanceMonitor )
{
delete PerformanceMonitor ;
}
2014-06-26 14:47:39 -04:00
2014-06-18 11:26:28 -04:00
UPackage : : PackageDirtyStateChangedEvent . RemoveAll ( this ) ;
2014-10-02 06:13:35 -04:00
FCoreUObjectDelegates : : PostGarbageCollect . RemoveAll ( this ) ;
2014-03-14 14:13:41 -04:00
FCoreDelegates : : ColorPickerChanged . RemoveAll ( this ) ;
Super : : FinishDestroy ( ) ;
}
void UUnrealEdEngine : : Tick ( float DeltaSeconds , bool bIdleMode )
{
Super : : Tick ( DeltaSeconds , bIdleMode ) ;
// Increment the "seconds since last autosave" counter, then try to autosave.
if ( ! GSlowTaskOccurred )
{
// Don't increment autosave count while in game/pie/automation testing or while in Matinee
const bool PauseAutosave = ( PlayWorld ! = NULL ) | | GIsAutomationTesting ;
if ( ! PauseAutosave & & PackageAutoSaver . Get ( ) )
{
PackageAutoSaver - > UpdateAutoSaveCount ( DeltaSeconds ) ;
}
}
if ( ! GIsSlowTask )
{
GSlowTaskOccurred = false ;
}
// Display any load errors that happened while starting up the editor.
static bool bFirstTick = true ;
if ( bFirstTick )
{
FEditorDelegates : : DisplayLoadErrors . Broadcast ( ) ;
}
bFirstTick = false ;
if ( PackageAutoSaver . Get ( ) )
{
PackageAutoSaver - > AttemptAutoSave ( ) ;
}
// Try and notify the user about modified packages needing checkout
AttemptModifiedPackageNotification ( ) ;
// Attempt to warn about any packages that have been modified but were previously
// saved with an engine version newer than the current one
AttemptWarnAboutPackageEngineVersions ( ) ;
// Attempt to warn about any packages that have been modified but the user
// does not have permission to write them to disk
AttemptWarnAboutWritePermission ( ) ;
// Update lightmass
UpdateBuildLighting ( ) ;
FAVIWriter * AVIWriter = FAVIWriter : : GetInstance ( ) ;
if ( AVIWriter )
{
AVIWriter - > Update ( DeltaSeconds ) ;
}
ICrashTrackerModule * CrashTracker = FModuleManager : : LoadModulePtr < ICrashTrackerModule > ( FName ( " CrashTracker " ) ) ;
2014-06-24 12:11:51 -04:00
bool bCrashTrackerEnabled = false ;
2014-03-14 14:13:41 -04:00
if ( CrashTracker )
{
CrashTracker - > Update ( DeltaSeconds ) ;
2014-06-24 12:11:51 -04:00
bCrashTrackerEnabled = CrashTracker - > IsCurrentlyCapturing ( ) ;
}
// Only allow live streaming if crash tracker is disabled. This is because the SlateRHIRenderer shares the same render targets
// for both crash tracker and live editor streaming, and we don't want them to be thrashed every frame.
if ( ! bCrashTrackerEnabled )
{
// If the editor is configured to broadcast frames, do that now
if ( IEditorLiveStreaming : : Get ( ) . IsBroadcastingEditor ( ) )
{
IEditorLiveStreaming : : Get ( ) . BroadcastEditorVideoFrame ( ) ;
}
2014-03-14 14:13:41 -04:00
}
}
void UUnrealEdEngine : : OnPackageDirtyStateUpdated ( UPackage * Pkg )
{
// The passed in object should never be NULL
check ( Pkg ) ;
UPackage * Package = Pkg - > GetOutermost ( ) ;
const FString PackageName = Package - > GetName ( ) ;
// Alert the user if they have modified a package that won't be able to be saved because
2015-04-10 03:30:54 -04:00
// it's already been saved with an engine version that is newer than the current one.
2015-04-01 03:03:18 -04:00
if ( ! FUObjectThreadContext : : Get ( ) . IsRoutingPostLoad & & Package - > IsDirty ( ) & & ! PackagesCheckedForEngineVersion . Contains ( PackageName ) )
2014-03-14 14:13:41 -04:00
{
EWriteDisallowedWarningState WarningStateToSet = WDWS_WarningUnnecessary ;
FString PackageFileName ;
if ( FPackageName : : DoesPackageExist ( Package - > GetName ( ) , NULL , & PackageFileName ) )
{
// If a package has never been loaded, a file reader is necessary to find the package file summary for its saved engine version.
FArchive * PackageReader = IFileManager : : Get ( ) . CreateFileReader ( * PackageFileName ) ;
if ( PackageReader )
{
FPackageFileSummary Summary ;
* PackageReader < < Summary ;
2015-03-11 13:18:45 -04:00
if ( Summary . GetFileVersionUE4 ( ) > GPackageFileUE4Version | | ! GEngineVersion . IsCompatibleWith ( Summary . CompatibleWithEngineVersion ) )
2014-03-14 14:13:41 -04:00
{
WarningStateToSet = WDWS_PendingWarn ;
bNeedWarningForPkgEngineVer = true ;
}
}
delete PackageReader ;
}
PackagesCheckedForEngineVersion . Add ( PackageName , WarningStateToSet ) ;
}
// Alert the user if they have modified a package that they do not have sufficient permission to write to disk.
// This can be due to the content being in the "Program Files" folder and the user does not have admin privileges.
2015-04-01 03:03:18 -04:00
if ( ! FUObjectThreadContext : : Get ( ) . IsRoutingPostLoad & & Package - > IsDirty ( ) & & ! PackagesCheckedForWritePermission . Contains ( PackageName ) )
2014-03-14 14:13:41 -04:00
{
EWriteDisallowedWarningState WarningStateToSet = GetWarningStateForWritePermission ( PackageName ) ;
if ( WarningStateToSet = = WDWS_PendingWarn )
{
bNeedWarningForWritePermission = true ;
}
PackagesCheckedForWritePermission . Add ( PackageName , WarningStateToSet ) ;
}
if ( Package - > IsDirty ( ) )
{
// Find out if we have already asked the user to modify this package
const uint8 * PromptState = PackageToNotifyState . Find ( Package ) ;
const bool bAlreadyAsked = PromptState ! = NULL ;
// During an autosave, packages are saved in the autosave directory which switches off their dirty flags.
// To preserve the pre-autosave state, any saved package is then remarked as dirty because it wasn't saved in the normal location where it would be picked up by source control.
2015-01-12 11:19:17 -05:00
// Any callback that happens during an autosave is bogus since a package wasn't marked dirty due to a user modification.
2014-03-14 14:13:41 -04:00
const bool bIsAutoSaving = PackageAutoSaver . Get ( ) & & PackageAutoSaver - > IsAutoSaving ( ) ;
2015-01-12 11:19:17 -05:00
const UEditorLoadingSavingSettings * Settings = GetDefault < UEditorLoadingSavingSettings > ( ) ;
2014-03-14 14:13:41 -04:00
if ( ! bIsAutoSaving & &
! GIsEditorLoadingPackage & & // Don't ask if the package was modified as a result of a load
! bAlreadyAsked & & // Don't ask if we already asked once!
2015-01-12 11:19:17 -05:00
( Settings - > bPromptForCheckoutOnAssetModification | | Settings - > bAutomaticallyCheckoutOnAssetModification ) )
2014-03-14 14:13:41 -04:00
{
2015-01-12 11:19:17 -05:00
// Force source control state to be updated
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-12 11:19:17 -05:00
TArray < FString > Files ;
Files . Add ( SourceControlHelpers : : PackageFilename ( Package ) ) ;
SourceControlProvider . Execute ( ISourceControlOperation : : Create < FUpdateStatus > ( ) , SourceControlHelpers : : AbsoluteFilenames ( Files ) , EConcurrency : : Asynchronous , FSourceControlOperationComplete : : CreateUObject ( this , & UUnrealEdEngine : : OnSourceControlStateUpdated , TWeakObjectPtr < UPackage > ( Package ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
// This package was saved, the user should be prompted again if they checked in the package
PackageToNotifyState . Remove ( Package ) ;
}
}
2015-01-12 11:19:17 -05:00
void UUnrealEdEngine : : OnSourceControlStateUpdated ( const FSourceControlOperationRef & SourceControlOp , ECommandResult : : Type ResultType , TWeakObjectPtr < UPackage > Package )
{
if ( ResultType = = ECommandResult : : Succeeded & & Package . IsValid ( ) )
{
// Get the source control state of the package
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( Package . Get ( ) , EStateCacheUsage : : Use ) ;
if ( SourceControlState . IsValid ( ) )
{
const UEditorLoadingSavingSettings * Settings = GetDefault < UEditorLoadingSavingSettings > ( ) ;
check ( Settings - > bPromptForCheckoutOnAssetModification | | Settings - > bAutomaticallyCheckoutOnAssetModification ) ;
if ( Settings - > bAutomaticallyCheckoutOnAssetModification & & SourceControlState - > CanCheckout ( ) )
{
// Automatically check out asset
TArray < FString > Files ;
Files . Add ( SourceControlHelpers : : PackageFilename ( Package . Get ( ) ) ) ;
SourceControlProvider . Execute ( ISourceControlOperation : : Create < FCheckOut > ( ) , SourceControlHelpers : : AbsoluteFilenames ( Files ) , EConcurrency : : Asynchronous , FSourceControlOperationComplete : : CreateUObject ( this , & UUnrealEdEngine : : OnPackageCheckedOut , TWeakObjectPtr < UPackage > ( Package ) ) ) ;
}
else
{
2015-06-22 16:29:03 -04:00
// Note when cooking in the editor we ignore package notifications. The cooker is saving packages in a temp location which generates bogus checkout messages otherwise.
if ( ( SourceControlState - > CanCheckout ( ) | | ! SourceControlState - > IsCurrent ( ) | | SourceControlState - > IsCheckedOutOther ( ) ) & & ( ! CookServer | | ! CookServer - > IsCookingInEditor ( ) ) )
2015-01-12 11:19:17 -05:00
{
// To get here, either "prompt for checkout on asset modification" is set, or "automatically checkout on asset modification"
// is set, but it failed.
2015-06-22 16:29:03 -04:00
// Allow packages that are not checked out to pass through.
// Allow packages that are not current or checked out by others pass through.
// The user wont be able to checkout these packages but the checkout dialog will show up with a special icon
// to let the user know they wont be able to checkout the package they are modifying.
2015-01-12 11:19:17 -05:00
PackageToNotifyState . Add ( Package , SourceControlState - > CanCheckout ( ) ? NS_PendingPrompt : NS_PendingWarning ) ;
2015-06-22 16:29:03 -04:00
// We need to prompt since a new package was added
bNeedToPromptForCheckout = true ;
}
}
2015-01-12 11:19:17 -05:00
}
}
}
void UUnrealEdEngine : : OnPackageCheckedOut ( const FSourceControlOperationRef & SourceControlOp , ECommandResult : : Type ResultType , TWeakObjectPtr < UPackage > Package )
{
if ( Package . IsValid ( ) )
{
// Get the source control state of the package
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( Package . Get ( ) , EStateCacheUsage : : Use ) ;
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " Package " ) , FText : : FromString ( Package - > GetName ( ) ) ) ;
if ( ResultType = = ECommandResult : : Succeeded )
{
if ( SourceControlState . IsValid ( ) & & SourceControlState - > IsCheckedOut ( ) )
2015-01-26 18:20:53 -05:00
{
2015-01-12 11:19:17 -05:00
FNotificationInfo Notification ( FText : : Format ( NSLOCTEXT ( " SourceControl " , " AutoCheckOutNotification " , " Package '{Package}' automatically checked out. " ) , Arguments ) ) ;
Notification . bFireAndForget = true ;
Notification . ExpireDuration = 4.0f ;
Notification . bUseThrobber = true ;
FSlateNotificationManager : : Get ( ) . AddNotification ( Notification ) ;
return ;
}
}
FNotificationInfo ErrorNotification ( FText : : Format ( NSLOCTEXT ( " SourceControl " , " AutoCheckOutFailedNotification " , " Unable to automatically check out Package '{Package}'. " ) , Arguments ) ) ;
ErrorNotification . bFireAndForget = true ;
ErrorNotification . ExpireDuration = 4.0f ;
ErrorNotification . bUseThrobber = true ;
FSlateNotificationManager : : Get ( ) . AddNotification ( ErrorNotification ) ;
// Automatic checkout failed - pop up the notification for manual checkout
PackageToNotifyState . Add ( Package , SourceControlState - > CanCheckout ( ) ? NS_PendingPrompt : NS_PendingWarning ) ;
bNeedToPromptForCheckout = true ;
}
}
2014-03-14 14:13:41 -04:00
void UUnrealEdEngine : : OnPostGarbageCollect ( )
{
// Refresh Editor browsers after GC in case objects where removed. Note that if the user is currently
// playing in a PIE level, we don't want to interrupt performance by refreshing the Generic Browser window.
if ( GIsEditor & & ! GIsPlayInEditorWorld )
{
FEditorDelegates : : RefreshAllBrowsers . Broadcast ( ) ;
}
// Clean up any GCed packages in the PackageToNotifyState
for ( TMap < TWeakObjectPtr < UPackage > , uint8 > : : TIterator It ( PackageToNotifyState ) ; It ; + + It )
{
if ( It . Key ( ) . IsValid ( ) = = false )
{
It . RemoveCurrent ( ) ;
}
}
}
void UUnrealEdEngine : : OnColorPickerChanged ( )
{
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
FEditorSupportDelegates : : PreWindowsMessage . RemoveAll ( this ) ;
FEditorSupportDelegates : : PostWindowsMessage . RemoveAll ( this ) ;
}
UWorld * SavedGWorld = NULL ;
void UUnrealEdEngine : : OnPreWindowsMessage ( FViewport * Viewport , uint32 Message )
{
// Make sure the proper GWorld is set before handling the windows message
if ( GEditor - > GameViewport & & ! GUnrealEd - > bIsSimulatingInEditor & & GEditor - > GameViewport - > Viewport = = Viewport & & ! GIsPlayInEditorWorld )
{
// remember the current GWorld that will be restored in the PostWindowsMessage callback
SavedGWorld = GWorld ;
SetPlayInEditorWorld ( GEditor - > PlayWorld ) ;
}
else
{
SavedGWorld = NULL ;
}
}
void UUnrealEdEngine : : OnPostWindowsMessage ( FViewport * Viewport , uint32 Message )
{
if ( SavedGWorld )
{
RestoreEditorWorld ( SavedGWorld ) ;
}
}
void UUnrealEdEngine : : OnOpenMatinee ( )
{
// Register a delegate to pickup when Matinee is closed.
2015-01-08 09:29:27 -05:00
OnMatineeEditorClosedDelegateHandle = GLevelEditorModeTools ( ) . OnEditorModeChanged ( ) . AddUObject ( this , & UUnrealEdEngine : : OnMatineeEditorClosed ) ;
2014-03-14 14:13:41 -04:00
}
2015-04-27 12:57:02 -04:00
bool UUnrealEdEngine : : IsAutosaving ( ) const
{
2015-04-28 18:50:01 -04:00
if ( PackageAutoSaver )
{
return PackageAutoSaver - > IsAutoSaving ( ) ;
}
2015-04-28 21:04:50 -04:00
return false ;
2015-04-27 12:57:02 -04:00
}
2014-03-14 14:13:41 -04:00
void UUnrealEdEngine : : ConvertMatinees ( )
{
FVector StartLocation = FVector : : ZeroVector ;
UWorld * World = GWorld ;
if ( World )
{
ULevel * Level = World - > GetCurrentLevel ( ) ;
if ( ! Level )
{
Level = World - > PersistentLevel ;
}
check ( Level ) ;
for ( TObjectIterator < UInterpData > It ; It ; + + It )
{
UInterpData * InterpData = * It ;
if ( InterpData - > IsIn ( Level ) )
{
// We dont care about renaming references or adding redirectors. References to this will be old seqact_interps
GEditor - > RenameObject ( InterpData , Level - > GetOutermost ( ) , * InterpData - > GetName ( ) ) ;
AMatineeActor * MatineeActor = Level - > OwningWorld - > SpawnActor < AMatineeActor > ( StartLocation , FRotator : : ZeroRotator ) ;
StartLocation . Y + = 50 ;
MatineeActor - > MatineeData = InterpData ;
UProperty * MatineeDataProp = NULL ;
for ( UProperty * Property = MatineeActor - > GetClass ( ) - > PropertyLink ; Property ! = NULL ; Property = Property - > PropertyLinkNext )
{
if ( Property - > GetName ( ) = = TEXT ( " MatineeData " ) )
{
MatineeDataProp = Property ;
break ;
}
}
FPropertyChangedEvent PropertyChangedEvent ( MatineeDataProp ) ;
MatineeActor - > PostEditChangeProperty ( PropertyChangedEvent ) ;
}
}
}
}
void UUnrealEdEngine : : ShowActorProperties ( )
{
// See if we have any unlocked property windows available. If not, create a new one.
if ( FSlateApplication : : IsInitialized ( ) )
{
IMainFrameModule & MainFrameModule = FModuleManager : : LoadModuleChecked < IMainFrameModule > ( TEXT ( " MainFrame " ) ) ;
bool bHasUnlockedViews = false ;
FPropertyEditorModule & PropertyEditorModule = FModuleManager : : LoadModuleChecked < FPropertyEditorModule > ( TEXT ( " PropertyEditor " ) ) ;
bHasUnlockedViews = PropertyEditorModule . HasUnlockedDetailViews ( ) ;
// If the slate main frame is shown, summon a new property viewer in the Level editor module
if ( MainFrameModule . IsWindowInitialized ( ) )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
LevelEditorModule . SummonSelectionDetails ( ) ;
}
if ( ! bHasUnlockedViews )
{
UpdateFloatingPropertyWindows ( ) ;
}
}
}
bool UUnrealEdEngine : : GetMapBuildCancelled ( ) const
{
return FUnrealEdMisc : : Get ( ) . GetMapBuildCancelled ( ) ;
}
void UUnrealEdEngine : : SetMapBuildCancelled ( bool InCancelled )
{
FUnrealEdMisc : : Get ( ) . SetMapBuildCancelled ( InCancelled ) ;
}
// namespace to match the original in the old loc system
# define LOCTEXT_NAMESPACE "UnrealEd"
2014-12-02 06:42:27 -05:00
FText FClassPickerDefaults : : GetName ( ) const
2014-03-14 14:13:41 -04:00
{
2015-02-09 12:00:06 -05:00
FText Result = LOCTEXT ( " NullClass " , " (null class) " ) ;
2014-03-14 14:13:41 -04:00
2015-02-09 12:00:06 -05:00
if ( UClass * ItemClass = LoadClass < UObject > ( NULL , * ClassName , NULL , LOAD_None , NULL ) )
2014-03-14 14:13:41 -04:00
{
2015-02-09 12:00:06 -05:00
Result = ItemClass - > GetDisplayNameText ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-09 12:00:06 -05:00
return Result ;
2014-03-14 14:13:41 -04:00
}
2014-12-02 06:42:27 -05:00
FText FClassPickerDefaults : : GetDescription ( ) const
2014-03-14 14:13:41 -04:00
{
2015-02-09 12:00:06 -05:00
FText Result = LOCTEXT ( " NullClass " , " (null class) " ) ;
2014-03-14 14:13:41 -04:00
2015-02-09 12:00:06 -05:00
if ( UClass * ItemClass = LoadClass < UObject > ( NULL , * ClassName , NULL , LOAD_None , NULL ) )
2014-03-14 14:13:41 -04:00
{
2015-02-09 12:00:06 -05:00
Result = ItemClass - > GetToolTipText ( /*bShortTooltip=*/ true ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-09 12:00:06 -05:00
return Result ;
2014-03-14 14:13:41 -04:00
}
# undef LOCTEXT_NAMESPACE
2014-10-14 10:29:11 -04:00
UUnrealEdKeyBindings : : UUnrealEdKeyBindings ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
}
2014-10-14 10:29:11 -04:00
UUnrealEdOptions : : UUnrealEdOptions ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
}
void UUnrealEdOptions : : PostInitProperties ( )
{
Super : : PostInitProperties ( ) ;
if ( ! HasAnyFlags ( RF_ClassDefaultObject | RF_NeedLoad ) )
{
2015-02-03 05:40:57 -05:00
EditorKeyBindings = NewObject < UUnrealEdKeyBindings > ( this , FName ( " EditorKeyBindingsInst " ) ) ;
2014-03-14 14:13:41 -04:00
}
}
UUnrealEdOptions * UUnrealEdEngine : : GetUnrealEdOptions ( )
{
if ( EditorOptionsInst = = NULL )
{
2015-02-03 05:40:57 -05:00
EditorOptionsInst = NewObject < UUnrealEdOptions > ( ) ;
2014-03-14 14:13:41 -04:00
}
return EditorOptionsInst ;
}
void UUnrealEdEngine : : CloseEditor ( )
{
check ( GEngine ) ;
// if PIE is still happening, stop it before doing anything
if ( PlayWorld )
{
EndPlayMap ( ) ;
}
// End any play on console/pc games still happening
EndPlayOnLocalPc ( ) ;
// Can't use FPlatformMisc::RequestExit as it uses PostQuitMessage which is not what we want here.
GIsRequestingExit = 1 ;
}
bool UUnrealEdEngine : : AllowSelectTranslucent ( ) const
{
2015-04-20 10:12:55 -04:00
return GetDefault < UEditorPerProjectUserSettings > ( ) - > bAllowSelectTranslucent ;
2014-03-14 14:13:41 -04:00
}
bool UUnrealEdEngine : : OnlyLoadEditorVisibleLevelsInPIE ( ) const
{
return GetDefault < ULevelEditorPlaySettings > ( ) - > bOnlyLoadVisibleLevelsInPIE ;
}
2015-03-04 08:31:40 -05:00
bool UUnrealEdEngine : : PreferToStreamLevelsInPIE ( ) const
{
return GetDefault < ULevelEditorPlaySettings > ( ) - > bPreferToStreamLevelsInPIE ;
}
2014-03-14 14:13:41 -04:00
void UUnrealEdEngine : : RedrawLevelEditingViewports ( bool bInvalidateHitProxies )
{
// Redraw Slate based viewports
if ( FModuleManager : : Get ( ) . IsModuleLoaded ( " LevelEditor " ) )
{
FLevelEditorModule & LevelEditor = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
LevelEditor . BroadcastRedrawViewports ( bInvalidateHitProxies ) ;
}
}
void UUnrealEdEngine : : TakeHighResScreenShots ( )
{
// Tell all viewports to take a screenshot
if ( FModuleManager : : Get ( ) . IsModuleLoaded ( " LevelEditor " ) )
{
FLevelEditorModule & LevelEditor = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
LevelEditor . BroadcastTakeHighResScreenShots ( ) ;
}
}
void UUnrealEdEngine : : SetCurrentClass ( UClass * InClass )
{
USelection * SelectionSet = GetSelectedObjects ( ) ;
SelectionSet - > DeselectAll ( UClass : : StaticClass ( ) ) ;
if ( InClass ! = NULL )
{
SelectionSet - > Select ( InClass ) ;
}
}
void UUnrealEdEngine : : GetPackageList ( TArray < UPackage * > * InPackages , UClass * InClass )
{
InPackages - > Empty ( ) ;
for ( FObjectIterator It ; It ; + + It )
{
if ( It - > GetOuter ( ) & & It - > GetOuter ( ) ! = GetTransientPackage ( ) )
{
UObject * TopParent = NULL ;
if ( InClass = = NULL | | It - > IsA ( InClass ) )
TopParent = It - > GetOutermost ( ) ;
if ( Cast < UPackage > ( TopParent ) )
InPackages - > AddUnique ( ( UPackage * ) TopParent ) ;
}
}
}
bool UUnrealEdEngine : : CanSavePackage ( UPackage * PackageToSave )
{
const FString & PackageName = PackageToSave - > GetName ( ) ;
EWriteDisallowedWarningState WarningState = GetWarningStateForWritePermission ( PackageName ) ;
if ( WarningState = = WDWS_PendingWarn )
{
bNeedWarningForWritePermission = true ;
PackagesCheckedForWritePermission . Add ( PackageName , WarningState ) ;
return false ;
}
return true ;
}
UThumbnailManager * UUnrealEdEngine : : GetThumbnailManager ( )
{
return & ( UThumbnailManager : : Get ( ) ) ;
}
void UUnrealEdEngine : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
Ar < < MaterialCopyPasteBuffer ;
Ar < < AnimationCompressionAlgorithms ;
Ar < < MatineeCopyPasteBuffer ;
}
void UUnrealEdEngine : : MakeSelectedActorsLevelCurrent ( )
{
ULevel * LevelToMakeCurrent = NULL ;
// Look to the selected actors for the level to make current.
// If actors from multiple levels are selected, do nothing.
for ( FSelectionIterator It ( GetSelectedActorIterator ( ) ) ; It ; + + It )
{
AActor * Actor = static_cast < AActor * > ( * It ) ;
checkSlow ( Actor - > IsA ( AActor : : StaticClass ( ) ) ) ;
ULevel * ActorLevel = Actor - > GetLevel ( ) ;
if ( ! LevelToMakeCurrent )
{
// First assignment.
LevelToMakeCurrent = ActorLevel ;
}
else if ( LevelToMakeCurrent ! = ActorLevel )
{
// Actors from multiple levels are selected -- abort.
LevelToMakeCurrent = NULL ;
break ;
}
}
// Change the current level to something different
if ( LevelToMakeCurrent & & ! LevelToMakeCurrent - > IsCurrentLevel ( ) )
{
EditorLevelUtils : : MakeLevelCurrent ( LevelToMakeCurrent ) ;
}
}
int32 UUnrealEdEngine : : GetSpriteCategoryIndex ( const FName & InSpriteCategory )
{
// Find the sprite category in the unlocalized to index map, if possible
const int32 * CategoryIndexPtr = SpriteIDToIndexMap . Find ( InSpriteCategory ) ;
const int32 CategoryIndex = CategoryIndexPtr ? * CategoryIndexPtr : INDEX_NONE ;
return CategoryIndex ;
}
void UUnrealEdEngine : : ShowLightingStaticMeshInfoWindow ( )
{
// first invoke the stats viewer tab
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
TSharedPtr < FTabManager > LevelEditorTabManager = LevelEditorModule . GetLevelEditorTabManager ( ) ;
LevelEditorTabManager - > InvokeTab ( FName ( " LevelEditorStatsViewer " ) ) ;
// then switch pages
FStatsViewerModule & StatsViewerModule = FModuleManager : : Get ( ) . LoadModuleChecked < FStatsViewerModule > ( TEXT ( " StatsViewer " ) ) ;
StatsViewerModule . GetPage ( EStatsPage : : StaticMeshLightingInfo ) - > Show ( ) ;
}
void UUnrealEdEngine : : OpenSceneStatsWindow ( )
{
// first invoke the stats viewer tab
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
TSharedPtr < FTabManager > LevelEditorTabManager = LevelEditorModule . GetLevelEditorTabManager ( ) ;
LevelEditorTabManager - > InvokeTab ( FName ( " LevelEditorStatsViewer " ) ) ;
// then switch pages
FStatsViewerModule & StatsViewerModule = FModuleManager : : Get ( ) . LoadModuleChecked < FStatsViewerModule > ( TEXT ( " StatsViewer " ) ) ;
StatsViewerModule . GetPage ( EStatsPage : : PrimitiveStats ) - > Show ( ) ;
}
void UUnrealEdEngine : : OpenTextureStatsWindow ( )
{
// first invoke the stats viewer tab
FLevelEditorModule & LevelEditorModule = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
TSharedPtr < FTabManager > LevelEditorTabManager = LevelEditorModule . GetLevelEditorTabManager ( ) ;
LevelEditorTabManager - > InvokeTab ( FName ( " LevelEditorStatsViewer " ) ) ;
// then switch pages
FStatsViewerModule & StatsViewerModule = FModuleManager : : Get ( ) . LoadModuleChecked < FStatsViewerModule > ( TEXT ( " StatsViewer " ) ) ;
StatsViewerModule . GetPage ( EStatsPage : : TextureStats ) - > Show ( ) ;
}
void UUnrealEdEngine : : GetSortedVolumeClasses ( TArray < UClass * > * VolumeClasses )
{
// Add all of the volume classes to the passed in array and then sort it
for ( auto * Class : TObjectRange < UClass > ( ) )
{
2014-12-03 04:41:34 -05:00
if ( Class - > IsChildOf ( AVolume : : StaticClass ( ) ) & & ! Class - > HasAnyClassFlags ( CLASS_Deprecated | CLASS_Abstract | CLASS_NotPlaceable ) & & Class - > ClassGeneratedBy = = nullptr )
2014-03-14 14:13:41 -04:00
{
VolumeClasses - > AddUnique ( Class ) ;
}
}
VolumeClasses - > Sort ( ) ;
}
void UUnrealEdOptions : : GenerateCommandMap ( )
{
CommandMap . Empty ( ) ;
for ( int32 CmdIdx = 0 ; CmdIdx < EditorCommands . Num ( ) ; CmdIdx + + )
{
FEditorCommand & Cmd = EditorCommands [ CmdIdx ] ;
CommandMap . Add ( Cmd . CommandName , CmdIdx ) ;
}
}
FString UUnrealEdOptions : : GetExecCommand ( FKey Key , bool bAltDown , bool bCtrlDown , bool bShiftDown , FName EditorSet )
{
TArray < FEditorKeyBinding > & KeyBindings = EditorKeyBindings - > KeyBindings ;
FString Result ;
for ( int32 BindingIdx = 0 ; BindingIdx < KeyBindings . Num ( ) ; BindingIdx + + )
{
FEditorKeyBinding & Binding = KeyBindings [ BindingIdx ] ;
int32 * CommandIdx = CommandMap . Find ( Binding . CommandName ) ;
if ( CommandIdx & & EditorCommands . IsValidIndex ( * CommandIdx ) )
{
FEditorCommand & Cmd = EditorCommands [ * CommandIdx ] ;
if ( Cmd . Parent = = EditorSet )
{
// See if this key binding matches the key combination passed in.
if ( bAltDown = = Binding . bAltDown & & bCtrlDown = = Binding . bCtrlDown & & bShiftDown = = Binding . bShiftDown & & Key = = Binding . Key )
{
int32 * EditorCommandIdx = CommandMap . Find ( Binding . CommandName ) ;
if ( EditorCommandIdx & & EditorCommands . IsValidIndex ( * EditorCommandIdx ) )
{
FEditorCommand & EditorCommand = EditorCommands [ * EditorCommandIdx ] ;
Result = EditorCommand . ExecCommand ;
}
break ;
}
}
}
}
return Result ;
}
/**
* Does the update for volume actor visibility
*
* @ param ActorsToUpdate The list of actors to update
* @ param ViewClient The viewport client to apply visibility changes to
*/
static void InternalUpdateVolumeActorVisibility ( TArray < AActor * > & ActorsToUpdate , const FLevelEditorViewportClient & ViewClient , TArray < AActor * > & OutActorsThatChanged )
{
for ( int32 ActorIdx = 0 ; ActorIdx < ActorsToUpdate . Num ( ) ; + + ActorIdx )
{
AVolume * VolumeToUpdate = Cast < AVolume > ( ActorsToUpdate [ ActorIdx ] ) ;
if ( VolumeToUpdate )
{
const bool bIsVisible = ViewClient . IsVolumeVisibleInViewport ( * VolumeToUpdate ) ;
uint64 OriginalViews = VolumeToUpdate - > HiddenEditorViews ;
if ( bIsVisible )
{
// If the actor should be visible, unset the bit for the actor in this viewport
VolumeToUpdate - > HiddenEditorViews & = ~ ( ( uint64 ) 1 < < ViewClient . ViewIndex ) ;
}
else
{
if ( VolumeToUpdate - > IsSelected ( ) )
{
// We are hiding the actor, make sure its not selected anymore
GEditor - > SelectActor ( VolumeToUpdate , false , true ) ;
}
// If the actor should be hidden, set the bit for the actor in this viewport
VolumeToUpdate - > HiddenEditorViews | = ( ( uint64 ) 1 < < ViewClient . ViewIndex ) ;
}
if ( OriginalViews ! = VolumeToUpdate - > HiddenEditorViews )
{
// At least one actor has visibility changes
OutActorsThatChanged . AddUnique ( VolumeToUpdate ) ;
}
}
}
}
2014-09-16 16:22:01 -04:00
void UUnrealEdEngine : : UpdateVolumeActorVisibility ( UClass * InVolumeActorClass , FLevelEditorViewportClient * InViewport )
2014-03-14 14:13:41 -04:00
{
2014-09-16 16:22:01 -04:00
TSubclassOf < AActor > VolumeClassToCheck = InVolumeActorClass ? InVolumeActorClass : AVolume : : StaticClass ( ) ;
2014-03-14 14:13:41 -04:00
// Build a list of actors that need to be updated. Only take actors of the passed in volume class.
UWorld * World = InViewport ? InViewport - > GetWorld ( ) : GWorld ;
TArray < AActor * > ActorsToUpdate ;
2014-09-16 16:22:01 -04:00
for ( TActorIterator < AActor > It ( World , VolumeClassToCheck ) ; It ; + + It )
2014-03-14 14:13:41 -04:00
{
2014-09-16 16:22:01 -04:00
ActorsToUpdate . Add ( * It ) ;
2014-03-14 14:13:41 -04:00
}
if ( ActorsToUpdate . Num ( ) > 0 )
{
TArray < AActor * > ActorsThatChanged ;
if ( ! InViewport )
{
// Update the visibility state of each actor for each viewport
for ( int32 ViewportIdx = 0 ; ViewportIdx < LevelViewportClients . Num ( ) ; + + ViewportIdx )
{
FLevelEditorViewportClient & ViewClient = * LevelViewportClients [ ViewportIdx ] ;
{
// Only update the editor frame clients as those are the only viewports right now that show volumes.
InternalUpdateVolumeActorVisibility ( ActorsToUpdate , ViewClient , ActorsThatChanged ) ;
if ( ActorsThatChanged . Num ( ) )
{
// If actor visibility changed in the viewport, it needs to be redrawn
ViewClient . Invalidate ( ) ;
}
}
}
}
else
{
// Only update the editor frame clients as those are the only viewports right now that show volumes.
InternalUpdateVolumeActorVisibility ( ActorsToUpdate , * InViewport , ActorsThatChanged ) ;
if ( ActorsThatChanged . Num ( ) )
{
// If actor visibility changed in the viewport, it needs to be redrawn
InViewport - > Invalidate ( ) ;
}
}
// Push all changes in the actors to the scene proxy so the render thread correctly updates visibility
for ( int32 ActorIdx = 0 ; ActorIdx < ActorsThatChanged . Num ( ) ; + + ActorIdx )
{
AActor * ActorToUpdate = ActorsThatChanged [ ActorIdx ] ;
// Find all registered primitive components and update the scene proxy with the actors updated visibility map
2014-12-18 17:02:31 -05:00
TInlineComponentArray < UPrimitiveComponent * > PrimitiveComponents ;
2014-03-14 14:13:41 -04:00
ActorToUpdate - > GetComponents ( PrimitiveComponents ) ;
for ( int32 ComponentIdx = 0 ; ComponentIdx < PrimitiveComponents . Num ( ) ; + + ComponentIdx )
{
UPrimitiveComponent * PrimitiveComponent = PrimitiveComponents [ ComponentIdx ] ;
if ( PrimitiveComponent - > IsRegistered ( ) )
{
// Push visibility to the render thread
PrimitiveComponent - > PushEditorVisibilityToProxy ( ActorToUpdate - > HiddenEditorViews ) ;
}
}
}
}
}
void UUnrealEdEngine : : RegisterComponentVisualizer ( FName ComponentClassName , TSharedPtr < FComponentVisualizer > Visualizer )
{
if ( ComponentClassName ! = NAME_Name )
{
ComponentVisualizerMap . Add ( ComponentClassName , Visualizer ) ;
}
}
void UUnrealEdEngine : : UnregisterComponentVisualizer ( FName ComponentClassName )
{
ComponentVisualizerMap . Remove ( ComponentClassName ) ;
}
2014-06-11 00:20:45 -04:00
TSharedPtr < FComponentVisualizer > UUnrealEdEngine : : FindComponentVisualizer ( FName ComponentClassName ) const
2014-05-16 09:37:22 -04:00
{
TSharedPtr < FComponentVisualizer > Visualizer = NULL ;
2014-06-11 00:20:45 -04:00
const TSharedPtr < FComponentVisualizer > * VisualizerPtr = ComponentVisualizerMap . Find ( ComponentClassName ) ;
2014-05-16 09:37:22 -04:00
if ( VisualizerPtr ! = NULL )
{
Visualizer = * VisualizerPtr ;
}
return Visualizer ;
}
2014-06-11 00:20:45 -04:00
/** Find a component visualizer for the given component class (checking parent classes too) */
TSharedPtr < class FComponentVisualizer > UUnrealEdEngine : : FindComponentVisualizer ( UClass * ComponentClass ) const
{
TSharedPtr < FComponentVisualizer > Visualizer ;
while ( ! Visualizer . IsValid ( ) & & ( ComponentClass ! = nullptr ) & & ( ComponentClass ! = UActorComponent : : StaticClass ( ) ) )
{
Visualizer = FindComponentVisualizer ( ComponentClass - > GetFName ( ) ) ;
ComponentClass = ComponentClass - > GetSuperClass ( ) ;
}
return Visualizer ;
}
2014-03-14 14:13:41 -04:00
2014-05-20 13:39:35 -04:00
2014-03-14 14:13:41 -04:00
void UUnrealEdEngine : : DrawComponentVisualizers ( const FSceneView * View , FPrimitiveDrawInterface * PDI )
{
// Iterate over all selected actors
for ( FSelectionIterator It ( GetSelectedActorIterator ( ) ) ; It ; + + It )
{
AActor * Actor = Cast < AActor > ( * It ) ;
if ( Actor ! = NULL )
{
// Then iterate over components of that actor
2014-12-18 17:02:31 -05:00
TInlineComponentArray < UActorComponent * > Components ;
2014-03-14 14:13:41 -04:00
Actor - > GetComponents ( Components ) ;
for ( int32 CompIdx = 0 ; CompIdx < Components . Num ( ) ; CompIdx + + )
{
UActorComponent * Comp = Components [ CompIdx ] ;
if ( Comp - > IsRegistered ( ) )
{
// Try and find a visualizer
2014-06-11 00:20:45 -04:00
TSharedPtr < FComponentVisualizer > Visualizer = FindComponentVisualizer ( Comp - > GetClass ( ) ) ;
2014-05-16 09:37:22 -04:00
if ( Visualizer . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-05-16 09:37:22 -04:00
Visualizer - > DrawVisualization ( Comp , View , PDI ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
}
}
2014-10-15 11:32:36 -04:00
void UUnrealEdEngine : : DrawComponentVisualizersHUD ( const FViewport * Viewport , const FSceneView * View , FCanvas * Canvas )
{
// Iterate over all selected actors
for ( FSelectionIterator It ( GetSelectedActorIterator ( ) ) ; It ; + + It )
{
AActor * Actor = Cast < AActor > ( * It ) ;
if ( Actor ! = NULL )
{
// Then iterate over components of that actor
2014-12-18 17:02:31 -05:00
TInlineComponentArray < UActorComponent * > Components ;
2014-10-15 11:32:36 -04:00
Actor - > GetComponents ( Components ) ;
for ( int32 CompIdx = 0 ; CompIdx < Components . Num ( ) ; CompIdx + + )
{
UActorComponent * Comp = Components [ CompIdx ] ;
if ( Comp - > IsRegistered ( ) )
{
// Try and find a visualizer
TSharedPtr < FComponentVisualizer > Visualizer = FindComponentVisualizer ( Comp - > GetClass ( ) ) ;
if ( Visualizer . IsValid ( ) )
{
Visualizer - > DrawVisualizationHUD ( Comp , Viewport , View , Canvas ) ;
}
}
}
}
}
}
2014-03-14 14:13:41 -04:00
EWriteDisallowedWarningState UUnrealEdEngine : : GetWarningStateForWritePermission ( const FString & PackageName ) const
{
EWriteDisallowedWarningState WarningState = WDWS_WarningUnnecessary ;
if ( FPackageName : : IsValidLongPackageName ( PackageName , /*bIncludeReadOnlyRoots=*/ false ) )
{
// Test for write permission in the folder the package is in by creating a temp file and writing to it.
// This isn't exactly the same as testing the package file for write permission, but we can not test that without directly writing to the file.
FString BasePackageFileName = FPackageName : : LongPackageNameToFilename ( PackageName ) ;
FString TempPackageFileName = BasePackageFileName ;
// Make sure the temp file we are writing does not already exist by appending a numbered suffix
const int32 MaxSuffix = 32 ;
bool bCanTestPermission = false ;
for ( int32 SuffixIdx = 0 ; SuffixIdx < MaxSuffix ; + + SuffixIdx )
{
TempPackageFileName = BasePackageFileName + FString : : Printf ( TEXT ( " .tmp%d " ) , SuffixIdx ) ;
if ( ! FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * TempPackageFileName ) )
{
// Found a file that is not already in use
bCanTestPermission = true ;
break ;
}
}
// If we actually found a file to test permission, test it now.
if ( bCanTestPermission )
{
bool bHasWritePermission = FFileHelper : : SaveStringToFile ( TEXT ( " Write Test " ) , * TempPackageFileName ) ;
if ( bHasWritePermission )
{
// We can successfully write to the folder containing the package.
// Delete the temp file.
IFileManager : : Get ( ) . Delete ( * TempPackageFileName ) ;
}
else
{
// We may not write to the specified location. Warn the user that he will not be able to write to this file.
WarningState = WDWS_PendingWarn ;
}
}
else
{
// Failed to find a proper file to test permission...
}
}
return WarningState ;
}
void UUnrealEdEngine : : OnMatineeEditorClosed ( FEdMode * Mode , bool IsEntering )
{
// if we are closing the Matinee editor
if ( ! IsEntering & & Mode - > GetID ( ) = = FBuiltinEditorModes : : EM_InterpEdit )
{
// set the autosave timer to save soon
if ( PackageAutoSaver )
{
PackageAutoSaver - > ForceMinimumTimeTillAutoSave ( ) ;
}
// Remove this delegate.
2015-01-08 09:29:27 -05:00
GLevelEditorModeTools ( ) . OnEditorModeChanged ( ) . Remove ( OnMatineeEditorClosedDelegateHandle ) ;
2014-03-14 14:13:41 -04:00
}
}