2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "ProjectsPrivatePCH.h"
DEFINE_LOG_CATEGORY_STATIC ( LogProjectManager , Log , All ) ;
# define LOCTEXT_NAMESPACE "ProjectManager"
FProject : : FProject ( )
{
}
FProject : : FProject ( const FProjectInfo & InitProjectInfo )
: ProjectInfo ( InitProjectInfo )
{
}
bool FProject : : IsSignedSampleProject ( const FString & FilePath ) const
{
return ProjectInfo . EpicSampleNameHash = = GetTypeHash ( FPaths : : GetCleanFilename ( FilePath ) ) ;
}
void FProject : : SignSampleProject ( const FString & FilePath , const FString & Category )
{
ProjectInfo . EpicSampleNameHash = GetTypeHash ( FPaths : : GetCleanFilename ( FilePath ) ) ;
ProjectInfo . Category = Category ;
}
2014-05-29 17:37:19 -04:00
void FProject : : UpdateSupportedTargetPlatforms ( const FName & InPlatformName , const bool bIsSupported )
{
if ( bIsSupported )
{
ProjectInfo . TargetPlatforms . AddUnique ( InPlatformName ) ;
}
else
{
ProjectInfo . TargetPlatforms . Remove ( InPlatformName ) ;
}
}
2014-06-05 12:13:44 -04:00
void FProject : : ClearSupportedTargetPlatforms ( )
{
ProjectInfo . TargetPlatforms . Empty ( ) ;
}
2014-03-14 14:13:41 -04:00
bool FProject : : PerformAdditionalDeserialization ( const TSharedRef < FJsonObject > & FileObject )
{
ReadNumberFromJSON ( FileObject , TEXT ( " EpicSampleNameHash " ) , ProjectInfo . EpicSampleNameHash ) ;
2014-05-29 17:37:19 -04:00
ProjectInfo . TargetPlatforms . Empty ( ) ;
if ( FileObject - > HasField ( TEXT ( " TargetPlatforms " ) ) )
{
const TSharedPtr < FJsonValue > & TargetPlatformsValue = FileObject - > GetField < EJson : : Array > ( TEXT ( " TargetPlatforms " ) ) ;
const TArray < TSharedPtr < FJsonValue > > & TargetPlatformsArray = TargetPlatformsValue - > AsArray ( ) ;
for ( const auto & TargetPlatformsEntry : TargetPlatformsArray )
{
const FString PlatformName = TargetPlatformsEntry - > AsString ( ) ;
ProjectInfo . TargetPlatforms . Add ( * PlatformName ) ;
}
}
2014-03-14 14:13:41 -04:00
return true ;
}
void FProject : : PerformAdditionalSerialization ( const TSharedRef < TJsonWriter < > > & Writer ) const
{
Writer - > WriteValue ( TEXT ( " EpicSampleNameHash " ) , FString : : Printf ( TEXT ( " %u " ) , ProjectInfo . EpicSampleNameHash ) ) ;
2014-05-29 17:37:19 -04:00
if ( ProjectInfo . TargetPlatforms . Num ( ) > 0 )
{
Writer - > WriteArrayStart ( TEXT ( " TargetPlatforms " ) ) ;
for ( const FName & PlatformName : ProjectInfo . TargetPlatforms )
{
Writer - > WriteValue ( PlatformName . ToString ( ) ) ;
}
Writer - > WriteArrayEnd ( ) ;
}
2014-03-14 14:13:41 -04:00
}
FProjectManager : : FProjectManager ( )
{
}
bool FProjectManager : : LoadProjectFile ( const FString & InProjectFile )
{
FText FailureReason ;
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ) ) ;
if ( NewProject - > LoadFromFile ( InProjectFile , FailureReason ) )
{
2014-05-13 18:23:53 -04:00
// Load successful. Set the loaded project file pointer.
CurrentlyLoadedProject = NewProject ;
2014-03-14 14:13:41 -04:00
2014-05-13 18:23:53 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:40:57 -04:00
# if PLATFORM_IOS
FString UpdatedMessage = FString : : Printf ( TEXT ( " %s \n %s " ) , * FailureReason . ToString ( ) , TEXT ( " For troubleshooting, please go to https://docs.unrealengine.com/latest/INT/Platforms/iOS/GettingStarted/index.html " ) ) ;
FailureReason = FText : : FromString ( UpdatedMessage ) ;
# endif
2014-03-14 14:13:41 -04:00
UE_LOG ( LogProjectManager , Error , TEXT ( " %s " ) , * FailureReason . ToString ( ) ) ;
FMessageDialog : : Open ( EAppMsgType : : Ok , FailureReason ) ;
2014-04-23 18:40:57 -04:00
2014-03-14 14:13:41 -04:00
return false ;
}
bool FProjectManager : : LoadModulesForProject ( const ELoadingPhase : : Type LoadingPhase )
{
DECLARE_SCOPE_CYCLE_COUNTER ( TEXT ( " Loading Game Modules " ) , STAT_GameModule , STATGROUP_LoadTime ) ;
bool bSuccess = true ;
if ( CurrentlyLoadedProject . IsValid ( ) )
{
TMap < FName , ELoadModuleFailureReason : : Type > ModuleLoadFailures ;
CurrentlyLoadedProject - > LoadModules ( LoadingPhase , ModuleLoadFailures ) ;
if ( ModuleLoadFailures . Num ( ) > 0 )
{
FText FailureMessage ;
for ( auto FailureIt = ModuleLoadFailures . CreateConstIterator ( ) ; FailureIt ; + + FailureIt )
{
const ELoadModuleFailureReason : : Type FailureReason = FailureIt . Value ( ) ;
if ( FailureReason ! = ELoadModuleFailureReason : : Success )
{
const FText TextModuleName = FText : : FromName ( FailureIt . Key ( ) ) ;
if ( FailureReason = = ELoadModuleFailureReason : : FileNotFound )
{
FailureMessage = FText : : Format ( LOCTEXT ( " PrimaryGameModuleNotFound " , " The game module '{0}' could not be found. Please ensure that this module exists and that it is compiled. " ) , TextModuleName ) ;
}
else if ( FailureReason = = ELoadModuleFailureReason : : FileIncompatible )
{
FailureMessage = FText : : Format ( LOCTEXT ( " PrimaryGameModuleIncompatible " , " The game module '{0}' does not appear to be up to date. This may happen after updating the engine. Please recompile this module and try again. " ) , TextModuleName ) ;
}
else if ( FailureReason = = ELoadModuleFailureReason : : FailedToInitialize )
{
FailureMessage = FText : : Format ( LOCTEXT ( " PrimaryGameModuleFailedToInitialize " , " The game module '{0}' could not be successfully initialized after it was loaded. " ) , TextModuleName ) ;
}
else if ( FailureReason = = ELoadModuleFailureReason : : CouldNotBeLoadedByOS )
{
FailureMessage = FText : : Format ( LOCTEXT ( " PrimaryGameModuleCouldntBeLoaded " , " The game module '{0}' could not be loaded. There may be an operating system error or the module may not be properly set up. " ) , TextModuleName ) ;
}
else
{
ensure ( 0 ) ; // If this goes off, the error handling code should be updated for the new enum values!
FailureMessage = FText : : Format ( LOCTEXT ( " PrimaryGameModuleGenericLoadFailure " , " The game module '{0}' failed to load for an unspecified reason. Please report this error. " ) , TextModuleName ) ;
}
// Just report the first error
break ;
}
}
FMessageDialog : : Open ( EAppMsgType : : Ok , FailureMessage ) ;
bSuccess = false ;
}
}
return bSuccess ;
}
2014-04-30 10:48:13 -04:00
bool FProjectManager : : AreProjectModulesUpToDate ( )
{
return ! CurrentlyLoadedProject . IsValid ( ) | | CurrentlyLoadedProject - > AreModulesUpToDate ( ) ;
}
2014-03-14 14:13:41 -04:00
const FString & FProjectManager : : GetAutoLoadProjectFileName ( )
{
static FString RecentProjectFileName = FPaths : : Combine ( * FPaths : : GameAgnosticSavedDir ( ) , TEXT ( " AutoLoadProject.txt " ) ) ;
return RecentProjectFileName ;
}
const FString & FProjectManager : : NonStaticGetProjectFileExtension ( )
{
static FString GameProjectFileExtension ( TEXT ( " uproject " ) ) ;
return GameProjectFileExtension ;
}
2014-04-23 18:32:52 -04:00
bool FProjectManager : : GenerateNewProjectFile ( const FString & NewProjectFilename , const TArray < FString > & StartupModuleNames , const FString & EngineIdentifier , FText & OutFailReason )
2014-03-14 14:13:41 -04:00
{
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ) ) ;
2014-04-23 18:32:52 -04:00
NewProject - > UpdateVersionToCurrent ( EngineIdentifier ) ;
2014-03-14 14:13:41 -04:00
NewProject - > ReplaceModulesInProject ( & StartupModuleNames ) ;
const FString & FileContents = NewProject - > SerializeToJSON ( ) ;
if ( FFileHelper : : SaveStringToFile ( FileContents , * NewProjectFilename ) )
{
return true ;
}
else
{
OutFailReason = FText : : Format ( LOCTEXT ( " FailedToWriteOutputFile " , " Failed to write output file '{0}'. Perhaps the file is Read-Only? " ) , FText : : FromString ( NewProjectFilename ) ) ;
return false ;
}
}
2014-04-23 18:32:52 -04:00
bool FProjectManager : : DuplicateProjectFile ( const FString & SourceProjectFilename , const FString & NewProjectFilename , const FString & EngineIdentifier , FText & OutFailReason )
2014-03-14 14:13:41 -04:00
{
// Load the source project
TSharedRef < FProject > SourceProject = MakeShareable ( new FProject ( ) ) ;
if ( ! SourceProject - > LoadFromFile ( SourceProjectFilename , OutFailReason ) )
{
return false ;
}
// Duplicate the project info
FProjectInfo ProjectInfo = SourceProject - > GetProjectInfo ( ) ;
// Clear the sample hash
ProjectInfo . EpicSampleNameHash = 0 ;
// Fix up module names
const FString BaseSourceName = FPaths : : GetBaseFilename ( SourceProjectFilename ) ;
const FString BaseNewName = FPaths : : GetBaseFilename ( NewProjectFilename ) ;
for ( auto ModuleIt = ProjectInfo . Modules . CreateIterator ( ) ; ModuleIt ; + + ModuleIt )
{
FProjectOrPluginInfo : : FModuleInfo & ModuleInfo = * ModuleIt ;
ModuleInfo . Name = FName ( * ModuleInfo . Name . ToString ( ) . Replace ( * BaseSourceName , * BaseNewName ) ) ;
}
// Create new project, update version numbers (no need to replace modules here)
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ProjectInfo ) ) ;
2014-04-23 18:32:52 -04:00
NewProject - > UpdateVersionToCurrent ( EngineIdentifier ) ;
2014-03-14 14:13:41 -04:00
// Serialize and write to disk
const FString & FileContents = NewProject - > SerializeToJSON ( ) ;
if ( FFileHelper : : SaveStringToFile ( FileContents , * NewProjectFilename ) )
{
return true ;
}
else
{
OutFailReason = FText : : Format ( LOCTEXT ( " FailedToWriteOutputFile " , " Failed to write output file '{0}'. Perhaps the file is Read-Only? " ) , FText : : FromString ( NewProjectFilename ) ) ;
return false ;
}
}
2014-04-23 18:32:52 -04:00
bool FProjectManager : : UpdateLoadedProjectFileToCurrent ( const TArray < FString > * StartupModuleNames , const FString & EngineIdentifier , FText & OutFailReason )
2014-03-14 14:13:41 -04:00
{
if ( ! CurrentlyLoadedProject . IsValid ( ) )
{
return false ;
}
// Freshen version information
2014-04-23 18:32:52 -04:00
CurrentlyLoadedProject - > UpdateVersionToCurrent ( EngineIdentifier ) ;
2014-03-14 14:13:41 -04:00
// Replace the modules names, if specified
CurrentlyLoadedProject - > ReplaceModulesInProject ( StartupModuleNames ) ;
// Update file on disk
const FString & FileContents = CurrentlyLoadedProject - > SerializeToJSON ( ) ;
if ( FFileHelper : : SaveStringToFile ( FileContents , * FPaths : : GetProjectFilePath ( ) ) )
{
return true ;
}
else
{
// We failed to generate the file. Could be read only.
OutFailReason = FText : : Format ( LOCTEXT ( " FailedToWriteOutputFile " , " Failed to write output file '{0}'. Perhaps the file is Read-Only? " ) , FText : : FromString ( FPaths : : GetProjectFilePath ( ) ) ) ;
return false ;
}
}
bool FProjectManager : : SignSampleProject ( const FString & FilePath , const FString & Category , FText & OutFailReason )
{
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ) ) ;
if ( ! NewProject - > LoadFromFile ( FilePath , OutFailReason ) )
{
return false ;
}
NewProject - > SignSampleProject ( FilePath , Category ) ;
const FString & FileContents = NewProject - > SerializeToJSON ( ) ;
if ( FFileHelper : : SaveStringToFile ( FileContents , * FilePath ) )
{
return true ;
}
else
{
OutFailReason = FText : : Format ( LOCTEXT ( " FailedToSaveSignedProject " , " Failed to save signed project file {0} " ) , FText : : FromString ( FilePath ) ) ;
return false ;
}
}
2014-05-13 18:23:53 -04:00
bool FProjectManager : : QueryStatusForProject ( const FString & FilePath , FProjectStatus & OutProjectStatus ) const
2014-03-14 14:13:41 -04:00
{
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ) ) ;
FText FailReason ;
if ( ! NewProject - > LoadFromFile ( FilePath , FailReason ) )
{
return false ;
}
2014-05-29 17:37:19 -04:00
QueryStatusForProjectImpl ( * NewProject , FilePath , OutProjectStatus ) ;
return true ;
}
bool FProjectManager : : QueryStatusForCurrentProject ( FProjectStatus & OutProjectStatus ) const
{
if ( ! CurrentlyLoadedProject . IsValid ( ) )
{
return false ;
}
QueryStatusForProjectImpl ( * CurrentlyLoadedProject , FPaths : : GetProjectFilePath ( ) , OutProjectStatus ) ;
return true ;
}
void FProjectManager : : QueryStatusForProjectImpl ( const FProject & Project , const FString & FilePath , FProjectStatus & OutProjectStatus )
{
const FProjectInfo & ProjectInfo = Project . GetProjectInfo ( ) ;
2014-03-14 14:13:41 -04:00
OutProjectStatus . Name = ProjectInfo . Name ;
OutProjectStatus . Description = ProjectInfo . Description ;
OutProjectStatus . Category = ProjectInfo . Category ;
2014-05-13 18:23:53 -04:00
OutProjectStatus . bCodeBasedProject = ProjectInfo . Modules . Num ( ) > 0 ;
2014-05-29 17:37:19 -04:00
OutProjectStatus . bSignedSampleProject = Project . IsSignedSampleProject ( FilePath ) ;
OutProjectStatus . bRequiresUpdate = Project . RequiresUpdate ( ) ;
OutProjectStatus . TargetPlatforms = ProjectInfo . TargetPlatforms ;
}
2014-03-14 14:13:41 -04:00
2014-05-29 17:37:19 -04:00
void FProjectManager : : UpdateSupportedTargetPlatformsForProject ( const FString & FilePath , const FName & InPlatformName , const bool bIsSupported )
{
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ) ) ;
FText FailReason ;
if ( ! NewProject - > LoadFromFile ( FilePath , FailReason ) )
{
return ;
}
NewProject - > UpdateSupportedTargetPlatforms ( InPlatformName , bIsSupported ) ;
const FString & FileContents = NewProject - > SerializeToJSON ( ) ;
FFileHelper : : SaveStringToFile ( FileContents , * FilePath ) ;
// Call OnTargetPlatformsForCurrentProjectChangedEvent if this project is the same as the one we currently have loaded
const FString CurrentProjectPath = FPaths : : ConvertRelativePathToFull ( FPaths : : GetProjectFilePath ( ) ) ;
const FString InProjectPath = FPaths : : ConvertRelativePathToFull ( FilePath ) ;
if ( CurrentProjectPath = = InProjectPath )
{
OnTargetPlatformsForCurrentProjectChangedEvent . Broadcast ( ) ;
}
}
void FProjectManager : : UpdateSupportedTargetPlatformsForCurrentProject ( const FName & InPlatformName , const bool bIsSupported )
{
if ( ! CurrentlyLoadedProject . IsValid ( ) )
{
return ;
}
CurrentlyLoadedProject - > UpdateSupportedTargetPlatforms ( InPlatformName , bIsSupported ) ;
const FString & FileContents = CurrentlyLoadedProject - > SerializeToJSON ( ) ;
FFileHelper : : SaveStringToFile ( FileContents , * FPaths : : GetProjectFilePath ( ) ) ;
OnTargetPlatformsForCurrentProjectChangedEvent . Broadcast ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-05 12:13:44 -04:00
void FProjectManager : : ClearSupportedTargetPlatformsForProject ( const FString & FilePath )
{
TSharedRef < FProject > NewProject = MakeShareable ( new FProject ( ) ) ;
FText FailReason ;
if ( ! NewProject - > LoadFromFile ( FilePath , FailReason ) )
{
return ;
}
NewProject - > ClearSupportedTargetPlatforms ( ) ;
const FString & FileContents = NewProject - > SerializeToJSON ( ) ;
FFileHelper : : SaveStringToFile ( FileContents , * FilePath ) ;
// Call OnTargetPlatformsForCurrentProjectChangedEvent if this project is the same as the one we currently have loaded
const FString CurrentProjectPath = FPaths : : ConvertRelativePathToFull ( FPaths : : GetProjectFilePath ( ) ) ;
const FString InProjectPath = FPaths : : ConvertRelativePathToFull ( FilePath ) ;
if ( CurrentProjectPath = = InProjectPath )
{
OnTargetPlatformsForCurrentProjectChangedEvent . Broadcast ( ) ;
}
}
void FProjectManager : : ClearSupportedTargetPlatformsForCurrentProject ( )
{
if ( ! CurrentlyLoadedProject . IsValid ( ) )
{
return ;
}
CurrentlyLoadedProject - > ClearSupportedTargetPlatforms ( ) ;
const FString & FileContents = CurrentlyLoadedProject - > SerializeToJSON ( ) ;
FFileHelper : : SaveStringToFile ( FileContents , * FPaths : : GetProjectFilePath ( ) ) ;
OnTargetPlatformsForCurrentProjectChangedEvent . Broadcast ( ) ;
}
2014-03-14 14:13:41 -04:00
IProjectManager & IProjectManager : : Get ( )
{
// Single instance of manager, allocated on demand and destroyed on program exit.
static FProjectManager * ProjectManager = NULL ;
if ( ProjectManager = = NULL )
{
ProjectManager = new FProjectManager ( ) ;
}
return * ProjectManager ;
}
# undef LOCTEXT_NAMESPACE