2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-04-23 18:33:25 -04:00
/*=============================================================================
CookOnTheFlyServer . cpp : handles polite cook requests via network ; )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "UnrealEd.h"
# include "PackageHelperFunctions.h"
# include "DerivedDataCacheInterface.h"
# include "ISourceControlModule.h"
# include "GlobalShader.h"
2015-03-16 14:44:28 -04:00
# include "MaterialShader.h"
2014-04-23 18:33:25 -04:00
# include "TargetPlatform.h"
# include "IConsoleManager.h"
# include "Developer/PackageDependencyInfo/Public/PackageDependencyInfo.h"
# include "IPlatformFileSandboxWrapper.h"
# include "Messaging.h"
# include "NetworkFileSystem.h"
# include "AssetRegistryModule.h"
# include "UnrealEdMessages.h"
# include "GameDelegates.h"
2014-11-18 19:54:38 -05:00
# include "PhysicsPublic.h"
2015-05-18 11:22:48 -04:00
# include "AutoSaveUtils.h"
2014-04-23 18:33:25 -04:00
2014-09-16 12:15:46 -04:00
// cook by the book requirements
# include "Commandlets/ChunkManifestGenerator.h"
# include "Engine/WorldComposition.h"
2014-09-16 21:12:55 -04:00
// error message log
# include "TokenizedMessage.h"
# include "MessageLog.h"
2014-04-23 18:33:25 -04:00
2014-10-03 14:56:20 -04:00
// shader compiler processAsyncResults
# include "ShaderCompiler.h"
2014-11-12 04:43:54 -05:00
# include "Engine/LevelStreaming.h"
2015-03-17 09:50:32 -04:00
# include "Engine/TextureLODSettings.h"
2014-04-23 18:33:25 -04:00
2015-04-24 14:41:13 -04:00
# define LOCTEXT_NAMESPACE "Cooker"
2014-12-01 16:53:12 -05:00
DEFINE_LOG_CATEGORY_STATIC ( LogCook , Log , All ) ;
2014-04-23 18:33:25 -04:00
2015-03-06 13:31:19 -05:00
2014-04-23 18:33:25 -04:00
# define DEBUG_COOKONTHEFLY 0
2015-06-29 11:45:25 -04:00
# define OUTPUT_TIMING 0
2014-08-18 16:20:23 -04:00
2015-04-20 15:19:16 -04:00
# define USEASSETREGISTRYFORDEPENDENTPACKAGES 1
# define VERIFY_GETDEPENDENTPACKAGES 0 // verify has false hits because old serialization method for generating dependencies had errors (included transient objects which shouldn't be in asset registry), but you can still use verify to build a list then cross check against transient objects.
2014-08-18 16:20:23 -04:00
# if OUTPUT_TIMING
2015-05-04 14:11:21 -04:00
# define HEIRARCHICAL_TIMER 1
2015-06-01 11:34:55 -04:00
# define PERPACKAGE_TIMER 0
2015-03-06 13:31:19 -05:00
2014-08-18 16:20:23 -04:00
struct FTimerInfo
{
public :
FTimerInfo ( FTimerInfo & & InTimerInfo )
{
Swap ( Name , InTimerInfo . Name ) ;
Length = InTimerInfo . Length ;
}
2014-08-18 18:45:54 -04:00
FTimerInfo ( const FTimerInfo & InTimerInfo )
{
Name = InTimerInfo . Name ;
Length = InTimerInfo . Length ;
}
2014-08-18 16:20:23 -04:00
FTimerInfo ( FString & & InName , double InLength ) : Name ( MoveTemp ( InName ) ) , Length ( InLength ) { }
FString Name ;
double Length ;
} ;
2014-04-23 18:33:25 -04:00
2015-05-04 14:11:21 -04:00
# if HEIRARCHICAL_TIMER
struct FHierarchicalTimerInfo : public FTimerInfo
{
public :
FHierarchicalTimerInfo * Parent ;
TMap < FString , FHierarchicalTimerInfo * > Children ;
FHierarchicalTimerInfo ( const FHierarchicalTimerInfo & InTimerInfo ) : FTimerInfo ( InTimerInfo )
{
Children = InTimerInfo . Children ;
for ( auto & Child : Children )
{
Child . Value - > Parent = this ;
}
}
FHierarchicalTimerInfo ( FHierarchicalTimerInfo & & InTimerInfo ) : FTimerInfo ( InTimerInfo )
{
Swap ( Children , InTimerInfo . Children ) ;
for ( auto & Child : Children )
{
Child . Value - > Parent = this ;
}
}
FHierarchicalTimerInfo ( FString & & Name ) : FTimerInfo ( MoveTemp ( Name ) , 0.0 )
{
}
2015-06-01 11:34:55 -04:00
~ FHierarchicalTimerInfo ( )
{
Parent = NULL ;
ClearChildren ( ) ;
}
void ClearChildren ( )
{
for ( auto & Child : Children )
{
delete Child . Value ;
}
Children . Empty ( ) ;
}
2015-05-04 14:11:21 -04:00
FHierarchicalTimerInfo * FindChild ( const FString & Name )
{
FHierarchicalTimerInfo * Child = ( FHierarchicalTimerInfo * ) ( Children . FindRef ( Name ) ) ;
if ( ! Child )
{
FString Temp = Name ;
Child = Children . Add ( Name , new FHierarchicalTimerInfo ( MoveTemp ( Temp ) ) ) ;
Child - > Parent = this ;
}
check ( Child ) ;
return Child ;
}
} ;
2015-06-16 12:43:26 -04:00
static TMap < FName , int32 > IntStats ;
void IncIntStat ( const FName & Name , const int32 Amount )
{
int32 * Value = IntStats . Find ( Name ) ;
if ( Value = = NULL )
{
IntStats . Add ( Name , Amount ) ;
}
else
{
* Value + = Amount ;
}
}
2015-05-04 14:11:21 -04:00
static FHierarchicalTimerInfo RootTimerInfo ( MoveTemp ( FString ( TEXT ( " Root " ) ) ) ) ;
static FHierarchicalTimerInfo * CurrentTimerInfo = & RootTimerInfo ;
# endif
2014-04-23 18:33:25 -04:00
2014-08-18 16:20:23 -04:00
static TArray < FTimerInfo > GTimerInfo ;
2015-05-04 14:11:21 -04:00
2014-08-18 16:20:23 -04:00
struct FScopeTimer
{
private :
bool Started ;
bool DecrementScope ;
static int GScopeDepth ;
2015-05-04 14:11:21 -04:00
# if HEIRARCHICAL_TIMER
FHierarchicalTimerInfo * HeirarchyTimerInfo ;
# endif
2014-08-18 16:20:23 -04:00
public :
FScopeTimer ( const FScopeTimer & outer )
{
Index = outer . Index ;
DecrementScope = false ;
2015-05-04 14:11:21 -04:00
Started = false ;
2014-08-18 16:20:23 -04:00
}
FScopeTimer ( const FString & InName , bool IncrementScope = false )
{
DecrementScope = IncrementScope ;
2014-09-22 14:29:26 -04:00
2014-08-18 16:20:23 -04:00
FString Name = InName ;
for ( int i = 0 ; i < GScopeDepth ; + + i )
{
Name = FString ( TEXT ( " " ) ) + Name ;
}
2014-09-22 14:29:26 -04:00
if ( DecrementScope )
{
+ + GScopeDepth ;
}
2015-06-01 11:34:55 -04:00
2015-05-04 14:11:21 -04:00
# if HEIRARCHICAL_TIMER
HeirarchyTimerInfo = CurrentTimerInfo - > FindChild ( Name ) ;
CurrentTimerInfo = HeirarchyTimerInfo ;
# endif
2015-06-01 11:34:55 -04:00
# if PERPACKAGE_TIMER
Index = GTimerInfo . Emplace ( MoveTemp ( Name ) , 0.0 ) ;
# endif
Started = false ;
2014-08-18 16:20:23 -04:00
}
void Start ( )
{
if ( ! Started )
{
2015-06-01 11:34:55 -04:00
# if PERPACKAGE_TIMER
2014-08-18 16:20:23 -04:00
GTimerInfo [ Index ] . Length - = FPlatformTime : : Seconds ( ) ;
2015-06-01 11:34:55 -04:00
# endif
2014-08-18 16:20:23 -04:00
Started = true ;
2015-05-04 14:11:21 -04:00
# if HEIRARCHICAL_TIMER
HeirarchyTimerInfo - > Length - = FPlatformTime : : Seconds ( ) ;
# endif
2014-08-18 16:20:23 -04:00
}
}
void Stop ( )
{
if ( Started )
{
2015-05-04 14:11:21 -04:00
# if HEIRARCHICAL_TIMER
HeirarchyTimerInfo - > Length + = FPlatformTime : : Seconds ( ) ;
# endif
2015-06-01 11:34:55 -04:00
# if PERPACKAGE_TIMER
2014-08-18 16:20:23 -04:00
GTimerInfo [ Index ] . Length + = FPlatformTime : : Seconds ( ) ;
2015-06-01 11:34:55 -04:00
# endif
2014-08-18 16:20:23 -04:00
Started = false ;
}
}
~ FScopeTimer ( )
{
Stop ( ) ;
2015-05-04 14:11:21 -04:00
# if HEIRARCHICAL_TIMER
check ( CurrentTimerInfo = = HeirarchyTimerInfo ) ;
CurrentTimerInfo = HeirarchyTimerInfo - > Parent ;
# endif
2014-08-18 16:20:23 -04:00
if ( DecrementScope )
{
- - GScopeDepth ;
}
}
int Index ;
} ;
int FScopeTimer : : GScopeDepth = 0 ;
void OutputTimers ( )
{
2015-06-01 11:34:55 -04:00
# if PERPACKAGE_TIMER
2014-09-16 12:15:46 -04:00
if ( GTimerInfo . Num ( ) < = 0 )
return ;
static FArchive * OutputDevice = NULL ;
static TMap < FString , int > TimerIndexMap ;
if ( OutputDevice = = NULL )
{
OutputDevice = IFileManager : : Get ( ) . CreateFileWriter ( TEXT ( " CookOnTheFlyServerTiming.csv " ) ) ;
}
TArray < FString > OutputValues ;
OutputValues . AddZeroed ( TimerIndexMap . Num ( ) ) ;
bool OutputTimerIndexMap = false ;
for ( auto TimerInfo : GTimerInfo )
{
int * IndexPtr = TimerIndexMap . Find ( TimerInfo . Name ) ;
int Index = 0 ;
if ( IndexPtr = = NULL )
{
Index = TimerIndexMap . Num ( ) ;
TimerIndexMap . Add ( TimerInfo . Name , Index ) ;
OutputValues . AddZeroed ( ) ;
OutputTimerIndexMap = true ;
}
else
Index = * IndexPtr ;
OutputValues [ Index ] = FString : : Printf ( TEXT ( " %f " ) , TimerInfo . Length ) ;
}
2015-05-11 16:41:12 -04:00
static FString NewLine = FString ( TEXT ( " \r \n " ) ) ;
2014-09-16 12:15:46 -04:00
if ( OutputTimerIndexMap )
{
TArray < FString > OutputHeader ;
OutputHeader . AddZeroed ( TimerIndexMap . Num ( ) ) ;
for ( auto TimerIndex : TimerIndexMap )
{
int LocalIndex = TimerIndex . Value ;
OutputHeader [ LocalIndex ] = TimerIndex . Key ;
}
for ( auto OutputString : OutputHeader )
{
OutputString . Append ( TEXT ( " , " ) ) ;
OutputDevice - > Serialize ( ( void * ) ( * OutputString ) , OutputString . Len ( ) * sizeof ( TCHAR ) ) ;
}
OutputDevice - > Serialize ( ( void * ) * NewLine , NewLine . Len ( ) * sizeof ( TCHAR ) ) ;
}
for ( auto OutputString : OutputValues )
{
OutputString . Append ( TEXT ( " , " ) ) ;
OutputDevice - > Serialize ( ( void * ) ( * OutputString ) , OutputString . Len ( ) * sizeof ( TCHAR ) ) ;
}
OutputDevice - > Serialize ( ( void * ) * NewLine , NewLine . Len ( ) * sizeof ( TCHAR ) ) ;
OutputDevice - > Flush ( ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Timing information for cook " ) ) ;
UE_LOG ( LogCook , Display , TEXT ( " Name \t length(ms) " ) ) ;
2014-08-18 16:20:23 -04:00
for ( auto TimerInfo : GTimerInfo )
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " %s \t %.2f " ) , * TimerInfo . Name , TimerInfo . Length * 1000.0f ) ;
2014-08-18 16:20:23 -04:00
}
2014-12-01 11:58:48 -05:00
// first item is the total
if ( GTimerInfo . Num ( ) > 0 & & ( ( GTimerInfo [ 0 ] . Length * 1000.0f ) > 40.0f ) )
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Cook tick exceeded 40ms by %f " ) , GTimerInfo [ 0 ] . Length * 1000.0f ) ;
2014-12-01 11:58:48 -05:00
}
2014-08-18 16:20:23 -04:00
GTimerInfo . Empty ( ) ;
2015-06-01 11:34:55 -04:00
# endif
}
2015-06-16 12:43:26 -04:00
# if HEIRARCHICAL_TIMER
2015-06-01 11:34:55 -04:00
void OutputHierarchyTimers ( const FHierarchicalTimerInfo * TimerInfo , FString & Output , int32 & Depth )
{
// put our line into the output buffer
/*for (int32 I = 0; I < Depth; ++I)
{
Output + = TEXT ( " \t " ) ;
} */
2015-06-16 12:43:26 -04:00
Output + = FString : : Printf ( TEXT ( " %s: %fms \r \n " ) , * TimerInfo - > Name , TimerInfo - > Length * 1000 ) ;
2015-06-01 11:34:55 -04:00
+ + Depth ;
for ( const auto & ChildInfo : TimerInfo - > Children )
{
OutputHierarchyTimers ( ChildInfo . Value , Output , Depth ) ;
}
- - Depth ;
}
void OutputHierarchyTimers ( )
{
FHierarchicalTimerInfo * TimerInfo = & RootTimerInfo ;
int32 Depth = 0 ;
FString Output = TEXT ( " Hierarchy timer information \n Name: Length(ms) " ) ;
OutputHierarchyTimers ( TimerInfo , Output , Depth ) ;
2015-06-16 12:43:26 -04:00
Output + = FString : : Printf ( TEXT ( " IntStats \n " ) ) ;
for ( const auto & IntStat : IntStats )
{
Output + = FString : : Printf ( TEXT ( " %s=%d \r \n " ) , * IntStat . Key . ToString ( ) , IntStat . Value ) ;
}
2015-06-01 11:34:55 -04:00
UE_LOG ( LogCook , Display , TEXT ( " %s " ) , * Output ) ;
RootTimerInfo . ClearChildren ( ) ;
2014-08-18 16:20:23 -04:00
}
2015-06-16 12:43:26 -04:00
# endif
2014-08-18 16:20:23 -04:00
# define CREATE_TIMER(name, incrementScope) FScopeTimer ScopeTimer##name(#name, incrementScope);
# define SCOPE_TIMER(name) CREATE_TIMER(name, true); ScopeTimer##name.Start();
# define STOP_TIMER( name ) ScopeTimer##name.Stop();
# define ACCUMULATE_TIMER(name) CREATE_TIMER(name, false);
# define ACCUMULATE_TIMER_SCOPE(name) FScopeTimer ScopeTimerInner##name(ScopeTimer##name); ScopeTimerInner##name.Start();
# define ACCUMULATE_TIMER_START(name) ScopeTimer##name.Start();
# define ACCUMULATE_TIMER_STOP(name) ScopeTimer##name.Stop();
2015-06-16 12:43:26 -04:00
# if HEIRARCHICAL_TIMER
# define INC_INT_STAT( name, amount ) { static FName StaticName##name(#name); IncIntStat(StaticName##name, amount); }
# else
# define INC_INT_STAT( name, amount )
# endif
2014-08-18 16:20:23 -04:00
# define OUTPUT_TIMERS() OutputTimers();
2015-06-01 11:34:55 -04:00
# define OUTPUT_HIERARCHYTIMERS() OutputHierarchyTimers();
2014-08-18 16:20:23 -04:00
# else
# define CREATE_TIMER(name)
# define SCOPE_TIMER(name)
# define STOP_TIMER(name)
# define ACCUMULATE_TIMER(name)
# define ACCUMULATE_TIMER_SCOPE(name)
# define ACCUMULATE_TIMER_START(name)
# define ACCUMULATE_TIMER_STOP(name)
2015-06-16 12:43:26 -04:00
# define INC_INT_STAT( name, amount )
2014-08-18 16:20:23 -04:00
# define OUTPUT_TIMERS()
2015-06-01 11:34:55 -04:00
# define OUTPUT_HIERARCHYTIMERS()
2014-08-18 16:20:23 -04:00
# endif
2014-04-23 18:33:25 -04:00
////////////////////////////////////////////////////////////////
/// Cook on the fly server
///////////////////////////////////////////////////////////////
2014-12-01 16:53:12 -05:00
/* helper structs functions
2014-04-23 18:33:25 -04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-12-01 16:53:12 -05:00
/** Helper to pass a recompile request to game thread */
struct FRecompileRequest
2014-08-18 16:20:23 -04:00
{
2014-12-01 16:53:12 -05:00
struct FShaderRecompileData RecompileData ;
bool bComplete ;
2014-08-18 16:20:23 -04:00
} ;
2014-12-10 10:12:47 -05:00
const FString & GetAssetRegistryPath ( )
{
static const FString AssetRegistryPath = FPaths : : GameDir ( ) ;
return AssetRegistryPath ;
}
2015-06-29 11:44:58 -04:00
FString GetChildCookerResultFilename ( const FString & ResponseFilename )
{
FString Result = ResponseFilename + TEXT ( " Result.txt " ) ;
return Result ;
}
2014-12-10 10:12:47 -05:00
/**
* Return the release asset registry filename for the release version supplied
*/
FString GetReleaseVersionAssetRegistryPath ( const FString & ReleaseVersion , const FName & PlatformName )
{
// cache the part of the path which is static because getting the GameDir is really slow and also string manipulation
const static FString GameDirectory = FPaths : : GameDir ( ) / FString ( TEXT ( " Releases " ) ) ;
return GameDirectory / ReleaseVersion / PlatformName . ToString ( ) ;
}
const FString & GetAssetRegistryFilename ( )
{
static const FString AssetRegistryFilename = FString ( TEXT ( " AssetRegistry.bin " ) ) ;
return AssetRegistryFilename ;
}
2014-12-01 16:53:12 -05:00
/**
* Uses the FMessageLog to log a message
*
* @ param Message to log
* @ param Severity of the message
*/
void LogCookerMessage ( const FString & MessageText , EMessageSeverity : : Type Severity )
{
FMessageLog MessageLog ( " CookResults " ) ;
2014-04-23 18:33:25 -04:00
2014-12-01 16:53:12 -05:00
TSharedRef < FTokenizedMessage > Message = FTokenizedMessage : : Create ( Severity ) ;
Message - > AddToken ( FTextToken : : Create ( FText : : FromString ( MessageText ) ) ) ;
// Message->AddToken(FTextToken::Create(MessageLogTextDetail));
// Message->AddToken(FDocumentationToken::Create(TEXT("https://docs.unrealengine.com/latest/INT/Platforms/iOS/QuickStart/6/index.html")));
MessageLog . AddMessage ( Message ) ;
2015-04-24 14:41:13 -04:00
MessageLog . Notify ( FText ( ) , EMessageSeverity : : Warning , false ) ;
2014-12-01 16:53:12 -05:00
}
/* FIlename caching functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-12-10 10:12:47 -05:00
FString UCookOnTheFlyServer : : GetCachedPackageFilename ( const FName & PackageName ) const
2014-12-01 16:53:12 -05:00
{
return Cache ( PackageName ) . PackageFilename ;
}
2014-12-10 10:12:47 -05:00
FString UCookOnTheFlyServer : : GetCachedStandardPackageFilename ( const FName & PackageName ) const
2014-12-01 16:53:12 -05:00
{
return Cache ( PackageName ) . StandardFilename ;
}
2014-12-10 10:12:47 -05:00
FName UCookOnTheFlyServer : : GetCachedStandardPackageFileFName ( const FName & PackageName ) const
2014-12-01 16:53:12 -05:00
{
return Cache ( PackageName ) . StandardFileFName ;
}
2015-01-19 10:58:24 -05:00
FString UCookOnTheFlyServer : : GetCachedPackageFilename ( const UPackage * Package ) const
2014-12-01 16:53:12 -05:00
{
2015-05-04 14:11:21 -04:00
// check( Package->GetName() == Package->GetFName().ToString() );
2014-12-01 16:53:12 -05:00
return Cache ( Package - > GetFName ( ) ) . PackageFilename ;
}
2015-01-19 10:58:24 -05:00
FString UCookOnTheFlyServer : : GetCachedStandardPackageFilename ( const UPackage * Package ) const
2014-12-01 16:53:12 -05:00
{
2015-05-04 14:11:21 -04:00
// check( Package->GetName() == Package->GetFName().ToString() );
2014-12-01 16:53:12 -05:00
return Cache ( Package - > GetFName ( ) ) . StandardFilename ;
}
2015-01-19 10:58:24 -05:00
FName UCookOnTheFlyServer : : GetCachedStandardPackageFileFName ( const UPackage * Package ) const
2014-12-01 16:53:12 -05:00
{
2015-05-04 14:11:21 -04:00
// check( Package->GetName() == Package->GetFName().ToString() );
2014-12-01 16:53:12 -05:00
return Cache ( Package - > GetFName ( ) ) . StandardFileFName ;
}
2015-01-19 10:58:24 -05:00
bool UCookOnTheFlyServer : : ClearPackageFilenameCacheForPackage ( const FName & PackageName ) const
{
return PackageFilenameCache . Remove ( PackageName ) > = 1 ;
}
bool UCookOnTheFlyServer : : ClearPackageFilenameCacheForPackage ( const UPackage * Package ) const
{
return PackageFilenameCache . Remove ( Package - > GetFName ( ) ) > = 1 ;
}
2015-03-02 13:41:53 -05:00
const FString & UCookOnTheFlyServer : : GetCachedSandboxFilename ( const UPackage * Package , TAutoPtr < class FSandboxPlatformFile > & InSandboxFile ) const
2014-12-01 16:53:12 -05:00
{
FName PackageFName = Package - > GetFName ( ) ;
static TMap < FName , FString > CachedSandboxFilenames ;
FString * CachedSandboxFilename = CachedSandboxFilenames . Find ( PackageFName ) ;
if ( CachedSandboxFilename )
return * CachedSandboxFilename ;
const FString & PackageFilename = GetCachedPackageFilename ( Package ) ;
FString SandboxFilename = ConvertToFullSandboxPath ( * PackageFilename , true ) ;
return CachedSandboxFilenames . Add ( PackageFName , MoveTemp ( SandboxFilename ) ) ;
}
2014-12-10 10:12:47 -05:00
const UCookOnTheFlyServer : : FCachedPackageFilename & UCookOnTheFlyServer : : Cache ( const FName & PackageName ) const
2014-08-18 16:20:23 -04:00
{
2014-09-16 12:15:46 -04:00
FCachedPackageFilename * Cached = PackageFilenameCache . Find ( PackageName ) ;
2014-08-18 16:20:23 -04:00
if ( Cached ! = NULL )
{
return * Cached ;
}
2014-12-01 16:53:12 -05:00
// cache all the things, like it's your birthday!
2014-08-18 16:20:23 -04:00
FString Filename ;
2014-09-16 12:15:46 -04:00
FString PackageFilename ;
2014-08-18 16:20:23 -04:00
FString StandardFilename ;
FName StandardFileFName = NAME_None ;
2014-09-22 14:29:26 -04:00
if ( FPackageName : : DoesPackageExist ( PackageName . ToString ( ) , NULL , & Filename ) )
2015-04-27 14:10:18 -04:00
{
2014-09-16 12:15:46 -04:00
StandardFilename = PackageFilename = FPaths : : ConvertRelativePathToFull ( Filename ) ;
2014-11-18 15:49:39 -05:00
2014-08-18 16:20:23 -04:00
FPaths : : MakeStandardFilename ( StandardFilename ) ;
StandardFileFName = FName ( * StandardFilename ) ;
}
2015-05-18 15:52:52 -04:00
PackageFilenameToPackageFNameCache . Add ( StandardFileFName , PackageName ) ;
2014-09-16 12:15:46 -04:00
return PackageFilenameCache . Emplace ( PackageName , MoveTemp ( FCachedPackageFilename ( MoveTemp ( PackageFilename ) , MoveTemp ( StandardFilename ) , StandardFileFName ) ) ) ;
2014-08-18 16:20:23 -04:00
}
2015-05-18 15:52:52 -04:00
const FName * UCookOnTheFlyServer : : GetCachedPackageFilenameToPackageFName ( const FName & StandardPackageFilename ) const
{
return PackageFilenameToPackageFNameCache . Find ( StandardPackageFilename ) ;
}
2014-12-10 10:12:47 -05:00
void UCookOnTheFlyServer : : ClearPackageFilenameCache ( ) const
{
2014-12-01 16:53:12 -05:00
PackageFilenameCache . Empty ( ) ;
2015-05-18 15:52:52 -04:00
PackageFilenameToPackageFNameCache . Empty ( ) ;
2014-12-10 10:12:47 -05:00
// need to clear the IniVersionStringsMap too
CachedIniVersionStringsMap . Empty ( ) ;
2014-09-16 12:15:46 -04:00
}
2014-08-18 16:20:23 -04:00
2014-12-01 16:53:12 -05:00
/* UCookOnTheFlyServer functions
2014-04-23 18:33:25 -04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-14 10:29:11 -04:00
UCookOnTheFlyServer : : UCookOnTheFlyServer ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer ) ,
2014-09-16 12:15:46 -04:00
CurrentCookMode ( ECookMode : : CookOnTheFly ) ,
CookByTheBookOptions ( NULL ) ,
CookFlags ( ECookInitializationFlags : : None ) ,
bIsSavingPackage ( false )
2014-04-23 18:33:25 -04:00
{
}
2014-09-16 12:15:46 -04:00
UCookOnTheFlyServer : : ~ UCookOnTheFlyServer ( )
{
if ( CookByTheBookOptions )
{
delete CookByTheBookOptions ;
CookByTheBookOptions = NULL ;
}
}
2014-04-23 18:33:25 -04:00
void UCookOnTheFlyServer : : Tick ( float DeltaTime )
{
uint32 CookedPackagesCount = 0 ;
2014-09-16 12:15:46 -04:00
const static float CookOnTheSideTimeSlice = 0.1f ; // seconds
2014-04-23 19:25:25 -04:00
TickCookOnTheSide ( CookOnTheSideTimeSlice , CookedPackagesCount ) ;
2014-04-23 18:33:25 -04:00
TickRecompileShaderRequests ( ) ;
}
bool UCookOnTheFlyServer : : IsTickable ( ) const
{
2014-09-16 12:15:46 -04:00
return IsCookFlagSet ( ECookInitializationFlags : : AutoTick ) ;
2014-04-23 18:33:25 -04:00
}
TStatId UCookOnTheFlyServer : : GetStatId ( ) const
{
RETURN_QUICK_DECLARE_CYCLE_STAT ( UCookServer , STATGROUP_Tickables ) ;
}
2014-07-07 15:39:19 -04:00
bool UCookOnTheFlyServer : : StartNetworkFileServer ( const bool BindAnyPort )
2014-04-23 18:33:25 -04:00
{
2014-12-01 11:58:48 -05:00
check ( IsCookOnTheFlyMode ( ) ) ;
2014-04-23 18:33:25 -04:00
//GetDerivedDataCacheRef().WaitForQuiescence(false);
2014-12-12 12:59:47 -05:00
InitializeSandbox ( ) ;
2014-12-10 10:12:47 -05:00
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
const TArray < ITargetPlatform * > & Platforms = TPM . GetCookingTargetPlatforms ( ) ;
{
// When cooking on the fly the full registry is saved at the beginning
// in cook by the book asset registry is saved after the cook is finished
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
// write it out to a memory archive
FArrayWriter SerializedAssetRegistry ;
2015-05-11 22:13:40 -04:00
SerializedAssetRegistry . SetFilterEditorOnly ( true ) ;
2014-12-10 10:12:47 -05:00
AssetRegistry . Serialize ( SerializedAssetRegistry ) ;
UE_LOG ( LogCook , Display , TEXT ( " Generated asset registry size is %5.2fkb " ) , ( float ) SerializedAssetRegistry . Num ( ) / 1024.f ) ;
// now save it in each cooked directory
FString RegistryFilename = FPaths : : GameDir ( ) / TEXT ( " AssetRegistry.bin " ) ;
// Use SandboxFile to do path conversion to properly handle sandbox paths (outside of standard paths in particular).
FString SandboxFilename = ConvertToFullSandboxPath ( * RegistryFilename , true ) ;
for ( int32 Index = 0 ; Index < Platforms . Num ( ) ; Index + + )
{
FString PlatFilename = SandboxFilename . Replace ( TEXT ( " [Platform] " ) , * Platforms [ Index ] - > PlatformName ( ) ) ;
FFileHelper : : SaveArrayToFile ( SerializedAssetRegistry , * PlatFilename ) ;
}
}
2014-04-23 18:33:25 -04:00
// start the listening thread
FFileRequestDelegate FileRequestDelegate ( FFileRequestDelegate : : CreateUObject ( this , & UCookOnTheFlyServer : : HandleNetworkFileServerFileRequest ) ) ;
FRecompileShadersDelegate RecompileShadersDelegate ( FRecompileShadersDelegate : : CreateUObject ( this , & UCookOnTheFlyServer : : HandleNetworkFileServerRecompileShaders ) ) ;
2014-07-07 15:39:19 -04:00
INetworkFileServer * TcpFileServer = FModuleManager : : LoadModuleChecked < INetworkFileSystemModule > ( " NetworkFileSystem " )
2014-09-08 11:51:08 -04:00
. CreateNetworkFileServer ( true , BindAnyPort ? 0 : - 1 , & FileRequestDelegate , & RecompileShadersDelegate , ENetworkFileServerProtocol : : NFSP_Tcp ) ;
2014-07-07 15:39:19 -04:00
if ( TcpFileServer )
{
NetworkFileServers . Add ( TcpFileServer ) ;
}
2014-05-02 10:44:16 -04:00
2014-07-07 15:39:19 -04:00
INetworkFileServer * HttpFileServer = FModuleManager : : LoadModuleChecked < INetworkFileSystemModule > ( " NetworkFileSystem " )
2014-09-08 11:51:08 -04:00
. CreateNetworkFileServer ( true , BindAnyPort ? 0 : - 1 , & FileRequestDelegate , & RecompileShadersDelegate , ENetworkFileServerProtocol : : NFSP_Http ) ;
2014-07-07 15:39:19 -04:00
if ( HttpFileServer )
{
NetworkFileServers . Add ( HttpFileServer ) ;
}
2014-12-10 10:12:47 -05:00
2014-05-02 10:44:16 -04:00
// loop while waiting for requests
GIsRequestingExit = false ;
return true ;
}
bool UCookOnTheFlyServer : : BroadcastFileserverPresence ( const FGuid & InstanceId )
{
2014-07-07 15:39:19 -04:00
TArray < FString > AddressStringList ;
2014-04-23 18:33:25 -04:00
2014-07-07 15:39:19 -04:00
for ( int i = 0 ; i < NetworkFileServers . Num ( ) ; + + i )
2014-04-23 18:33:25 -04:00
{
2014-07-07 15:39:19 -04:00
TArray < TSharedPtr < FInternetAddr > > AddressList ;
INetworkFileServer * NetworkFileServer = NetworkFileServers [ i ] ;
if ( ( NetworkFileServer = = NULL | | ! NetworkFileServer - > IsItReadyToAcceptConnections ( ) | | ! NetworkFileServer - > GetAddressList ( AddressList ) ) )
2014-04-23 18:33:25 -04:00
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString ( TEXT ( " Failed to create network file server " ) ) , EMessageSeverity : : Error ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Error , TEXT ( " Failed to create network file server " ) ) ;
2014-07-07 15:39:19 -04:00
continue ;
2014-04-23 18:33:25 -04:00
}
2014-07-07 15:39:19 -04:00
// broadcast our presence
if ( InstanceId . IsValid ( ) )
2014-04-23 18:33:25 -04:00
{
2014-07-07 15:39:19 -04:00
for ( int32 AddressIndex = 0 ; AddressIndex < AddressList . Num ( ) ; + + AddressIndex )
{
AddressStringList . Add ( FString : : Printf ( TEXT ( " %s://%s " ) , * NetworkFileServer - > GetSupportedProtocol ( ) , * AddressList [ AddressIndex ] - > ToString ( true ) ) ) ;
}
}
2014-04-23 18:33:25 -04:00
}
2014-07-07 15:39:19 -04:00
FMessageEndpointPtr MessageEndpoint = FMessageEndpoint : : Builder ( " UCookOnTheFlyServer " ) . Build ( ) ;
if ( MessageEndpoint . IsValid ( ) )
{
MessageEndpoint - > Publish ( new FFileServerReady ( AddressStringList , InstanceId ) , EMessageScope : : Network ) ;
}
2014-04-23 18:33:25 -04:00
return true ;
}
2014-09-16 12:15:46 -04:00
/*----------------------------------------------------------------------------
FArchiveFindReferences .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
* Archive for gathering all the object references to other objects
*/
class FArchiveFindReferences : public FArchiveUObject
{
private :
/**
* I / O function . Called when an object reference is encountered .
*
* @ param Obj a pointer to the object that was encountered
*/
2015-04-01 07:20:55 -04:00
FArchive & operator < < ( UObject * & Obj ) override
2014-09-16 12:15:46 -04:00
{
if ( Obj )
{
FoundObject ( Obj ) ;
}
return * this ;
}
virtual FArchive & operator < < ( class FAssetPtr & Value ) override
{
if ( Value . Get ( ) )
{
Value . Get ( ) - > Serialize ( * this ) ;
}
return * this ;
}
virtual FArchive & operator < < ( struct FStringAssetReference & Value ) override
{
if ( Value . ResolveObject ( ) )
{
Value . ResolveObject ( ) - > Serialize ( * this ) ;
}
return * this ;
}
void FoundObject ( UObject * Object )
{
if ( RootSet . Find ( Object ) = = NULL )
{
if ( Exclude . Find ( Object ) = = INDEX_NONE )
{
// remove this check later because don't want this happening in development builds
2015-03-30 18:49:38 -04:00
//check(RootSetArray.Find(Object)==INDEX_NONE);
2014-09-16 12:15:46 -04:00
RootSetArray . Add ( Object ) ;
RootSet . Add ( Object ) ;
Found . Add ( Object ) ;
}
}
}
/**
* list of Outers to ignore ; any objects encountered that have one of
* these objects as an Outer will also be ignored
*/
TArray < UObject * > & Exclude ;
/** list of objects that have been found */
TSet < UObject * > & Found ;
/** the objects to display references to */
TArray < UObject * > RootSetArray ;
/** Reflection of the rootsetarray */
TSet < UObject * > RootSet ;
public :
/**
* Constructor
*
* @ param inOutputAr archive to use for logging results
* @ param inOuter only consider objects that do not have this object as its Outer
* @ param inSource object to show references for
* @ param inExclude list of objects that should be ignored if encountered while serializing SourceObject
*/
2014-09-16 15:31:36 -04:00
FArchiveFindReferences ( TSet < UObject * > InRootSet , TSet < UObject * > & inFound , TArray < UObject * > & inExclude )
2014-09-16 12:15:46 -04:00
: Exclude ( inExclude )
, Found ( inFound )
, RootSet ( InRootSet )
{
ArIsObjectReferenceCollector = true ;
2015-04-20 15:19:16 -04:00
ArIsSaving = true ;
2014-09-16 12:15:46 -04:00
for ( const auto & Object : RootSet )
{
RootSetArray . Add ( Object ) ;
}
// loop through all the objects in the root set and serialize them
for ( int RootIndex = 0 ; RootIndex < RootSetArray . Num ( ) ; + + RootIndex )
{
UObject * SourceObject = RootSetArray [ RootIndex ] ;
// quick sanity check
check ( SourceObject ) ;
check ( SourceObject - > IsValidLowLevel ( ) ) ;
SourceObject - > Serialize ( * this ) ;
}
}
/**
2015-04-24 14:41:13 -04:00
* Returns the name of the Archive . Useful for getting the name of the package a struct or object
2014-09-16 12:15:46 -04:00
* is in when a loading error occurs .
*
* This is overridden for the specific Archive Types
* */
2015-04-01 07:20:55 -04:00
virtual FString GetArchiveName ( ) const override { return TEXT ( " FArchiveFindReferences " ) ; }
2014-09-16 12:15:46 -04:00
} ;
2015-06-16 12:43:26 -04:00
void UCookOnTheFlyServer : : GetDependentPackages ( const TSet < UPackage * > & RootPackages , TSet < FName > & FoundPackages )
2015-04-20 15:19:16 -04:00
{
2015-06-16 12:43:26 -04:00
check ( IsChildCooker ( ) = = false ) ;
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
TSet < FName > RootPackageFNames ;
for ( const UPackage * RootPackage : RootPackages )
{
RootPackageFNames . Add ( RootPackage - > GetFName ( ) ) ;
}
GetDependentPackages ( RootPackageFNames , FoundPackages ) ;
}
void UCookOnTheFlyServer : : GetDependentPackages ( const TSet < FName > & RootPackages , TSet < FName > & FoundPackages )
{
check ( IsChildCooker ( ) = = false ) ;
2015-04-23 14:00:52 -04:00
static const FName AssetRegistryName ( " AssetRegistry " ) ;
2015-04-20 15:19:16 -04:00
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
TArray < FName > FoundPackagesArray ;
2015-06-16 12:43:26 -04:00
for ( const auto & RootPackage : RootPackages )
2015-04-20 15:19:16 -04:00
{
2015-06-16 12:43:26 -04:00
FoundPackagesArray . Add ( RootPackage ) ;
FoundPackages . Add ( RootPackage ) ;
2015-04-20 15:19:16 -04:00
}
int FoundPackagesCounter = 0 ;
while ( FoundPackagesCounter < FoundPackagesArray . Num ( ) )
{
TArray < FName > PackageDependencies ;
2015-06-23 11:24:52 -04:00
if ( AssetRegistry . GetDependencies ( FoundPackagesArray [ FoundPackagesCounter ] , PackageDependencies ) = = false )
{
// this could happen if we are in the editor and the dependency list is not up to date
if ( IsCookingInEditor ( ) = = false )
{
UE_LOG ( LogCook , Fatal , TEXT ( " Unable to find package %s in asset registry. Can't generate cooked asset registry " ) , * FoundPackagesArray [ FoundPackagesCounter ] . ToString ( ) ) ;
}
else
{
UE_LOG ( LogCook , Warning , TEXT ( " Unable to find package %s in asset registry, cooked asset registry information may be invalid " ) , * FoundPackagesArray [ FoundPackagesCounter ] . ToString ( ) ) ;
}
}
2015-04-20 15:19:16 -04:00
+ + FoundPackagesCounter ;
2015-04-23 14:00:52 -04:00
for ( const auto & OriginalPackageDependency : PackageDependencies )
2015-04-20 15:19:16 -04:00
{
2015-04-23 14:00:52 -04:00
// check(PackageDependency.ToString().StartsWith(TEXT("/")));
FName PackageDependency = OriginalPackageDependency ;
FString PackageDepdencyString = PackageDependency . ToString ( ) ;
2015-04-24 14:41:13 -04:00
FText OutReason ;
2015-04-27 11:24:42 -04:00
const bool bIncludeReadOnlyRoots = true ; // Dependency packages are often script packages (read-only)
if ( ! FPackageName : : IsValidLongPackageName ( PackageDepdencyString , bIncludeReadOnlyRoots , & OutReason ) )
2015-04-24 14:41:13 -04:00
{
const FText FailMessage = FText : : Format ( LOCTEXT ( " UnableToGeneratePackageName " , " Unable to generate long package name for {0}. {1} " ) ,
FText : : FromString ( PackageDepdencyString ) , OutReason ) ;
LogCookerMessage ( FailMessage . ToString ( ) , EMessageSeverity : : Warning ) ;
UE_LOG ( LogCook , Warning , TEXT ( " %s " ) , * ( FailMessage . ToString ( ) ) ) ;
2015-04-23 14:00:52 -04:00
continue ;
}
2015-04-27 15:00:57 -04:00
else if ( FPackageName : : IsScriptPackage ( PackageDepdencyString ) )
{
continue ;
}
2015-04-23 14:00:52 -04:00
2015-04-20 15:19:16 -04:00
if ( FoundPackages . Contains ( PackageDependency ) = = false )
{
FoundPackages . Add ( PackageDependency ) ;
FoundPackagesArray . Add ( PackageDependency ) ;
}
}
}
# if VERIFY_GETDEPENDENTPACKAGES
TSet < UObject * > RootSet ;
TSet < UObject * > FoundObjects ;
for ( UPackage * Package : RootPackages )
{
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( Package , ObjectsInPackage , true ) ;
for ( UObject * Obj : ObjectsInPackage )
{
RootSet . Add ( Obj ) ;
FoundObjects . Add ( Obj ) ;
}
}
TArray < UObject * > Exclude ;
FArchiveFindReferences ArFindReferences ( RootSet , FoundObjects , Exclude ) ;
TSet < UPackage * > NewFoundPackages ;
for ( const auto & Obj : FoundObjects )
{
NewFoundPackages . Add ( Obj - > GetOutermost ( ) ) ;
}
// verify that the old code (directly above) functions the same as the new code
for ( const UPackage * NewPackage : NewFoundPackages )
{
UE_LOG ( LogCook , Display , TEXT ( " Old Found package %s " ) , * NewPackage - > GetFName ( ) . ToString ( ) ) ;
}
for ( const auto & CurrentPackage : FoundPackages )
{
UE_LOG ( LogCook , Display , TEXT ( " New Found package %s " ) , * CurrentPackage . ToString ( ) ) ;
}
for ( const UPackage * NewPackage : NewFoundPackages )
{
if ( FoundPackages . Contains ( NewPackage - > GetFName ( ) ) = = false )
{
UE_LOG ( LogCook , Display , TEXT ( " Package was missing from new generated packages list %s " ) , * NewPackage - > GetFName ( ) . ToString ( ) ) ;
}
//check( FoundPackages.Contains( NewPackage->GetFName() ) );
}
check ( NewFoundPackages . Num ( ) = = FoundPackages . Num ( ) ) ;
# endif
}
2014-09-16 12:15:46 -04:00
void UCookOnTheFlyServer : : GetDependencies ( const TSet < UPackage * > & Packages , TSet < UObject * > & Found )
{
TSet < UObject * > RootSet ;
2015-03-30 18:49:38 -04:00
for ( UPackage * Package : Packages )
2014-09-16 12:15:46 -04:00
{
2015-03-30 18:49:38 -04:00
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( Package , ObjectsInPackage , true ) ;
for ( UObject * Obj : ObjectsInPackage )
2014-09-16 12:15:46 -04:00
{
2015-03-30 18:49:38 -04:00
RootSet . Add ( Obj ) ;
Found . Add ( Obj ) ;
2014-09-16 12:15:46 -04:00
}
}
TArray < UObject * > Exclude ;
FArchiveFindReferences ArFindReferences ( RootSet , Found , Exclude ) ;
}
2015-06-16 12:43:26 -04:00
bool UCookOnTheFlyServer : : ContainsMap ( const FName & PackageName ) const
{
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
TArray < FAssetData > Assets ;
ensure ( AssetRegistry . GetAssetsByPackageName ( PackageName , Assets ) ) ;
for ( const auto & Asset : Assets )
{
if ( Asset . GetClass ( ) - > IsChildOf ( UWorld : : StaticClass ( ) ) | | Asset . GetClass ( ) - > IsChildOf ( ULevel : : StaticClass ( ) ) )
{
return true ;
}
}
return false ;
}
2015-04-20 15:19:16 -04:00
void UCookOnTheFlyServer : : GenerateManifestInfo ( UPackage * Package , const TArray < FName > & TargetPlatformNames )
2014-09-16 12:15:46 -04:00
{
2015-04-20 15:19:16 -04:00
if ( ! CookByTheBookOptions )
2014-09-16 12:15:46 -04:00
return ;
2015-04-20 15:19:16 -04:00
2015-06-16 12:43:26 -04:00
check ( IsChildCooker ( ) = = false ) ;
2015-04-20 15:19:16 -04:00
2015-06-16 12:43:26 -04:00
// generate dependency information for this package
2014-09-16 12:15:46 -04:00
TSet < UPackage * > RootPackages ;
RootPackages . Add ( Package ) ;
FString LastLoadedMapName ;
// load sublevels
UWorld * World = UWorld : : FindWorldInPackage ( Package ) ;
2015-06-23 11:24:52 -04:00
# define VERIFY_LEVELS_IN_DEPENDENCIES_LIST 1
2015-06-16 12:43:26 -04:00
# if VERIFY_LEVELS_IN_DEPENDENCIES_LIST
TArray < FString > LevelPackageNames ;
# endif
2015-04-20 15:19:16 -04:00
if ( World )
2014-09-16 12:15:46 -04:00
{
for ( const auto & StreamingLevel : World - > StreamingLevels )
{
2015-04-20 15:19:16 -04:00
if ( StreamingLevel - > GetLoadedLevel ( ) )
2014-12-01 16:53:12 -05:00
{
2015-04-20 15:19:16 -04:00
RootPackages . Add ( StreamingLevel - > GetLoadedLevel ( ) - > GetOutermost ( ) ) ;
2015-06-16 12:43:26 -04:00
# if VERIFY_LEVELS_IN_DEPENDENCIES_LIST
LevelPackageNames . AddUnique ( StreamingLevel - > GetLoadedLevel ( ) - > GetOutermost ( ) - > GetName ( ) ) ;
# endif
2014-12-01 16:53:12 -05:00
}
2014-09-16 12:15:46 -04:00
}
TArray < FString > NewPackagesToCook ;
// Collect world composition tile packages to cook
if ( World - > WorldComposition )
{
World - > WorldComposition - > CollectTilesToCook ( NewPackagesToCook ) ;
}
2015-06-16 12:43:26 -04:00
# if VERIFY_LEVELS_IN_DEPENDENCIES_LIST
for ( const auto & PackageToCook : NewPackagesToCook )
{
LevelPackageNames . AddUnique ( PackageToCook ) ;
}
# endif
2015-04-20 15:19:16 -04:00
for ( const auto & PackageName : NewPackagesToCook )
2014-09-16 12:15:46 -04:00
{
2015-04-20 15:19:16 -04:00
UPackage * PackageToCook = LoadPackage ( NULL , * PackageName , LOAD_None ) ;
2014-09-16 12:15:46 -04:00
2015-04-20 15:19:16 -04:00
RootPackages . Add ( PackageToCook ) ;
2015-03-02 13:41:53 -05:00
//GetDependencies( PackageToCook, Dependencies );
2014-09-16 12:15:46 -04:00
2015-03-02 13:41:53 -05:00
// Dependencies.Add(PackageToCook);
2014-09-16 12:15:46 -04:00
}
LastLoadedMapName = Package - > GetName ( ) ;
}
2015-04-20 15:19:16 -04:00
# if USEASSETREGISTRYFORDEPENDENTPACKAGES
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
TSet < FName > Packages ;
GetDependentPackages ( RootPackages , Packages ) ;
auto GetPackageFName = [ ] ( const FName & Name ) { return Name ; } ;
2014-09-16 12:15:46 -04:00
2015-06-16 12:43:26 -04:00
# if VERIFY_LEVELS_IN_DEPENDENCIES_LIST
if ( World )
2015-04-20 15:19:16 -04:00
{
2015-06-16 12:43:26 -04:00
TSet < UPackage * > WorldPackages ;
WorldPackages . Add ( Package ) ;
TSet < FName > DependentWorldPackages ;
GetDependentPackages ( WorldPackages , DependentWorldPackages ) ;
for ( const auto & LevelPackageName : LevelPackageNames )
{
check ( DependentWorldPackages . Contains ( FName ( * LevelPackageName ) ) ) ;
}
2015-04-20 15:19:16 -04:00
}
# endif
# else
TSet < UObject * > Dependencies ;
GetDependencies ( RootPackages , Dependencies ) ;
TSet < UPackage * > Packages ;
for ( const auto & Object : Dependencies )
{
Packages . Add ( Object - > GetOutermost ( ) ) ;
}
auto GetPackageFName = [ ] ( const UPackage * Package ) { return Package - > GetFName ( ) ; } ;
# endif
2015-06-16 12:43:26 -04:00
}
2015-04-20 15:19:16 -04:00
bool UCookOnTheFlyServer : : IsCookingInEditor ( ) const
2015-01-19 10:58:24 -05:00
{
return CurrentCookMode = = ECookMode : : CookByTheBookFromTheEditor | | CurrentCookMode = = ECookMode : : CookOnTheFlyFromTheEditor ; ;
}
2014-12-01 11:58:48 -05:00
bool UCookOnTheFlyServer : : IsRealtimeMode ( ) const
2014-10-03 14:56:20 -04:00
{
2014-12-01 11:58:48 -05:00
return CurrentCookMode = = ECookMode : : CookByTheBookFromTheEditor | | CurrentCookMode = = ECookMode : : CookOnTheFlyFromTheEditor ;
}
bool UCookOnTheFlyServer : : IsCookByTheBookMode ( ) const
{
2014-12-01 16:53:12 -05:00
return CurrentCookMode = = ECookMode : : CookByTheBookFromTheEditor | | CurrentCookMode = = ECookMode : : CookByTheBook ;
2014-12-01 11:58:48 -05:00
}
bool UCookOnTheFlyServer : : IsCookOnTheFlyMode ( ) const
{
return CurrentCookMode = = ECookMode : : CookOnTheFly | | CurrentCookMode = = ECookMode : : CookOnTheFlyFromTheEditor ;
2014-10-03 14:56:20 -04:00
}
2014-09-16 12:15:46 -04:00
2015-04-27 14:10:18 -04:00
FString UCookOnTheFlyServer : : GetDLCContentPath ( )
{
return FPaths : : GamePluginsDir ( ) / CookByTheBookOptions - > DlcName / FString ( TEXT ( " Content " ) ) ;
}
2015-03-06 13:31:19 -05:00
COREUOBJECT_API extern bool GOutputCookingWarnings ;
2015-06-29 11:44:58 -04:00
bool UCookOnTheFlyServer : : TickChildCookers ( const bool bCheckIfFinished )
2015-06-16 12:43:26 -04:00
{
bool bChildCookersFinished = true ;
if ( IsCookByTheBookMode ( ) )
{
for ( auto & ChildCooker : CookByTheBookOptions - > ChildCookers )
{
if ( ChildCooker . bFinished = = false )
{
bool bIsCookerFinished = false ;
int32 ReturnCode = 0 ;
2015-06-29 11:44:58 -04:00
if ( bCheckIfFinished = = true )
2015-06-16 12:43:26 -04:00
{
2015-06-29 11:44:58 -04:00
if ( FPlatformProcess : : GetProcReturnCode ( ChildCooker . ProcessHandle , & ReturnCode ) )
2015-06-16 12:43:26 -04:00
{
2015-06-29 11:44:58 -04:00
UE_LOG ( LogCook , Display , TEXT ( " ChildCooker returned error code %d " ) , ReturnCode ) ;
ChildCooker . ReturnCode = ReturnCode ;
ChildCooker . bFinished = true ;
if ( ReturnCode ! = 0 )
{
UE_LOG ( LogCook , Error , TEXT ( " ChildCooker returned error code %d " ) , ReturnCode ) ;
}
// if the child cooker completed successfully then it would have output a list of files which the main cooker needs to process
const FString AdditionalPackagesFileName = GetChildCookerResultFilename ( ChildCooker . ResponseFileName ) ;
FString AdditionalPackages ;
if ( FFileHelper : : LoadFileToString ( AdditionalPackages , * AdditionalPackagesFileName ) = = false )
{
UE_LOG ( LogCook , Fatal , TEXT ( " ChildCooker failed to write out additional packages file to location %s " ) , * AdditionalPackagesFileName ) ;
}
TArray < FString > AdditionalPackageList ;
AdditionalPackages . ParseIntoArrayLines ( AdditionalPackageList ) ;
for ( const auto & AdditionalPackage : AdditionalPackageList )
{
FName Filename = FName ( * AdditionalPackage ) ;
FFilePlatformRequest CheckCooked = FFilePlatformRequest ( Filename , CookByTheBookOptions - > TargetPlatformNames ) ;
if ( CookedPackages . Exists ( CheckCooked ) = = false )
{
CookRequests . EnqueueUnique ( CheckCooked ) ;
}
}
}
else
{
bChildCookersFinished = false ;
2015-06-16 12:43:26 -04:00
}
}
else
{
bChildCookersFinished = false ;
}
// process the log output from the child cooker even if we just finished to ensure that we get the end of the log
FString PipeContents = FPlatformProcess : : ReadPipe ( ChildCooker . ReadPipe ) ;
if ( PipeContents . Len ( ) )
{
TArray < FString > PipeLines ;
PipeContents . ParseIntoArrayLines ( PipeLines ) ;
for ( const auto & Line : PipeLines )
{
UE_LOG ( LogCook , Display , TEXT ( " Cooker output %s: %s " ) , * ChildCooker . BaseResponseFileName , * Line ) ;
}
}
}
}
}
return bChildCookersFinished ;
}
2014-04-23 18:33:25 -04:00
uint32 UCookOnTheFlyServer : : TickCookOnTheSide ( const float TimeSlice , uint32 & CookedPackageCount )
{
2014-10-03 14:56:20 -04:00
struct FCookerTimer
{
const bool bIsRealtimeMode ;
const double StartTime ;
const float & TimeSlice ;
2015-01-22 20:35:27 -05:00
const int MaxNumPackagesToSave ; // maximum packages to save before exiting tick (this should never really hit unless we are not using realtime mode)
int NumPackagesSaved ;
FCookerTimer ( const float & InTimeSlice , bool bInIsRealtimeMode , int InMaxNumPackagesToSave = 30 ) :
bIsRealtimeMode ( bInIsRealtimeMode ) , StartTime ( FPlatformTime : : Seconds ( ) ) , TimeSlice ( InTimeSlice ) ,
MaxNumPackagesToSave ( InMaxNumPackagesToSave ) , NumPackagesSaved ( 0 )
2014-10-03 14:56:20 -04:00
{
}
double GetTimeTillNow ( )
{
return FPlatformTime : : Seconds ( ) - StartTime ;
}
bool IsTimeUp ( )
{
2015-01-22 20:35:27 -05:00
if ( bIsRealtimeMode )
{
if ( ( FPlatformTime : : Seconds ( ) - StartTime ) > TimeSlice )
{
return true ;
}
}
if ( NumPackagesSaved > = MaxNumPackagesToSave )
{
return true ;
}
return false ;
}
void SavedPackage ( )
{
+ + NumPackagesSaved ;
2014-10-03 14:56:20 -04:00
}
} ;
FCookerTimer Timer ( TimeSlice , IsRealtimeMode ( ) ) ;
2014-04-23 18:33:25 -04:00
2014-10-03 14:56:20 -04:00
uint32 Result = 0 ;
2014-11-07 13:17:07 -05:00
2015-06-16 12:43:26 -04:00
if ( IsChildCooker ( ) = = false )
2014-11-07 13:17:07 -05:00
{
2015-06-16 12:43:26 -04:00
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
if ( AssetRegistry . IsLoadingAssets ( ) )
{
// early out
return Result ;
}
2014-11-07 13:17:07 -05:00
}
2014-04-23 18:33:25 -04:00
// This is all the target platforms which we needed to process requests for this iteration
// we use this in the unsolicited packages processing below
2014-05-02 10:44:16 -04:00
TArray < FName > AllTargetPlatformNames ;
2015-06-29 11:44:58 -04:00
if ( CurrentCookMode = = ECookMode : : CookByTheBook )
2015-06-16 12:43:26 -04:00
{
2015-06-29 11:44:58 -04:00
SCOPE_TIMER ( TickChildCookers ) ;
if ( CookRequests . HasItems ( ) = = false )
{
SCOPE_TIMER ( WaitingForChildCookersToFinish ) ;
// we have nothing left to cook so we are now waiting for child cookers to finish
if ( TickChildCookers ( true ) = = false )
{
Result | = COSR_WaitingOnChildCookers ;
if ( CookRequests . HasItems ( ) = = false )
{
FPlatformProcess : : Sleep ( 0.001f ) ;
}
}
}
else
{
if ( TickChildCookers ( false ) = = false )
{
Result | = COSR_WaitingOnChildCookers ;
}
}
2015-06-16 12:43:26 -04:00
}
2015-06-29 11:44:58 -04:00
2014-09-16 12:15:46 -04:00
while ( ! GIsRequestingExit | | CurrentCookMode = = ECookMode : : CookByTheBook )
2014-04-23 18:33:25 -04:00
{
2014-09-16 12:15:46 -04:00
// if we just cooked a map then don't process anything the rest of this tick
2015-01-22 20:35:27 -05:00
if ( Result & COSR_RequiresGC )
2014-09-16 12:15:46 -04:00
{
break ;
}
2014-09-22 14:29:26 -04:00
if ( IsCookByTheBookMode ( ) )
{
check ( CookByTheBookOptions ) ;
if ( CookByTheBookOptions - > bCancel )
{
CancelCookByTheBook ( ) ;
}
}
2014-08-18 16:20:23 -04:00
2014-04-23 18:33:25 -04:00
FFilePlatformRequest ToBuild ;
2014-04-23 19:25:25 -04:00
2014-09-16 12:15:46 -04:00
//bool bIsUnsolicitedRequest = false;
if ( CookRequests . HasItems ( ) )
2014-04-23 19:25:25 -04:00
{
2014-09-16 12:15:46 -04:00
CookRequests . Dequeue ( & ToBuild ) ;
2014-04-23 19:25:25 -04:00
}
else
{
// no more to do this tick break out and do some other stuff
break ;
}
2014-04-23 18:33:25 -04:00
2014-12-10 10:12:47 -05:00
// prevent autosave from happening until we are finished cooking
// causes really bad hitches
2015-02-26 12:12:21 -05:00
if ( GUnrealEd )
2014-12-10 10:12:47 -05:00
{
const static float SecondsWarningTillAutosave = 10.0f ;
GUnrealEd - > GetPackageAutoSaver ( ) . ForceMinimumTimeTillAutoSave ( SecondsWarningTillAutosave ) ;
}
2014-09-16 12:15:46 -04:00
if ( CookedPackages . Exists ( ToBuild ) )
2014-04-23 18:33:25 -04:00
{
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Package for platform already cooked %s, discarding request " ) , * ToBuild . GetFilename ( ) . ToString ( ) ) ;
# endif
2014-09-16 12:15:46 -04:00
continue ;
}
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Processing package %s " ) , * ToBuild . GetFilename ( ) . ToString ( ) ) ;
# endif
2014-09-16 12:15:46 -04:00
SCOPE_TIMER ( TickCookOnTheSide ) ;
check ( ToBuild . IsValid ( ) ) ;
const TArray < FName > & TargetPlatformNames = ToBuild . GetPlatformnames ( ) ;
TArray < UPackage * > PackagesToSave ;
# if OUTPUT_TIMING
//FScopeTimer PackageManualTimer( ToBuild.GetFilename().ToString(), false );
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " ProcessingPackage %s " ) , * ToBuild . GetFilename ( ) . ToString ( ) ) ;
2014-09-16 12:15:46 -04:00
# endif
for ( const auto & PlatformName : TargetPlatformNames )
{
AllTargetPlatformNames . AddUnique ( PlatformName ) ;
2014-04-23 18:33:25 -04:00
}
2015-02-24 16:20:50 -05:00
for ( const auto & PlatformName : AllTargetPlatformNames )
{
if ( ToBuild . HasPlatform ( PlatformName ) = = false )
{
ToBuild . AddPlatform ( PlatformName ) ;
}
}
2014-04-23 19:25:25 -04:00
bool bWasUpToDate = false ;
2014-05-02 10:44:16 -04:00
2014-09-16 12:15:46 -04:00
bool bLastLoadWasMap = false ;
FString LastLoadedMapName ;
const FString BuildFilename = ToBuild . GetFilename ( ) . ToString ( ) ;
2015-01-13 14:11:31 -05:00
if ( ToBuild . GetFilename ( ) ! = CurrentReentryData . FileName )
{
CurrentReentryData . Reset ( ToBuild . GetFilename ( ) ) ;
}
2014-09-16 12:15:46 -04:00
// if we have no target platforms then we want to cook because this will cook for all target platforms in that case
bool bShouldCook = TargetPlatformNames . Num ( ) > 0 ? false : ShouldCook ( BuildFilename , NAME_None ) ;
2014-04-23 18:33:25 -04:00
{
2014-09-16 12:15:46 -04:00
SCOPE_TIMER ( ShouldCook ) ;
2014-04-23 19:25:25 -04:00
for ( int Index = 0 ; Index < TargetPlatformNames . Num ( ) ; + + Index )
{
2014-09-16 12:15:46 -04:00
bShouldCook | = ShouldCook ( ToBuild . GetFilename ( ) . ToString ( ) , TargetPlatformNames [ Index ] ) ;
2014-04-23 18:33:25 -04:00
}
}
2014-09-16 12:15:46 -04:00
2015-04-20 15:19:16 -04:00
if ( CookByTheBookOptions & & CookByTheBookOptions - > bErrorOnEngineContentUse )
{
2015-04-27 14:10:18 -04:00
check ( IsCookingDLC ( ) ) ;
FString DLCPath = GetDLCContentPath ( ) ;
2015-04-20 15:19:16 -04:00
if ( ToBuild . GetFilename ( ) . ToString ( ) . StartsWith ( DLCPath ) = = false ) // if we don't start with the dlc path then we shouldn't be cooking this data
{
UE_LOG ( LogCook , Error , TEXT ( " Engine content %s is being referenced by DLC! " ) , * ToBuild . GetFilename ( ) . ToString ( ) ) ;
bShouldCook = false ;
}
}
2014-09-16 12:15:46 -04:00
if ( bShouldCook ) // if we should cook the package then cook it otherwise add it to the list of already cooked packages below
2014-04-23 18:33:25 -04:00
{
2014-10-03 14:56:20 -04:00
SCOPE_TIMER ( AllOfLoadPackage ) ;
2014-09-16 12:15:46 -04:00
UPackage * Package = NULL ;
{
2015-03-02 13:41:53 -05:00
FString PackageName ;
if ( FPackageName : : TryConvertFilenameToLongPackageName ( BuildFilename , PackageName ) )
{
Package = FindObject < UPackage > ( ANY_PACKAGE , * PackageName ) ;
}
2014-09-16 12:15:46 -04:00
}
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Processing request %s " ) , * BuildFilename ) ;
# endif
2015-03-16 16:35:43 -04:00
static TSet < FString > CookWarningsList ;
if ( CookWarningsList . Contains ( BuildFilename ) = = false )
{
CookWarningsList . Add ( BuildFilename ) ;
GOutputCookingWarnings = true ;
}
2014-09-16 12:15:46 -04:00
// if the package is already loaded then try to avoid reloading it :)
if ( ( Package = = NULL ) | | ( Package - > IsFullyLoaded ( ) = = false ) )
{
// moved to GenerateDependencies
/*if (CookByTheBookOptions && CookByTheBookOptions->bGenerateStreamingInstallManifests)
{
CookByTheBookOptions - > ManifestGenerator - > PrepareToLoadNewPackage ( BuildFilename ) ;
} */
SCOPE_TIMER ( LoadPackage ) ;
Package = LoadPackage ( NULL , * BuildFilename , LOAD_None ) ;
2015-06-16 12:43:26 -04:00
INC_INT_STAT ( LoadPackage , 1 ) ;
2014-09-16 12:15:46 -04:00
}
2014-12-10 18:23:56 -05:00
# if DEBUG_COOKONTHEFLY
2014-09-16 12:15:46 -04:00
else
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Package already loaded %s avoiding reload " ) , * BuildFilename ) ;
2014-09-16 12:15:46 -04:00
}
2014-12-10 18:23:56 -05:00
# endif
2014-09-16 12:15:46 -04:00
if ( Package = = NULL )
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Error loading %s! " ) , * BuildFilename ) , EMessageSeverity : : Error ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Error , TEXT ( " Error loading %s! " ) , * BuildFilename ) ;
2014-09-16 12:15:46 -04:00
Result | = COSR_ErrorLoadingPackage ;
}
else
{
check ( Package ) ;
if ( Package - > ContainsMap ( ) )
{
2015-06-16 12:43:26 -04:00
// child cookers can't process maps
// check(IsChildCooker() == false);
2014-09-16 12:15:46 -04:00
if ( IsCookByTheBookMode ( ) )
{
// load sublevels
UWorld * World = UWorld : : FindWorldInPackage ( Package ) ;
// TArray<FString> PreviouslyCookedPackages;
if ( World - > StreamingLevels . Num ( ) )
{
//World->LoadSecondaryLevels(true, &PreviouslyCookedPackages);
World - > LoadSecondaryLevels ( true , NULL ) ;
}
TArray < FString > NewPackagesToCook ;
// Collect world composition tile packages to cook
if ( World - > WorldComposition )
{
World - > WorldComposition - > CollectTilesToCook ( NewPackagesToCook ) ;
}
for ( auto PackageName : NewPackagesToCook )
{
FString Filename ;
if ( FPackageName : : DoesPackageExist ( PackageName , NULL , & Filename ) )
{
2015-06-16 12:43:26 -04:00
check ( IsChildCooker ( ) = = false ) ;
2014-09-16 12:15:46 -04:00
FString StandardFilename = FPaths : : ConvertRelativePathToFull ( Filename ) ;
FPaths : : MakeStandardFilename ( StandardFilename ) ;
CookRequests . EnqueueUnique ( FFilePlatformRequest ( MoveTemp ( FName ( * StandardFilename ) ) , MoveTemp ( TargetPlatformNames ) ) ) ;
}
}
// maps don't compile level script actors correctly unless we do FULL GC's, they may also hold weak pointer refs that need to be reset
// NumProcessedSinceLastGC = GCInterval;
// ForceGarbageCollect();
LastLoadedMapName = Package - > GetName ( ) ;
bLastLoadWasMap = true ;
}
}
FString Name = Package - > GetPathName ( ) ;
FString PackageFilename ( GetCachedStandardPackageFilename ( Package ) ) ;
if ( PackageFilename ! = BuildFilename )
{
// we have saved something which we didn't mean to load
// sounds unpossible.... but it is due to searching for files and such
// mark the original request as processed (if this isn't actually the file they were requesting then it will fail)
// and then also save our new request as processed so we don't do it again
PackagesToSave . AddUnique ( Package ) ;
2014-12-10 18:23:56 -05:00
# if DEBUG_COOKONTHEFLY
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Request for %s received going to save %s " ) , * BuildFilename , * PackageFilename ) ;
2014-12-10 18:23:56 -05:00
# endif
2014-09-16 12:15:46 -04:00
// CookedPackages.Add( ToBuild );
// ToBuild.SetFilename( PackageFilename );
}
else
{
PackagesToSave . AddUnique ( Package ) ;
}
}
2015-03-06 13:31:19 -05:00
GOutputCookingWarnings = false ;
2014-09-16 12:15:46 -04:00
}
if ( PackagesToSave . Num ( ) = = 0 )
{
2014-10-10 10:31:37 -04:00
// if we are iterative cooking the package might already be cooked
// so just add the package to the cooked packages list
// this could also happen if the source file doesn't exist which is often as we request files with different extensions when we are searching for files
2014-09-16 12:15:46 -04:00
// just return that we processed the cook request
// the network file manager will then handle the missing file and search somewhere else
2014-12-10 18:23:56 -05:00
# if DEBUG_COOKONTHEFLY
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Not cooking package %s " ) , * ToBuild . GetFilename ( ) . ToString ( ) ) ;
2014-12-10 18:23:56 -05:00
# endif
2014-09-16 12:15:46 -04:00
CookedPackages . Add ( FFilePlatformRequest ( ToBuild . GetFilename ( ) , TargetPlatformNames ) ) ;
continue ;
2014-05-02 10:44:16 -04:00
}
2014-09-16 12:15:46 -04:00
// if we are doing cook by the book we need to resolve string asset references
// this will load more packages :)
if ( IsCookByTheBookMode ( ) )
{
SCOPE_TIMER ( ResolveRedirectors ) ;
GRedirectCollector . ResolveStringAssetReference ( ) ;
}
2014-10-03 14:56:20 -04:00
bool bIsAllDataCached = true ;
2015-02-24 16:20:50 -05:00
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
TArray < const ITargetPlatform * > TargetPlatforms ;
for ( const auto & TargetPlatformName : AllTargetPlatformNames )
{
TargetPlatforms . Add ( TPM . FindTargetPlatform ( TargetPlatformName . ToString ( ) ) ) ;
}
auto BeginPackageCacheForCookedPlatformData = [ & ] ( const TArray < UObject * > & ObjectsInPackage )
{
2015-05-18 15:52:52 -04:00
if ( CurrentReentryData . bBeginCacheFinished )
return true ;
for ( ; CurrentReentryData . BeginCacheCount < ObjectsInPackage . Num ( ) ; + + CurrentReentryData . BeginCacheCount )
2015-02-24 16:20:50 -05:00
{
2015-05-18 15:52:52 -04:00
const auto & Obj = ObjectsInPackage [ CurrentReentryData . BeginCacheCount ] ;
2015-02-24 16:20:50 -05:00
for ( const auto & TargetPlatform : TargetPlatforms )
{
Obj - > BeginCacheForCookedPlatformData ( TargetPlatform ) ;
}
if ( Timer . IsTimeUp ( ) )
{
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Object %s took too long to cache " ) , * Obj - > GetFullName ( ) ) ;
# endif
return false ;
}
}
2015-05-18 15:52:52 -04:00
CurrentReentryData . bBeginCacheFinished = true ;
2015-02-24 16:20:50 -05:00
return true ;
} ;
auto FinishPackageCacheForCookedPlatformData = [ & ] ( const TArray < UObject * > & ObjectsInPackage )
{
for ( const auto & Obj : ObjectsInPackage )
{
for ( const auto & TargetPlatform : TargetPlatforms )
{
// These begin cache calls should be quick
// because they will just be checking that the data is already cached and kicking off new multithreaded requests if not
// all sync requests should have been caught in the first begincache call above
Obj - > BeginCacheForCookedPlatformData ( TargetPlatform ) ;
if ( Obj - > IsCachedCookedPlatformDataLoaded ( TargetPlatform ) = = false )
{
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Object %s isn't cached yet " ) , * Obj - > GetFullName ( ) ) ;
# endif
return false ;
}
}
// if this objects data is cached then we can call FinishedCookedPLatformDataCache
// we can only safely call this when we are finished caching this object completely.
// this doesn't ever happen for cook in editor or cook on the fly mode
2015-04-13 16:14:12 -04:00
if ( bIsAllDataCached & & ( CurrentCookMode = = ECookMode : : CookByTheBook ) )
2015-02-24 16:20:50 -05:00
{
// this might be run multiple times for a single object
Obj - > WillNeverCacheCookedPlatformDataAgain ( ) ;
}
}
return true ;
} ;
2014-10-03 14:56:20 -04:00
if ( PackagesToSave . Num ( ) )
{
SCOPE_TIMER ( CallBeginCacheForCookedPlatformData ) ;
// cache the resources for this package for each platform
2015-02-24 16:20:50 -05:00
2014-10-03 14:56:20 -04:00
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( PackagesToSave [ 0 ] , ObjectsInPackage ) ;
2015-02-24 16:20:50 -05:00
bIsAllDataCached & = BeginPackageCacheForCookedPlatformData ( ObjectsInPackage ) ;
if ( bIsAllDataCached )
{
bIsAllDataCached & = FinishPackageCacheForCookedPlatformData ( ObjectsInPackage ) ;
2014-10-03 14:56:20 -04:00
}
}
2015-02-24 16:20:50 -05:00
// if ( IsRealtimeMode() )
2014-10-03 14:56:20 -04:00
{
if ( bIsAllDataCached = = false )
{
// reque the current task and process it next tick
CookRequests . EnqueueUnique ( ToBuild , true ) ;
2015-02-13 15:34:55 -05:00
Result | = COSR_WaitingOnCache ;
2014-12-01 11:58:48 -05:00
break ; // break out of the package tick loop
2014-10-03 14:56:20 -04:00
}
}
2014-09-16 12:15:46 -04:00
int32 FirstUnsolicitedPackage = PackagesToSave . Num ( ) ;
// generate a list of other packages which were loaded with this one
2014-05-02 10:44:16 -04:00
{
2014-08-18 16:20:23 -04:00
SCOPE_TIMER ( UnsolicitedMarkup ) ;
2014-05-02 10:44:16 -04:00
TArray < UObject * > ObjectsInOuter ;
{
2014-08-18 16:20:23 -04:00
SCOPE_TIMER ( GetObjectsWithOuter ) ;
GetObjectsWithOuter ( NULL , ObjectsInOuter , false ) ;
}
2014-05-02 10:44:16 -04:00
2014-08-18 16:20:23 -04:00
TArray < FName > PackageNames ;
PackageNames . Empty ( ObjectsInOuter . Num ( ) ) ;
{
SCOPE_TIMER ( GeneratePackageNames ) ;
2014-09-22 14:29:26 -04:00
ACCUMULATE_TIMER ( UnsolicitedPackageAlreadyCooked ) ;
2014-08-18 16:20:23 -04:00
ACCUMULATE_TIMER ( PackageCast ) ;
2014-09-16 12:15:46 -04:00
ACCUMULATE_TIMER ( AddUnassignedPackageToManifest ) ;
2014-09-22 14:29:26 -04:00
ACCUMULATE_TIMER ( GetCachedName ) ;
2014-09-16 12:15:46 -04:00
for ( int32 Index = 0 ; Index < ObjectsInOuter . Num ( ) ; Index + + )
2014-05-02 10:44:16 -04:00
{
2014-08-18 16:20:23 -04:00
ACCUMULATE_TIMER_START ( PackageCast ) ;
UPackage * Package = Cast < UPackage > ( ObjectsInOuter [ Index ] ) ;
ACCUMULATE_TIMER_STOP ( PackageCast ) ;
2014-05-02 10:44:16 -04:00
2015-01-22 20:35:27 -05:00
UObject * Object = ObjectsInOuter [ Index ] ;
if ( FullGCAssetClasses . Contains ( Object - > GetClass ( ) ) )
{
Result | = COSR_RequiresGC ;
}
2015-02-24 16:20:50 -05:00
2014-08-18 16:20:23 -04:00
if ( Package )
{
2015-01-22 20:35:27 -05:00
ACCUMULATE_TIMER_START ( GetCachedName ) ;
2014-09-22 14:29:26 -04:00
FName StandardPackageFName = GetCachedStandardPackageFileFName ( Package ) ;
2015-01-22 20:35:27 -05:00
ACCUMULATE_TIMER_STOP ( GetCachedName ) ;
2014-09-22 14:29:26 -04:00
if ( StandardPackageFName = = NAME_None )
continue ;
ACCUMULATE_TIMER_START ( UnsolicitedPackageAlreadyCooked ) ;
// package is already cooked don't care about processing it again here
if ( CookRequests . Exists ( StandardPackageFName , AllTargetPlatformNames ) )
continue ;
if ( CookedPackages . Exists ( StandardPackageFName , AllTargetPlatformNames ) )
continue ;
ACCUMULATE_TIMER_STOP ( UnsolicitedPackageAlreadyCooked ) ;
2014-09-16 12:15:46 -04:00
2015-01-22 20:35:27 -05:00
if ( StandardPackageFName ! = NAME_None ) // if we have name none that means we are in core packages or something...
2014-05-02 10:44:16 -04:00
{
2015-06-29 11:44:58 -04:00
if ( IsChildCooker ( ) )
{
// notify the main cooker that it should make sure this package gets cooked
CookByTheBookOptions - > ChildUnsolicitedPackages . Add ( StandardPackageFName ) ;
}
else
{
// check if the package has already been saved
PackagesToSave . AddUnique ( Package ) ;
}
2014-05-02 10:44:16 -04:00
}
}
}
}
2014-04-23 18:33:25 -04:00
}
2014-09-16 12:15:46 -04:00
2014-10-22 13:37:17 -04:00
bool bFinishedSave = true ;
2014-09-16 12:15:46 -04:00
if ( PackagesToSave . Num ( ) )
{
2015-05-04 14:11:21 -04:00
int32 OriginalPackagesToSaveCount = PackagesToSave . Num ( ) ;
2014-09-16 12:15:46 -04:00
SCOPE_TIMER ( SavingPackages ) ;
for ( int32 I = 0 ; I < PackagesToSave . Num ( ) ; + + I )
{
2015-05-04 14:11:21 -04:00
2015-04-13 16:14:12 -04:00
UPackage * Package = PackagesToSave [ I ] ;
2014-09-16 12:15:46 -04:00
// if we are processing unsolicited packages we can optionally not save these right now
// the unsolicited packages which we missed now will be picked up on next run
2015-01-19 10:58:24 -05:00
// we want to do this in cook on the fly also, if there is a new network package request instead of saving unsolicited packages we can process the requested package
if ( ( IsRealtimeMode ( ) | | IsCookOnTheFlyMode ( ) ) & & ( I > = FirstUnsolicitedPackage ) )
2014-09-16 12:15:46 -04:00
{
2015-05-04 14:11:21 -04:00
SCOPE_TIMER ( WaitingForCachedCookedPlatformData ) ;
2014-09-16 12:15:46 -04:00
bool bShouldFinishTick = false ;
if ( CookRequests . HasItems ( ) )
{
bShouldFinishTick = true ;
}
2014-10-03 14:56:20 -04:00
if ( Timer . IsTimeUp ( ) )
2014-09-16 12:15:46 -04:00
{
bShouldFinishTick = true ;
// our timeslice is up
}
2015-04-13 16:14:12 -04:00
bool bFinishedCachingCookedPlatformData = false ;
// if we are in realtime mode then don't wait forever for the package to be ready
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( Package , ObjectsInPackage ) ;
while ( ( ! Timer . IsTimeUp ( ) ) & & IsRealtimeMode ( ) & & ( bShouldFinishTick = = false ) )
{
if ( FinishPackageCacheForCookedPlatformData ( ObjectsInPackage ) = = true )
{
bFinishedCachingCookedPlatformData = true ;
break ;
}
// sleep for a bit
FPlatformProcess : : Sleep ( 0.0f ) ;
}
bShouldFinishTick | = ! bFinishedCachingCookedPlatformData ;
2014-09-16 12:15:46 -04:00
if ( bShouldFinishTick )
{
2014-09-22 14:29:26 -04:00
SCOPE_TIMER ( EnqueueUnsavedPackages ) ;
2014-09-16 12:15:46 -04:00
// don't save these packages because we have a real request
// enqueue all the packages which we were about to save
if ( CurrentCookMode = = ECookMode : : CookByTheBookFromTheEditor )
{
for ( int32 RemainingIndex = I ; RemainingIndex < PackagesToSave . Num ( ) ; + + RemainingIndex )
{
FName StandardFilename = GetCachedStandardPackageFileFName ( PackagesToSave [ RemainingIndex ] ) ;
CookRequests . EnqueueUnique ( FFilePlatformRequest ( StandardFilename , AllTargetPlatformNames ) ) ;
}
}
// break out of the loop
2014-10-22 13:37:17 -04:00
bFinishedSave = false ;
2014-09-16 12:15:46 -04:00
break ;
}
}
FName PackageFName = GetCachedStandardPackageFileFName ( Package ) ;
TArray < FName > SaveTargetPlatformNames = AllTargetPlatformNames ;
TArray < FName > CookedTargetPlatforms ;
if ( CookedPackages . GetCookedPlatforms ( PackageFName , CookedTargetPlatforms ) )
{
for ( auto const & CookedPlatform : CookedTargetPlatforms )
{
SaveTargetPlatformNames . Remove ( CookedPlatform ) ;
}
}
if ( SaveTargetPlatformNames . Num ( ) = = 0 )
{
// already saved this package
continue ;
}
2015-02-24 16:20:50 -05:00
// precache platform data for next package
UPackage * NextPackage = PackagesToSave [ FMath : : Min ( PackagesToSave . Num ( ) - 1 , I + 1 ) ] ;
UPackage * NextNextPackage = PackagesToSave [ FMath : : Min ( PackagesToSave . Num ( ) - 1 , I + 2 ) ] ;
if ( NextPackage ! = Package )
{
2015-05-04 14:11:21 -04:00
SCOPE_TIMER ( PrecachePlatformDataForNextPackage ) ;
2015-02-24 16:20:50 -05:00
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( NextPackage , ObjectsInPackage ) ;
BeginPackageCacheForCookedPlatformData ( ObjectsInPackage ) ;
}
if ( NextNextPackage ! = NextPackage )
{
2015-05-04 14:11:21 -04:00
SCOPE_TIMER ( PrecachePlatformDataForNextNextPackage ) ;
2015-02-24 16:20:50 -05:00
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( NextNextPackage , ObjectsInPackage ) ;
BeginPackageCacheForCookedPlatformData ( ObjectsInPackage ) ;
}
2015-05-04 14:11:21 -04:00
// if we are running the cook commandlet
// if we already went through the entire package list then don't keep requeuing requests
if ( ! IsCookOnTheFlyMode ( ) & & ! IsRealtimeMode ( ) & & ( I < OriginalPackagesToSaveCount ) )
{
// we don't want to break out of this function without saving all the packages
// we can skip this package and do it later though
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( Package , ObjectsInPackage ) ;
if ( FinishPackageCacheForCookedPlatformData ( ObjectsInPackage ) = = false )
{
PackagesToSave . Add ( Package ) ;
}
}
2015-03-06 13:31:19 -05:00
bool bShouldSaveAsync = true ;
FString Temp ;
if ( FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " -diffagainstcookdirectory= " ) , Temp ) | | FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " -breakonfile= " ) , Temp ) )
{
// async save doesn't work with this flags
bShouldSaveAsync = false ;
}
2014-09-16 12:15:46 -04:00
{
2015-05-04 14:11:21 -04:00
SCOPE_TIMER ( SaveCookedPackage ) ;
if ( SaveCookedPackage ( Package , SAVE_KeepGUID | ( bShouldSaveAsync ? SAVE_Async : SAVE_None ) | ( IsCookFlagSet ( ECookInitializationFlags : : Unversioned ) ? SAVE_Unversioned : 0 ) , bWasUpToDate , AllTargetPlatformNames ) )
2014-09-16 12:15:46 -04:00
{
2015-05-04 14:11:21 -04:00
// Update flags used to determine garbage collection.
if ( Package - > ContainsMap ( ) )
{
Result | = COSR_CookedMap ;
}
else
{
+ + CookedPackageCount ;
Result | = COSR_CookedPackage ;
}
2014-09-16 12:15:46 -04:00
}
2015-05-04 14:11:21 -04:00
Timer . SavedPackage ( ) ;
2014-09-16 12:15:46 -04:00
}
2015-06-23 11:24:52 -04:00
if ( IsCookingInEditor ( ) = = false )
2015-02-24 16:20:50 -05:00
{
SCOPE_TIMER ( ClearAllCachedCookedPlatformData ) ;
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( Package , ObjectsInPackage ) ;
for ( const auto & Object : ObjectsInPackage )
{
Object - > ClearAllCachedCookedPlatformData ( ) ;
}
}
2014-09-16 12:15:46 -04:00
//@todo ResetLoaders outside of this (ie when Package is NULL) causes problems w/ default materials
if ( Package - > HasAnyFlags ( RF_RootSet ) = = false & & ( ( CurrentCookMode = = ECookMode : : CookOnTheFly ) ) )
{
SCOPE_TIMER ( ResetLoaders ) ;
ResetLoaders ( Package ) ;
}
FName StandardFilename = GetCachedStandardPackageFileFName ( Package ) ;
if ( StandardFilename ! = NAME_None )
{
// mark the package as cooked
FFilePlatformRequest FileRequest ( StandardFilename , AllTargetPlatformNames ) ;
CookedPackages . Add ( FileRequest ) ;
if ( ( CurrentCookMode = = ECookMode : : CookOnTheFly ) & & ( I > = FirstUnsolicitedPackage ) )
{
// this is an unsolicited package
if ( ( FPaths : : FileExists ( FileRequest . GetFilename ( ) . ToString ( ) ) = = true ) & &
( bWasUpToDate = = false ) )
{
UnsolicitedCookedPackages . AddCookedPackage ( FileRequest ) ;
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " UnsolicitedCookedPackages: %s " ) , * FileRequest . GetFilename ( ) . ToString ( ) ) ;
# endif
2014-09-16 12:15:46 -04:00
}
}
}
}
}
// if after all this our requested file didn't get saved then we need to mark it as saved (this can happen if the file loaded didn't match the one we saved)
// for example say we request A.uasset which doesn't exist however A.umap exists, our load call will succeed as it will find A.umap, then the save will save A.umap
// our original package request will fail however
if ( ! CookedPackages . Exists ( ToBuild ) )
{
CookedPackages . Add ( ToBuild ) ;
}
// TODO: Daniel: this is reference code needs to be reimplemented on the callee side.
// cooker can't depend on callee being able to garbage collect
// collect garbage
2014-10-22 13:39:24 -04:00
if ( CookByTheBookOptions & & CookByTheBookOptions - > bLeakTest & & bFinishedSave )
2014-09-16 12:15:46 -04:00
{
2014-10-22 13:37:17 -04:00
check ( CurrentCookMode = = ECookMode : : CookByTheBook ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Full GC... " ) ) ;
2014-09-16 12:15:46 -04:00
2015-06-16 18:42:56 -04:00
CollectGarbage ( GARBAGE_COLLECTION_KEEPFLAGS ) ;
2014-10-22 13:39:24 -04:00
for ( FObjectIterator It ; It ; + + It )
{
2014-10-22 13:37:17 -04:00
if ( ! CookByTheBookOptions - > LastGCItems . Contains ( FWeakObjectPtr ( * It ) ) )
2014-10-22 13:39:24 -04:00
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " \t Leaked %s " ) , * ( It - > GetFullName ( ) ) ) ;
2014-10-22 13:37:17 -04:00
CookByTheBookOptions - > LastGCItems . Add ( FWeakObjectPtr ( * It ) ) ;
2014-10-22 13:39:24 -04:00
}
}
2014-10-22 13:37:17 -04:00
}
2014-10-03 14:56:20 -04:00
if ( Timer . IsTimeUp ( ) )
2014-04-23 18:33:25 -04:00
{
2014-04-23 19:25:25 -04:00
break ;
2014-04-23 18:33:25 -04:00
}
2014-08-18 16:20:23 -04:00
}
2014-09-16 12:15:46 -04:00
OUTPUT_TIMERS ( ) ;
if ( CookByTheBookOptions )
{
2014-10-03 14:56:20 -04:00
CookByTheBookOptions - > CookTime + = Timer . GetTimeTillNow ( ) ;
2014-09-16 12:15:46 -04:00
}
if ( IsCookByTheBookRunning ( ) & &
2015-06-29 11:44:58 -04:00
( CookRequests . HasItems ( ) = = false ) & &
( ! ( Result & COSR_WaitingOnChildCookers ) ) )
2014-09-16 12:15:46 -04:00
{
check ( IsCookByTheBookMode ( ) ) ;
// if we are out of stuff and we are in cook by the book from the editor mode then we finish up
CookByTheBookFinished ( ) ;
}
2014-04-23 18:33:25 -04:00
return Result ;
}
2014-05-02 10:44:16 -04:00
void UCookOnTheFlyServer : : OnObjectModified ( UObject * ObjectMoving )
{
OnObjectUpdated ( ObjectMoving ) ;
}
2014-05-07 22:17:44 -04:00
void UCookOnTheFlyServer : : OnObjectPropertyChanged ( UObject * ObjectBeingModified , FPropertyChangedEvent & PropertyChangedEvent )
2014-05-02 10:44:16 -04:00
{
OnObjectUpdated ( ObjectBeingModified ) ;
}
2015-01-29 17:25:52 -05:00
void UCookOnTheFlyServer : : OnObjectSaved ( UObject * ObjectSaved )
{
OnObjectUpdated ( ObjectSaved ) ;
}
2014-05-02 10:44:16 -04:00
void UCookOnTheFlyServer : : OnObjectUpdated ( UObject * Object )
{
// get the outer of the object
UPackage * Package = Object - > GetOutermost ( ) ;
MarkPackageDirtyForCooker ( Package ) ;
}
void UCookOnTheFlyServer : : MarkPackageDirtyForCooker ( UPackage * Package )
{
2014-09-16 12:15:46 -04:00
if ( ! bIsSavingPackage )
{
// could have just cooked a file which we might need to write
UPackage : : WaitForAsyncFileWrites ( ) ;
2014-05-02 10:44:16 -04:00
2014-09-16 12:15:46 -04:00
// force that package to be recooked
const FString Name = Package - > GetPathName ( ) ;
/*FString PackageFilename(GetPackageFilename(Package));
FPaths : : MakeStandardFilename ( PackageFilename ) ; */
2015-01-19 10:58:24 -05:00
2015-04-13 16:14:12 -04:00
FName PackageFFileName = GetCachedStandardPackageFileFName ( Package ) ;
2015-01-29 17:25:52 -05:00
2015-04-13 16:14:12 -04:00
if ( PackageFFileName = = NAME_None )
{
ClearPackageFilenameCacheForPackage ( Package ) ;
}
2015-01-19 10:58:24 -05:00
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Modification detected to package %s " ) , * PackageFilename ) ;
# endif
2014-09-16 12:15:46 -04:00
2014-10-22 13:37:17 -04:00
if ( CurrentCookMode = = ECookMode : : CookByTheBookFromTheEditor )
{
TArray < FName > CookedPlatforms ;
2014-11-20 17:26:12 -05:00
// if we have already cooked this package and we have made changes then recook ;)
2014-10-22 13:37:17 -04:00
if ( CookedPackages . GetCookedPlatforms ( PackageFFileName , CookedPlatforms ) )
{
2014-11-20 17:26:12 -05:00
if ( IsCookByTheBookRunning ( ) )
{
2015-01-29 17:25:52 -05:00
// if this package was previously cooked and we are doing a cook by the book
// we need to recook this package before finishing cook by the book
CookRequests . EnqueueUnique ( FFilePlatformRequest ( PackageFFileName , CookedPlatforms ) ) ;
}
2014-10-22 13:37:17 -04:00
}
}
2014-12-10 10:12:47 -05:00
CookedPackages . RemoveFile ( PackageFFileName ) ;
2014-09-16 12:15:46 -04:00
}
2014-05-02 10:44:16 -04:00
}
2014-04-23 18:33:25 -04:00
void UCookOnTheFlyServer : : EndNetworkFileServer ( )
{
2014-07-07 15:39:19 -04:00
for ( int i = 0 ; i < NetworkFileServers . Num ( ) ; + + i )
2014-04-23 18:33:25 -04:00
{
2014-07-07 15:39:19 -04:00
INetworkFileServer * NetworkFileServer = NetworkFileServers [ i ] ;
2014-04-23 18:33:25 -04:00
// shutdown the server
NetworkFileServer - > Shutdown ( ) ;
delete NetworkFileServer ;
NetworkFileServer = NULL ;
}
2014-09-22 14:29:26 -04:00
NetworkFileServers . Empty ( ) ;
2014-04-23 18:33:25 -04:00
}
2015-01-22 20:35:27 -05:00
void UCookOnTheFlyServer : : SetFullGCAssetClasses ( const TArray < UClass * > & InFullGCAssetClasses )
{
FullGCAssetClasses = InFullGCAssetClasses ;
}
2015-03-26 18:38:30 -04:00
uint32 UCookOnTheFlyServer : : GetPackagesPerGC ( ) const
{
return PackagesPerGC ;
}
double UCookOnTheFlyServer : : GetIdleTimeToGC ( ) const
{
return IdleTimeToGC ;
}
uint64 UCookOnTheFlyServer : : GetMaxMemoryAllowance ( ) const
{
return MaxMemoryAllowance ;
}
2014-04-23 18:33:25 -04:00
void UCookOnTheFlyServer : : BeginDestroy ( )
{
EndNetworkFileServer ( ) ;
Super : : BeginDestroy ( ) ;
}
void UCookOnTheFlyServer : : TickRecompileShaderRequests ( )
{
// try to pull off a request
FRecompileRequest * Request = NULL ;
RecompileRequests . Dequeue ( & Request ) ;
// process it
if ( Request )
{
HandleNetworkFileServerRecompileShaders ( Request - > RecompileData ) ;
2014-09-16 12:15:46 -04:00
2014-04-23 18:33:25 -04:00
// all done! other thread can unblock now
Request - > bComplete = true ;
}
}
bool UCookOnTheFlyServer : : GetPackageTimestamp ( const FString & InFilename , FDateTime & OutDateTime )
{
FPackageDependencyInfoModule & PDInfoModule = FModuleManager : : LoadModuleChecked < FPackageDependencyInfoModule > ( " PackageDependencyInfo " ) ;
FDateTime DependentTime ;
if ( PDInfoModule . DeterminePackageDependentTimeStamp ( * InFilename , DependentTime ) = = true )
{
OutDateTime = DependentTime ;
return true ;
}
return false ;
}
bool UCookOnTheFlyServer : : SaveCookedPackage ( UPackage * Package , uint32 SaveFlags , bool & bOutWasUpToDate )
{
2014-05-02 10:44:16 -04:00
TArray < FName > TargetPlatformNames ;
2014-04-23 18:33:25 -04:00
return SaveCookedPackage ( Package , SaveFlags , bOutWasUpToDate , TargetPlatformNames ) ;
}
2014-05-02 10:44:16 -04:00
bool UCookOnTheFlyServer : : ShouldCook ( const FString & InFileName , const FName & InPlatformName )
2014-04-23 19:25:25 -04:00
{
2014-12-12 12:59:47 -05:00
// this only does anything if we are using iterative cooking
return true ;
/*
2014-04-23 19:25:25 -04:00
bool bDoCook = false ;
FString PkgFile ;
FString PkgFilename ;
FDateTime DependentTimeStamp = FDateTime : : MinValue ( ) ;
2014-09-16 12:15:46 -04:00
if ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) & & FPackageName : : DoesPackageExist ( InFileName , NULL , & PkgFile ) )
2014-04-23 19:25:25 -04:00
{
PkgFilename = PkgFile ;
if ( GetPackageTimestamp ( FPaths : : GetBaseFilename ( PkgFilename , false ) , DependentTimeStamp ) = = false )
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Failed to find dependency timestamp for: %s " ) , * PkgFilename ) ;
2014-04-23 19:25:25 -04:00
}
}
// Use SandboxFile to do path conversion to properly handle sandbox paths (outside of standard paths in particular).
2014-12-01 16:53:12 -05:00
PkgFilename = ConvertToFullSandboxPath ( * PkgFilename , true ) ;
2014-04-23 19:25:25 -04:00
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
2014-09-16 12:15:46 -04:00
static const TArray < ITargetPlatform * > & ActiveTargetPlatforms = TPM . GetCookingTargetPlatforms ( ) ;
2014-04-23 19:25:25 -04:00
TArray < ITargetPlatform * > Platforms ;
2014-05-02 10:44:16 -04:00
if ( InPlatformName ! = NAME_None )
2014-04-23 19:25:25 -04:00
{
2014-05-02 10:44:16 -04:00
Platforms . Add ( TPM . FindTargetPlatform ( InPlatformName . ToString ( ) ) ) ;
2014-04-23 19:25:25 -04:00
}
else
{
Platforms = ActiveTargetPlatforms ;
}
for ( int32 Index = 0 ; Index < Platforms . Num ( ) & & ! bDoCook ; Index + + )
{
ITargetPlatform * Target = Platforms [ Index ] ;
FString PlatFilename = PkgFilename . Replace ( TEXT ( " [Platform] " ) , * Target - > PlatformName ( ) ) ;
// If we are not iterative cooking, then cook the package
2014-09-16 12:15:46 -04:00
bool bCookPackage = ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) = = false ) ;
2014-04-23 19:25:25 -04:00
if ( bCookPackage = = false )
{
// If the cooked package doesn't exist, or if the cooked is older than the dependent, re-cook it
FDateTime CookedTimeStamp = IFileManager : : Get ( ) . GetTimeStamp ( * PlatFilename ) ;
int32 CookedTimespanSeconds = ( CookedTimeStamp - DependentTimeStamp ) . GetTotalSeconds ( ) ;
bCookPackage = ( CookedTimeStamp = = FDateTime : : MinValue ( ) ) | | ( CookedTimespanSeconds < 0 ) ;
}
bDoCook | = bCookPackage ;
}
2014-12-12 12:59:47 -05:00
return bDoCook ; */
2014-04-23 19:25:25 -04:00
}
2015-01-26 20:34:31 -05:00
bool UCookOnTheFlyServer : : ShouldConsiderCompressedPackageFileLengthRequirements ( ) const
{
bool bConsiderCompressedPackageFileLengthRequirements = true ;
GConfig - > GetBool ( TEXT ( " CookSettings " ) , TEXT ( " bConsiderCompressedPackageFileLengthRequirements " ) , bConsiderCompressedPackageFileLengthRequirements , GEditorIni ) ;
return bConsiderCompressedPackageFileLengthRequirements ;
}
2014-05-02 10:44:16 -04:00
bool UCookOnTheFlyServer : : SaveCookedPackage ( UPackage * Package , uint32 SaveFlags , bool & bOutWasUpToDate , TArray < FName > & TargetPlatformNames )
2014-04-23 18:33:25 -04:00
{
bool bSavedCorrectly = true ;
2014-09-16 12:15:46 -04:00
check ( bIsSavingPackage = = false ) ;
bIsSavingPackage = true ;
2014-08-18 16:20:23 -04:00
FString Filename ( GetCachedPackageFilename ( Package ) ) ;
2014-04-23 18:33:25 -04:00
if ( Filename . Len ( ) )
{
2014-12-10 10:12:47 -05:00
FString Name = Package - > GetPathName ( ) ;
/*FString PkgFilename;
2014-04-23 18:33:25 -04:00
FDateTime DependentTimeStamp = FDateTime : : MinValue ( ) ;
// We always want to use the dependent time stamp when saving a cooked package...
// Iterative or not!
FString PkgFile ;
2014-12-10 10:12:47 -05:00
2014-04-23 18:33:25 -04:00
2014-09-16 12:15:46 -04:00
if ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) & & FPackageName : : DoesPackageExist ( Name , NULL , & PkgFile ) )
2014-04-23 18:33:25 -04:00
{
PkgFilename = PkgFile ;
if ( GetPackageTimestamp ( FPaths : : GetBaseFilename ( PkgFilename , false ) , DependentTimeStamp ) = = false )
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Failed to find depedency timestamp for: %s " ) , * PkgFilename ) ;
2014-04-23 18:33:25 -04:00
}
2014-12-10 10:12:47 -05:00
} */
2014-04-23 18:33:25 -04:00
// Use SandboxFile to do path conversion to properly handle sandbox paths (outside of standard paths in particular).
2014-12-01 16:53:12 -05:00
Filename = ConvertToFullSandboxPath ( * Filename , true ) ;
2014-04-23 18:33:25 -04:00
uint32 OriginalPackageFlags = Package - > PackageFlags ;
2015-04-24 14:41:13 -04:00
UWorld * World = NULL ;
EObjectFlags Flags = RF_NoFlags ;
2014-04-23 18:33:25 -04:00
bool bPackageFullyLoaded = false ;
2015-05-22 11:39:21 -04:00
bool bShouldCompressPackage = IsCookFlagSet ( ECookInitializationFlags : : Compressed ) ;
if ( CookByTheBookOptions )
{
bShouldCompressPackage & = ( CookByTheBookOptions - > bForceDisableCompressedPackages = = false ) ;
bShouldCompressPackage | = CookByTheBookOptions - > bForceEnableCompressedPackages ;
}
2014-04-23 18:33:25 -04:00
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
2014-09-16 12:15:46 -04:00
static TArray < ITargetPlatform * > ActiveStartupPlatforms = TPM . GetCookingTargetPlatforms ( ) ;
2014-04-23 18:33:25 -04:00
TArray < ITargetPlatform * > Platforms ;
if ( TargetPlatformNames . Num ( ) )
{
2014-05-29 16:52:50 -04:00
const TArray < ITargetPlatform * > & TargetPlatforms = TPM . GetTargetPlatforms ( ) ;
for ( const FName TargetPlatformFName : TargetPlatformNames )
2014-04-23 18:33:25 -04:00
{
2014-05-29 16:52:50 -04:00
const FString TargetPlatformName = TargetPlatformFName . ToString ( ) ;
2014-04-23 18:33:25 -04:00
2014-05-29 16:52:50 -04:00
for ( ITargetPlatform * TargetPlatform : TargetPlatforms )
2014-04-23 18:33:25 -04:00
{
if ( TargetPlatform - > PlatformName ( ) = = TargetPlatformName )
{
Platforms . Add ( TargetPlatform ) ;
}
}
}
}
else
{
Platforms = ActiveStartupPlatforms ;
2014-05-29 16:52:50 -04:00
for ( ITargetPlatform * Platform : Platforms )
2014-04-23 18:33:25 -04:00
{
2014-05-29 16:52:50 -04:00
TargetPlatformNames . Add ( FName ( * Platform - > PlatformName ( ) ) ) ;
2014-04-23 18:33:25 -04:00
}
}
2015-05-29 18:46:07 -04:00
for ( const auto & TargetPlatform : Platforms )
{
bShouldCompressPackage & = TargetPlatform - > SupportsFeature ( ETargetPlatformFeatures : : ShouldUseCompressedCookedPackages ) ;
}
if ( bShouldCompressPackage )
{
Package - > PackageFlags | = PKG_StoreCompressed ;
}
2014-04-23 18:33:25 -04:00
2014-05-29 16:52:50 -04:00
for ( ITargetPlatform * Target : Platforms )
2014-04-23 18:33:25 -04:00
{
FString PlatFilename = Filename . Replace ( TEXT ( " [Platform] " ) , * Target - > PlatformName ( ) ) ;
2014-12-10 10:12:47 -05:00
bool bCookPackage = true ;
2015-04-13 16:14:12 -04:00
// this code has been moved to the clean sandbox so that it's only processed in one location on startup
// will remove this code in future release
2014-04-23 18:33:25 -04:00
// If we are not iterative cooking, then cook the package
2014-12-10 10:12:47 -05:00
/*bool bCookPackage = (IsCookFlagSet(ECookInitializationFlags::Iterative) == false);
2014-04-23 18:33:25 -04:00
if ( bCookPackage = = false )
{
// If the cooked package doesn't exist, or if the cooked is older than the dependent, re-cook it
FDateTime CookedTimeStamp = IFileManager : : Get ( ) . GetTimeStamp ( * PlatFilename ) ;
int32 CookedTimespanSeconds = ( CookedTimeStamp - DependentTimeStamp ) . GetTotalSeconds ( ) ;
bCookPackage = ( CookedTimeStamp = = FDateTime : : MinValue ( ) ) | | ( CookedTimespanSeconds < 0 ) ;
2014-12-10 10:12:47 -05:00
} */
2014-04-23 18:33:25 -04:00
// don't save Editor resources from the Engine if the target doesn't have editoronly data
2014-09-16 12:15:46 -04:00
if ( IsCookFlagSet ( ECookInitializationFlags : : SkipEditorContent ) & & Name . StartsWith ( TEXT ( " /Engine/Editor " ) ) & & ! Target - > HasEditorOnlyData ( ) )
2014-04-23 18:33:25 -04:00
{
bCookPackage = false ;
}
if ( bCookPackage = = true )
{
if ( bPackageFullyLoaded = = false )
{
2014-09-16 12:15:46 -04:00
SCOPE_TIMER ( LoadPackage ) ;
2014-04-23 18:33:25 -04:00
Package - > FullyLoad ( ) ;
if ( ! Package - > IsFullyLoaded ( ) )
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Package %s supposed to be fully loaded but isn't. RF_WasLoaded is %s " ) ,
* Package - > GetName ( ) , Package - > HasAnyFlags ( RF_WasLoaded ) ? TEXT ( " set " ) : TEXT ( " not set " ) ) , EMessageSeverity : : Warning ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " Package %s supposed to be fully loaded but isn't. RF_WasLoaded is %s " ) ,
2014-04-23 18:33:25 -04:00
* Package - > GetName ( ) , Package - > HasAnyFlags ( RF_WasLoaded ) ? TEXT ( " set " ) : TEXT ( " not set " ) ) ;
}
bPackageFullyLoaded = true ;
// If fully loading has caused a blueprint to be regenerated, make sure we eliminate all meta data outside the package
UMetaData * MetaData = Package - > GetMetaData ( ) ;
MetaData - > RemoveMetaDataOutsidePackage ( ) ;
// look for a world object in the package (if there is one, there's a map)
World = UWorld : : FindWorldInPackage ( Package ) ;
Flags = World ? RF_NoFlags : RF_Standalone ;
}
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Cooking %s -> %s " ) , * Package - > GetName ( ) , * PlatFilename ) ;
2014-04-23 18:33:25 -04:00
bool bSwap = ( ! Target - > IsLittleEndian ( ) ) ^ ( ! PLATFORM_LITTLE_ENDIAN ) ;
if ( ! Target - > HasEditorOnlyData ( ) )
{
Package - > PackageFlags | = PKG_FilterEditorOnly ;
}
else
{
Package - > PackageFlags & = ~ PKG_FilterEditorOnly ;
}
2015-01-26 20:34:31 -05:00
// need to subtract 32 because the SavePackage code creates temporary files with longer file names then the one we provide
// projects may ignore this restriction if desired
static bool bConsiderCompressedPackageFileLengthRequirements = ShouldConsiderCompressedPackageFileLengthRequirements ( ) ;
const int32 CompressedPackageFileLengthRequirement = bConsiderCompressedPackageFileLengthRequirements ? 32 : 0 ;
2014-05-08 14:07:04 -04:00
const FString FullFilename = FPaths : : ConvertRelativePathToFull ( PlatFilename ) ;
2015-01-26 20:34:31 -05:00
if ( FullFilename . Len ( ) > = ( PLATFORM_MAX_FILEPATH_LENGTH - CompressedPackageFileLengthRequirement ) )
2014-04-23 18:33:25 -04:00
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Couldn't save package, filename is too long: %s " ) , * PlatFilename ) , EMessageSeverity : : Error ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Error , TEXT ( " Couldn't save package, filename is too long :%s " ) , * PlatFilename ) ;
2014-04-23 18:33:25 -04:00
bSavedCorrectly = false ;
}
else
{
2014-09-16 12:15:46 -04:00
SCOPE_TIMER ( GEditorSavePackage ) ;
2014-10-23 15:26:32 -04:00
bSavedCorrectly & = GEditor - > SavePackage ( Package , World , Flags , * PlatFilename , GError , NULL , bSwap , false , SaveFlags , Target , FDateTime : : MinValue ( ) , false ) ;
2015-06-16 12:43:26 -04:00
INC_INT_STAT ( SavedPackage , 1 ) ;
2014-04-23 18:33:25 -04:00
}
2015-06-23 18:58:21 -04:00
2014-04-23 18:33:25 -04:00
bOutWasUpToDate = false ;
}
else
{
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Up to date: %s " ) , * PlatFilename ) ;
# endif
2014-04-23 18:33:25 -04:00
bOutWasUpToDate = true ;
}
}
Package - > PackageFlags = OriginalPackageFlags ;
}
2014-09-16 12:15:46 -04:00
check ( bIsSavingPackage = = true ) ;
bIsSavingPackage = false ;
2014-04-23 18:33:25 -04:00
// return success
return bSavedCorrectly ;
}
2014-12-10 10:12:47 -05:00
void UCookOnTheFlyServer : : Initialize ( ECookMode : : Type DesiredCookMode , ECookInitializationFlags InCookFlags , const FString & InOutputDirectoryOverride )
2014-04-23 18:33:25 -04:00
{
2014-12-10 10:12:47 -05:00
OutputDirectoryOverride = InOutputDirectoryOverride ;
2014-09-16 12:15:46 -04:00
CurrentCookMode = DesiredCookMode ;
CookFlags = InCookFlags ;
2015-01-22 20:35:27 -05:00
2015-06-16 12:43:26 -04:00
if ( IsCookByTheBookMode ( ) & & ! IsCookingInEditor ( ) )
{
FCoreUObjectDelegates : : PackageCreatedForLoad . AddUObject ( this , & UCookOnTheFlyServer : : MaybeMarkPackageAsAlreadyLoaded ) ;
}
if ( IsCookingInEditor ( ) )
{
FCoreUObjectDelegates : : OnObjectPropertyChanged . AddUObject ( this , & UCookOnTheFlyServer : : OnObjectPropertyChanged ) ;
FCoreUObjectDelegates : : OnObjectModified . AddUObject ( this , & UCookOnTheFlyServer : : OnObjectModified ) ;
FCoreUObjectDelegates : : OnObjectSaved . AddUObject ( this , & UCookOnTheFlyServer : : OnObjectSaved ) ;
}
2015-04-29 13:42:40 -04:00
bool bUseFullGCAssetClassNames = true ;
GConfig - > GetBool ( TEXT ( " CookSettings " ) , TEXT ( " bUseFullGCAssetClassNames " ) , bUseFullGCAssetClassNames , GEditorIni ) ;
if ( bUseFullGCAssetClassNames )
2015-01-22 20:35:27 -05:00
{
2015-04-29 13:42:40 -04:00
TArray < FString > FullGCAssetClassNames ;
GConfig - > GetArray ( TEXT ( " CookSettings " ) , TEXT ( " FullGCAssetClassNames " ) , FullGCAssetClassNames , GEditorIni ) ;
for ( const auto & FullGCAssetClassName : FullGCAssetClassNames )
2015-01-22 20:35:27 -05:00
{
2015-04-29 13:42:40 -04:00
UClass * FullGCAssetClass = FindObject < UClass > ( ANY_PACKAGE , * FullGCAssetClassName , true ) ;
if ( FullGCAssetClass = = NULL )
{
UE_LOG ( LogCook , Warning , TEXT ( " Unable to find full gc asset class name %s may result in bad cook " ) , * FullGCAssetClassName ) ;
}
else
{
FullGCAssetClasses . Add ( FullGCAssetClass ) ;
}
2015-01-22 20:35:27 -05:00
}
2015-04-29 13:42:40 -04:00
if ( FullGCAssetClasses . Num ( ) = = 0 )
2015-01-22 20:35:27 -05:00
{
2015-04-29 13:42:40 -04:00
// default to UWorld
FullGCAssetClasses . Add ( UWorld : : StaticClass ( ) ) ;
2015-01-22 20:35:27 -05:00
}
}
2015-03-26 18:38:30 -04:00
PackagesPerGC = 50 ;
int32 ConfigPackagesPerGC = 0 ;
if ( GConfig - > GetInt ( TEXT ( " CookSettings " ) , TEXT ( " PackagesPerGC " ) , ConfigPackagesPerGC , GEditorIni ) )
{
// Going unsigned. Make negative values 0
PackagesPerGC = ConfigPackagesPerGC > 0 ? ConfigPackagesPerGC : 0 ;
}
IdleTimeToGC = 20.0 ;
GConfig - > GetDouble ( TEXT ( " CookSettings " ) , TEXT ( " IdleTimeToGC " ) , IdleTimeToGC , GEditorIni ) ;
int32 MaxMemoryAllowanceInMB = 8 * 1024 ;
GConfig - > GetInt ( TEXT ( " CookSettings " ) , TEXT ( " MaxMemoryAllowance " ) , MaxMemoryAllowanceInMB , GEditorIni ) ;
MaxMemoryAllowance = MaxMemoryAllowanceInMB * 1024LL * 1024LL ;
2014-04-23 18:33:25 -04:00
2014-09-16 12:15:46 -04:00
if ( IsCookByTheBookMode ( ) )
{
CookByTheBookOptions = new FCookByTheBookOptions ( ) ;
}
2014-04-23 18:33:25 -04:00
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
2014-09-16 12:15:46 -04:00
const TArray < ITargetPlatform * > & Platforms = TPM . GetCookingTargetPlatforms ( ) ;
2014-04-23 18:33:25 -04:00
2015-01-22 20:35:27 -05:00
if ( ( ( CookFlags & ECookInitializationFlags : : Iterative ) ! = ECookInitializationFlags : : None ) & &
( ( CookFlags & ECookInitializationFlags : : Unversioned ) ! = ECookInitializationFlags : : None ) )
{
UE_LOG ( LogCook , Warning , TEXT ( " Iterative cooking is unstable when using unversioned cooked content, please disable one of these flags " ) ) ;
}
2014-04-23 18:33:25 -04:00
// always generate the asset registry before starting to cook, for either method
GenerateAssetRegistry ( Platforms ) ;
}
uint32 UCookOnTheFlyServer : : NumConnections ( ) const
{
2014-07-07 15:39:19 -04:00
int Result = 0 ;
for ( int i = 0 ; i < NetworkFileServers . Num ( ) ; + + i )
2014-04-23 18:33:25 -04:00
{
2014-07-07 15:39:19 -04:00
INetworkFileServer * NetworkFileServer = NetworkFileServers [ i ] ;
if ( NetworkFileServer )
{
Result + = NetworkFileServer - > NumConnections ( ) ;
}
2014-04-23 18:33:25 -04:00
}
2014-07-07 15:39:19 -04:00
return Result ;
2014-04-23 18:33:25 -04:00
}
2014-12-10 10:12:47 -05:00
FString UCookOnTheFlyServer : : GetOutputDirectoryOverride ( ) const
2014-04-23 18:33:25 -04:00
{
FString OutputDirectory = OutputDirectoryOverride ;
// Output directory override.
2014-05-29 16:43:14 -04:00
if ( OutputDirectory . Len ( ) < = 0 )
2014-04-23 18:33:25 -04:00
{
2014-12-10 10:12:47 -05:00
if ( IsCookingDLC ( ) )
{
check ( IsCookByTheBookMode ( ) ) ;
OutputDirectory = FPaths : : Combine ( * FPaths : : GamePluginsDir ( ) , * CookByTheBookOptions - > DlcName , TEXT ( " Saved " ) , TEXT ( " Cooked " ) , TEXT ( " [Platform] " ) ) ;
}
else
{
// Full path so that the sandbox wrapper doesn't try to re-base it under Sandboxes
OutputDirectory = FPaths : : Combine ( * FPaths : : GameDir ( ) , TEXT ( " Saved " ) , TEXT ( " Cooked " ) , TEXT ( " [Platform] " ) ) ;
}
2014-05-29 16:43:14 -04:00
OutputDirectory = FPaths : : ConvertRelativePathToFull ( OutputDirectory ) ;
2014-04-23 18:33:25 -04:00
}
else if ( ! OutputDirectory . Contains ( TEXT ( " [Platform] " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromEnd ) )
{
// Output directory needs to contain [Platform] token to be able to cook for multiple targets.
2014-05-29 16:43:14 -04:00
OutputDirectory = FPaths : : Combine ( * OutputDirectory , TEXT ( " [Platform] " ) ) ;
2014-04-23 18:33:25 -04:00
}
FPaths : : NormalizeDirectoryName ( OutputDirectory ) ;
return OutputDirectory ;
}
2014-10-28 11:22:34 -04:00
template < class T >
void GetVersionFormatNumbersForIniVersionStrings ( TArray < FString > & IniVersionStrings , const FString & FormatName , const TArray < T > & FormatArray )
{
for ( const auto & Format : FormatArray )
{
TArray < FName > SupportedFormats ;
Format - > GetSupportedFormats ( SupportedFormats ) ;
for ( const auto & SupportedFormat : SupportedFormats )
{
int32 VersionNumber = Format - > GetVersion ( SupportedFormat ) ;
FString IniVersionString = FString : : Printf ( TEXT ( " %s:%s:VersionNumber%d " ) , * FormatName , * SupportedFormat . ToString ( ) , VersionNumber ) ;
IniVersionStrings . Emplace ( IniVersionString ) ;
}
}
}
bool UCookOnTheFlyServer : : GetCurrentIniVersionStrings ( const ITargetPlatform * TargetPlatform , TArray < FString > & IniVersionStrings ) const
2014-10-22 13:37:17 -04:00
{
// there is a list of important ini settings in the Editor config
TArray < FString > IniVersionedParams ;
GConfig - > GetArray ( TEXT ( " CookSettings " ) , TEXT ( " VersionedIniParams " ) , IniVersionedParams , GEditorIni ) ;
2014-10-28 11:22:34 -04:00
// used to store temporary platform specific ini files
TMap < FString , FConfigFile * > PlatformIniFiles ;
2014-10-22 13:37:17 -04:00
// if the old one doesn't contain all the settings in the new one then we fail this check
for ( const auto & IniVersioned : IniVersionedParams )
{
TArray < FString > IniVersionedArray ;
2015-03-02 15:51:37 -05:00
IniVersioned . ParseIntoArray ( IniVersionedArray , TEXT ( " : " ) , false ) ;
2014-10-22 13:37:17 -04:00
if ( IniVersionedArray . Num ( ) ! = 3 )
{
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Warning , TEXT ( " Invalid entry in CookSettings, VersionedIniParams %s " ) , * IniVersioned ) ;
# endif
2014-10-22 13:37:17 -04:00
return false ;
}
const FString & Filename = IniVersionedArray [ 0 ] ;
const FString & Section = IniVersionedArray [ 1 ] ;
const FString & Key = IniVersionedArray [ 2 ] ;
2014-10-28 11:22:34 -04:00
// const FString& IniFilename = FPaths::GeneratedConfigDir() / TargetPlatform->IniPlatformName() / Filename + TEXT(".ini");
FConfigFile * PlatformIniFile = PlatformIniFiles . FindRef ( Filename ) ;
if ( PlatformIniFile = = NULL )
{
PlatformIniFile = new FConfigFile ( ) ;
FConfigCacheIni : : LoadLocalIniFile ( * PlatformIniFile , * Filename , true , * TargetPlatform - > IniPlatformName ( ) ) ;
PlatformIniFiles . Add ( Filename , PlatformIniFile ) ;
}
2014-10-22 13:37:17 -04:00
// get the value of the entry
FString Value ;
2014-10-28 11:22:34 -04:00
if ( ! PlatformIniFile - > GetString ( * Section , * Key , Value ) )
2014-10-22 13:37:17 -04:00
{
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Warning , TEXT ( " Unable to find entry in CookSettings, VersionedIniParams %s, assume default is being used " ) , * IniVersioned ) ;
# endif
2014-10-22 13:37:17 -04:00
continue ;
}
FString CurrentVersionString = FString : : Printf ( TEXT ( " %s:%s:%s:%s " ) , * Filename , * Section , * Key , * Value ) ;
IniVersionStrings . Emplace ( MoveTemp ( CurrentVersionString ) ) ;
}
2015-05-26 18:02:20 -04:00
TArray < FString > VersionedRValues ;
GConfig - > GetArray ( TEXT ( " CookSettings " ) , TEXT ( " VersionedIntRValues " ) , VersionedRValues , GEditorIni ) ;
for ( const auto & RValue : VersionedRValues )
{
static const auto CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.CompileShadersForDevelopment " ) ) ;
if ( CVar )
{
FString VersionedRValueString = FString : : Printf ( TEXT ( " %s:%d " ) , * RValue , CVar - > GetValueOnGameThread ( ) ) ;
IniVersionStrings . Emplace ( MoveTemp ( VersionedRValueString ) ) ;
}
}
2014-10-28 11:22:34 -04:00
// clean up our temporary platform ini files
for ( const auto & PlatformIniFile : PlatformIniFiles )
{
delete PlatformIniFile . Value ;
}
PlatformIniFiles . Empty ( ) ;
2014-10-22 13:37:17 -04:00
2015-03-17 09:50:32 -04:00
const UTextureLODSettings & LodSettings = TargetPlatform - > GetTextureLODSettings ( ) ;
2014-10-22 13:37:17 -04:00
UEnum * TextureGroupEnum = FindObject < UEnum > ( NULL , TEXT ( " Engine.TextureGroup " ) ) ;
UEnum * TextureMipGenSettingsEnum = FindObject < UEnum > ( NULL , TEXT ( " Engine.TextureMipGenSettings " ) ) ;
for ( int I = 0 ; I < TextureGroup : : TEXTUREGROUP_MAX ; + + I )
{
const TextureMipGenSettings & MipGenSettings = LodSettings . GetTextureMipGenSettings ( ( TextureGroup ) ( I ) ) ;
2014-10-28 11:22:34 -04:00
FString MipGenVersionString = FString : : Printf ( TEXT ( " TextureLODGroupMipGenSettings:%s:%s " ) , * TextureGroupEnum - > GetEnumName ( I ) , * TextureMipGenSettingsEnum - > GetEnumName ( ( int32 ) ( MipGenSettings ) ) ) ;
IniVersionStrings . Emplace ( MoveTemp ( MipGenVersionString ) ) ;
2014-10-22 13:37:17 -04:00
2014-10-28 11:22:34 -04:00
const int32 MinMipCount = LodSettings . GetMinLODMipCount ( ( TextureGroup ) ( I ) ) ;
FString MinMipVersionString = FString : : Printf ( TEXT ( " TextureLODGroupMinMipCount:%s:%d " ) , * TextureGroupEnum - > GetEnumName ( I ) , MinMipCount ) ;
IniVersionStrings . Emplace ( MoveTemp ( MinMipVersionString ) ) ;
2014-10-22 13:37:17 -04:00
2014-10-28 11:22:34 -04:00
const int32 MaxMipCount = LodSettings . GetMaxLODMipCount ( ( TextureGroup ) ( I ) ) ;
FString MaxMipVersionString = FString : : Printf ( TEXT ( " TextureLODGroupMaxMipCount:%s:%d " ) , * TextureGroupEnum - > GetEnumName ( I ) , MaxMipCount ) ;
IniVersionStrings . Emplace ( MoveTemp ( MaxMipVersionString ) ) ;
2014-10-22 13:37:17 -04:00
}
2014-10-28 11:22:34 -04:00
// save off the ddc version numbers also
ITargetPlatformManagerModule * TPM = GetTargetPlatformManager ( ) ;
check ( TPM ) ;
GetVersionFormatNumbersForIniVersionStrings ( IniVersionStrings , TEXT ( " AudioFormat " ) , TPM - > GetAudioFormats ( ) ) ;
GetVersionFormatNumbersForIniVersionStrings ( IniVersionStrings , TEXT ( " TextureFormat " ) , TPM - > GetTextureFormats ( ) ) ;
GetVersionFormatNumbersForIniVersionStrings ( IniVersionStrings , TEXT ( " ShaderFormat " ) , TPM - > GetShaderFormats ( ) ) ;
2014-10-22 13:37:17 -04:00
2015-05-04 16:23:03 -04:00
static const FCustomVersionContainer & CustomVersionContainer = FCustomVersionContainer : : GetRegistered ( ) ;
for ( const auto & CustomVersion : CustomVersionContainer . GetAllVersions ( ) )
{
FString CustomVersionString = FString : : Printf ( TEXT ( " %s:%s:%d " ) , * CustomVersion . FriendlyName , * CustomVersion . Key . ToString ( ) , CustomVersion . Version ) ;
IniVersionStrings . Emplace ( MoveTemp ( CustomVersionString ) ) ;
}
2015-05-06 18:03:19 -04:00
FString UE4Ver = FString : : Printf ( TEXT ( " PackageFileVersions:%d:%d " ) , GPackageFileUE4Version , GPackageFileLicenseeUE4Version ) ;
IniVersionStrings . Emplace ( MoveTemp ( UE4Ver ) ) ;
FString UE4NetVer = FString : : Printf ( TEXT ( " NetFileVersions:%d:%d " ) , GEngineNetVersion , GEngineNegotiationVersion ) ;
IniVersionStrings . Emplace ( MoveTemp ( UE4NetVer ) ) ;
2015-03-16 14:44:28 -04:00
FString MaterialShaderMapDDCVersion = FString : : Printf ( TEXT ( " MaterialShaderMapDDCVersion:%s " ) , * GetMaterialShaderMapDDCKey ( ) ) ;
IniVersionStrings . Emplace ( MoveTemp ( MaterialShaderMapDDCVersion ) ) ;
FString GlobalDDCVersion = FString : : Printf ( TEXT ( " GlobalDDCVersion:%s " ) , * GetGlobalShaderMapDDCKey ( ) ) ;
IniVersionStrings . Emplace ( MoveTemp ( GlobalDDCVersion ) ) ;
2014-10-22 13:37:17 -04:00
return true ;
}
bool UCookOnTheFlyServer : : GetCookedIniVersionStrings ( const ITargetPlatform * TargetPlatform , TArray < FString > & IniVersionStrings ) const
{
const FString EditorIni = FPaths : : GameDir ( ) / TEXT ( " CookedIniVersion.txt " ) ;
2014-12-01 16:53:12 -05:00
const FString SandboxEditorIni = ConvertToFullSandboxPath ( * EditorIni , true ) ;
2014-10-22 13:37:17 -04:00
const FString PlatformSandboxEditorIni = SandboxEditorIni . Replace ( TEXT ( " [Platform] " ) , * TargetPlatform - > PlatformName ( ) ) ;
TArray < FString > SavedIniVersionedParams ;
2014-10-30 10:13:05 -04:00
return GConfig - > GetArray ( TEXT ( " CookSettings " ) , TEXT ( " VersionedIniParams " ) , IniVersionStrings , PlatformSandboxEditorIni ) > 0 ;
2014-10-22 13:37:17 -04:00
}
2014-12-10 10:12:47 -05:00
bool UCookOnTheFlyServer : : CacheIniVersionStringsMap ( const ITargetPlatform * TargetPlatform ) const
2014-10-22 13:37:17 -04:00
{
2014-12-10 10:12:47 -05:00
// check if the cached ones are filled out
const FName TargetPlatformName = FName ( * TargetPlatform - > PlatformName ( ) ) ;
TArray < FString > * FoundCookedIniVersionStrings = CachedIniVersionStringsMap . Find ( TargetPlatformName ) ;
2014-10-22 13:37:17 -04:00
2014-12-10 10:12:47 -05:00
if ( FoundCookedIniVersionStrings = = NULL )
2014-10-22 13:37:17 -04:00
{
2014-12-01 16:53:12 -05:00
TArray < FString > CookedIniVersionStrings ;
2014-12-10 10:12:47 -05:00
if ( GetCookedIniVersionStrings ( TargetPlatform , CookedIniVersionStrings ) )
{
2014-12-01 11:58:48 -05:00
FoundCookedIniVersionStrings = & CachedIniVersionStringsMap . Emplace ( TargetPlatformName , MoveTemp ( CookedIniVersionStrings ) ) ;
2014-10-22 13:37:17 -04:00
}
2014-12-01 16:53:12 -05:00
}
2014-12-10 10:12:47 -05:00
return true ;
2014-12-01 16:53:12 -05:00
}
2014-12-10 10:12:47 -05:00
bool UCookOnTheFlyServer : : IniSettingsOutOfDate ( const ITargetPlatform * TargetPlatform ) const
{
TArray < FString > CurrentIniVersionStrings ;
if ( GetCurrentIniVersionStrings ( TargetPlatform , CurrentIniVersionStrings ) = = false )
{
// previous cook seems half baked... bomb out and recook all the things
return true ;
2014-10-22 13:37:17 -04:00
}
2014-12-10 10:12:47 -05:00
// check if the cached ones are filled out
const FName TargetPlatformName = FName ( * TargetPlatform - > PlatformName ( ) ) ;
TArray < FString > * FoundCookedIniVersionStrings = CachedIniVersionStringsMap . Find ( TargetPlatformName ) ;
if ( FoundCookedIniVersionStrings = = NULL )
{
TArray < FString > CookedIniVersionStrings ;
GetCookedIniVersionStrings ( TargetPlatform , CookedIniVersionStrings ) ;
FoundCookedIniVersionStrings = & CachedIniVersionStringsMap . Emplace ( TargetPlatformName , MoveTemp ( CookedIniVersionStrings ) ) ;
}
check ( FoundCookedIniVersionStrings ) ;
bool bCurrentIniSettingsChanged = false ;
for ( const auto & CurrentVersionString : CurrentIniVersionStrings )
{
if ( FoundCookedIniVersionStrings - > Contains ( CurrentVersionString ) = = false )
{
bCurrentIniSettingsChanged = true ;
break ;
}
}
if ( bCurrentIniSettingsChanged )
{
* FoundCookedIniVersionStrings = CurrentIniVersionStrings ;
}
return bCurrentIniSettingsChanged ;
}
bool UCookOnTheFlyServer : : SaveCurrentIniSettings ( const ITargetPlatform * TargetPlatform ) const
{
2015-06-16 12:43:26 -04:00
check ( IsChildCooker ( ) = = false ) ;
2014-12-10 10:12:47 -05:00
const FString CookedIni = FPaths : : GameDir ( ) / TEXT ( " CookedIniVersion.txt " ) ;
const FString SandboxCookedIni = ConvertToFullSandboxPath ( CookedIni , true ) ;
const FName TargetPlatformName = FName ( * TargetPlatform - > PlatformName ( ) ) ;
TArray < FString > * FoundCookedIniVersionStrings = CachedIniVersionStringsMap . Find ( TargetPlatformName ) ;
// need to call IniSettingsOutOfDate before calling this function
check ( FoundCookedIniVersionStrings ) ;
// save the iniversion strings
const FString PlatformSandboxCookedIni = SandboxCookedIni . Replace ( TEXT ( " [Platform] " ) , * TargetPlatform - > PlatformName ( ) ) ;
GConfig - > SetArray ( TEXT ( " CookSettings " ) , TEXT ( " VersionedIniParams " ) , * FoundCookedIniVersionStrings , PlatformSandboxCookedIni ) ;
GConfig - > Flush ( false , PlatformSandboxCookedIni ) ;
2014-10-22 13:37:17 -04:00
return true ;
}
2014-12-12 12:59:47 -05:00
void UCookOnTheFlyServer : : PopulateCookedPackagesFromDisk ( const TArray < ITargetPlatform * > & Platforms )
2014-04-23 18:33:25 -04:00
{
2015-06-16 12:43:26 -04:00
check ( IsChildCooker ( ) = = false ) ;
2014-12-12 12:59:47 -05:00
// check each package to see if it's out of date
FPackageDependencyInfoModule & PDInfoModule = FModuleManager : : LoadModuleChecked < FPackageDependencyInfoModule > ( " PackageDependencyInfo " ) ;
// list of directories to skip
TArray < FString > DirectoriesToSkip ;
TArray < FString > DirectoriesToNotRecurse ;
// See what files are out of date in the sandbox folder
for ( int32 Index = 0 ; Index < Platforms . Num ( ) ; Index + + )
{
ITargetPlatform * Target = Platforms [ Index ] ;
2015-05-11 16:41:12 -04:00
FString SandboxPath = GetSandboxDirectory ( Target - > PlatformName ( ) ) ;
2014-12-12 12:59:47 -05:00
FName PlatformFName ( * Target - > PlatformName ( ) ) ;
2015-05-11 16:41:12 -04:00
FString EngineSandboxPath = SandboxFile - > ConvertToSandboxPath ( * FPaths : : EngineDir ( ) ) + TEXT ( " / " ) ;
EngineSandboxPath . ReplaceInline ( TEXT ( " [Platform] " ) , * Target - > PlatformName ( ) ) ;
FString GameSandboxPath = SandboxFile - > ConvertToSandboxPath ( * ( FPaths : : GameDir ( ) + TEXT ( " a.txt " ) ) ) ;
GameSandboxPath . ReplaceInline ( TEXT ( " a.txt " ) , TEXT ( " " ) ) ;
GameSandboxPath . ReplaceInline ( TEXT ( " [Platform] " ) , * Target - > PlatformName ( ) ) ;
FString LocalGamePath = FPaths : : GameDir ( ) ;
if ( FPaths : : IsProjectFilePathSet ( ) )
{
LocalGamePath = FPaths : : GetPath ( FPaths : : GetProjectFilePath ( ) ) + TEXT ( " / " ) ;
}
FString LocalEnginePath = FPaths : : EngineDir ( ) ;
2014-12-12 12:59:47 -05:00
// use the timestamp grabbing visitor
IPlatformFile & PlatformFile = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
FLocalTimestampDirectoryVisitor Visitor ( PlatformFile , DirectoriesToSkip , DirectoriesToNotRecurse , false ) ;
2015-05-11 16:41:12 -04:00
PlatformFile . IterateDirectory ( * SandboxPath , Visitor ) ;
/*FString SandboxEngine = Sandbox->ConvertToSandboxPath(*LocalEngineDir) + TEXT("/");
// we need to add an extra bit to the game path to make the sandbox convert it correctly (investigate?)
// @todo: double check this
FString SandboxGame = Sandbox - > ConvertToSandboxPath ( * ( LocalGameDir + TEXT ( " a.txt " ) ) ) . Replace ( TEXT ( " a.txt " ) , TEXT ( " " ) ) ; */
2014-12-12 12:59:47 -05:00
for ( TMap < FString , FDateTime > : : TIterator TimestampIt ( Visitor . FileTimes ) ; TimestampIt ; + + TimestampIt )
{
FString CookedFilename = TimestampIt . Key ( ) ;
2015-05-11 16:41:12 -04:00
if ( ( CookedFilename . EndsWith ( TEXT ( " .uasset " ) ) = = false ) & &
( CookedFilename . EndsWith ( TEXT ( " .umap " ) ) = = false ) )
{
// don't care if it's not a map or an asset
continue ;
}
2014-12-12 12:59:47 -05:00
FDateTime CookedTimestamp = TimestampIt . Value ( ) ;
2015-03-02 10:16:16 -05:00
CookedFilename = FPaths : : ConvertRelativePathToFull ( CookedFilename ) ;
2015-05-11 16:41:12 -04:00
FString StandardCookedFilename = CookedFilename ;
StandardCookedFilename . ReplaceInline ( * SandboxPath , * ( FPaths : : GetRelativePathToRoot ( ) ) ) ;
2014-12-12 12:59:47 -05:00
2015-05-26 18:02:20 -04:00
StandardCookedFilename = FPaths : : ConvertRelativePathToFull ( StandardCookedFilename ) ;
FPaths : : MakeStandardFilename ( StandardCookedFilename ) ;
FDateTime DependentTimestamp ;
2014-12-12 12:59:47 -05:00
if ( PDInfoModule . DeterminePackageDependentTimeStamp ( * ( FPaths : : GetBaseFilename ( StandardCookedFilename , false ) ) , DependentTimestamp ) = = true )
{
double Diff = ( CookedTimestamp - DependentTimestamp ) . GetTotalSeconds ( ) ;
if ( Diff > = 0.0 )
{
CookedPackages . Add ( FFilePlatformRequest ( FName ( * StandardCookedFilename ) , PlatformFName ) ) ;
}
}
}
}
}
void UCookOnTheFlyServer : : CleanSandbox ( const bool bIterative )
{
2015-06-16 12:43:26 -04:00
//child cookers shouldn't clean sandbox we would be deleting the master cookers / other cookers data
check ( IsChildCooker ( ) = = false ) ;
2014-12-12 12:59:47 -05:00
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
const TArray < ITargetPlatform * > & Platforms = TPM . GetCookingTargetPlatforms ( ) ;
2014-12-10 10:12:47 -05:00
// before we can delete any cooked files we need to make sure that we have finished writing them
UPackage : : WaitForAsyncFileWrites ( ) ;
# if OUTPUT_TIMING
2014-04-23 18:33:25 -04:00
double SandboxCleanTime = 0.0 ;
2014-12-10 10:12:47 -05:00
# endif
2014-04-23 18:33:25 -04:00
{
2014-12-10 10:12:47 -05:00
# if OUTPUT_TIMING
2014-04-23 18:33:25 -04:00
SCOPE_SECONDS_COUNTER ( SandboxCleanTime ) ;
2014-12-10 10:12:47 -05:00
# endif
for ( const auto & Platform : Platforms )
{
CacheIniVersionStringsMap ( Platform ) ;
}
2014-12-12 12:59:47 -05:00
if ( bIterative = = false )
2014-04-23 18:33:25 -04:00
{
// for now we are going to wipe the cooked directory
for ( int32 Index = 0 ; Index < Platforms . Num ( ) ; Index + + )
{
ITargetPlatform * Target = Platforms [ Index ] ;
2014-12-10 10:12:47 -05:00
FString SandboxDirectory = GetSandboxDirectory ( Target - > PlatformName ( ) ) ; // GetOutputDirectory(Target->PlatformName());
2014-04-23 18:33:25 -04:00
IFileManager : : Get ( ) . DeleteDirectory ( * SandboxDirectory , false , true ) ;
2014-12-10 10:12:47 -05:00
ClearPlatformCookedData ( FName ( * Target - > PlatformName ( ) ) ) ;
IniSettingsOutOfDate ( Target ) ;
SaveCurrentIniSettings ( Target ) ;
2014-04-23 18:33:25 -04:00
}
2014-12-10 10:12:47 -05:00
2014-04-23 18:33:25 -04:00
}
else
{
2014-12-10 10:12:47 -05:00
for ( const auto & Target : Platforms )
2014-10-22 13:37:17 -04:00
{
2014-12-10 10:12:47 -05:00
if ( IniSettingsOutOfDate ( Target ) )
{
ClearPlatformCookedData ( FName ( * Target - > PlatformName ( ) ) ) ;
FString SandboxDirectory = GetSandboxDirectory ( Target - > PlatformName ( ) ) ;
IFileManager : : Get ( ) . DeleteDirectory ( * SandboxDirectory , false , true ) ;
SaveCurrentIniSettings ( Target ) ;
}
2014-10-22 13:37:17 -04:00
}
2014-10-10 10:31:37 -04:00
2014-10-22 13:37:17 -04:00
// check each package to see if it's out of date
FPackageDependencyInfoModule & PDInfoModule = FModuleManager : : LoadModuleChecked < FPackageDependencyInfoModule > ( " PackageDependencyInfo " ) ;
2014-04-23 18:33:25 -04:00
// list of directories to skip
TArray < FString > DirectoriesToSkip ;
TArray < FString > DirectoriesToNotRecurse ;
2015-04-24 15:36:57 -04:00
PackagesKeptFromPreviousCook . Empty ( ) ;
2014-04-23 18:33:25 -04:00
// See what files are out of date in the sandbox folder
for ( int32 Index = 0 ; Index < Platforms . Num ( ) ; Index + + )
{
ITargetPlatform * Target = Platforms [ Index ] ;
2015-05-11 16:41:12 -04:00
FString EngineSandboxPath = SandboxFile - > ConvertToSandboxPath ( * FPaths : : EngineDir ( ) ) + TEXT ( " / " ) ;
EngineSandboxPath . ReplaceInline ( TEXT ( " [Platform] " ) , * Target - > PlatformName ( ) ) ;
FString GameSandboxPath = SandboxFile - > ConvertToSandboxPath ( * ( FPaths : : GameDir ( ) + TEXT ( " a.txt " ) ) ) ;
GameSandboxPath . ReplaceInline ( TEXT ( " a.txt " ) , TEXT ( " " ) ) ;
GameSandboxPath . ReplaceInline ( TEXT ( " [Platform] " ) , * Target - > PlatformName ( ) ) ;
FString LocalGamePath = FPaths : : GameDir ( ) ;
if ( FPaths : : IsProjectFilePathSet ( ) )
{
LocalGamePath = FPaths : : GetPath ( FPaths : : GetProjectFilePath ( ) ) + TEXT ( " / " ) ;
}
FString LocalEnginePath = FPaths : : EngineDir ( ) ;
2014-12-10 10:12:47 -05:00
FName PlatformFName ( * Target - > PlatformName ( ) ) ;
2014-04-23 18:33:25 -04:00
// use the timestamp grabbing visitor
IPlatformFile & PlatformFile = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
FLocalTimestampDirectoryVisitor Visitor ( PlatformFile , DirectoriesToSkip , DirectoriesToNotRecurse , false ) ;
2014-10-22 13:37:17 -04:00
2015-05-11 16:41:12 -04:00
FString SandboxPath = GetSandboxDirectory ( Target - > PlatformName ( ) ) ;
PlatformFile . IterateDirectory ( * SandboxPath , Visitor ) ;
2014-04-23 18:33:25 -04:00
for ( TMap < FString , FDateTime > : : TIterator TimestampIt ( Visitor . FileTimes ) ; TimestampIt ; + + TimestampIt )
{
FString CookedFilename = TimestampIt . Key ( ) ;
2015-05-11 16:41:12 -04:00
if ( ( CookedFilename . EndsWith ( TEXT ( " .uasset " ) ) = = false ) & &
( CookedFilename . EndsWith ( TEXT ( " .umap " ) ) = = false ) )
{
// don't care if it's not a map or an asset
2015-05-26 18:02:20 -04:00
//IFileManager::Get().Delete(*CookedFilename);
2015-05-11 16:41:12 -04:00
continue ;
}
2014-04-23 18:33:25 -04:00
FDateTime CookedTimestamp = TimestampIt . Value ( ) ;
2015-05-11 16:41:12 -04:00
CookedFilename = FPaths : : ConvertRelativePathToFull ( CookedFilename ) ;
FString StandardCookedFilename = CookedFilename ;
StandardCookedFilename . ReplaceInline ( * SandboxPath , * ( FPaths : : GetRelativePathToRoot ( ) ) ) ;
2015-05-26 18:02:20 -04:00
StandardCookedFilename = FPaths : : ConvertRelativePathToFull ( StandardCookedFilename ) ;
FPaths : : MakeStandardFilename ( StandardCookedFilename ) ;
2014-04-23 18:33:25 -04:00
FDateTime DependentTimestamp ;
2015-04-24 15:36:57 -04:00
FName StandardCookedFileFName = FName ( * StandardCookedFilename ) ;
2014-04-23 18:33:25 -04:00
2015-05-22 08:15:51 -04:00
bool bShouldKeep = true ;
2014-04-23 18:33:25 -04:00
if ( PDInfoModule . DeterminePackageDependentTimeStamp ( * ( FPaths : : GetBaseFilename ( StandardCookedFilename , false ) ) , DependentTimestamp ) = = true )
{
double Diff = ( CookedTimestamp - DependentTimestamp ) . GetTotalSeconds ( ) ;
if ( Diff < 0.0 )
{
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Deleting out of date cooked file: %s " ) , * CookedFilename ) ;
# endif
2014-04-23 18:33:25 -04:00
IFileManager : : Get ( ) . Delete ( * CookedFilename ) ;
2014-12-10 10:12:47 -05:00
2015-04-24 15:36:57 -04:00
CookedPackages . RemoveFileForPlatform ( StandardCookedFileFName , PlatformFName ) ;
2015-05-22 08:15:51 -04:00
bShouldKeep = false ;
}
}
if ( bShouldKeep )
{
FString LongPackageName ;
FString FailureReason ;
if ( FPackageName : : TryConvertFilenameToLongPackageName ( StandardCookedFilename , LongPackageName , & FailureReason ) )
{
const FName LongPackageFName ( * LongPackageName ) ;
PackagesKeptFromPreviousCook . Add ( LongPackageFName ) ;
2014-04-23 18:33:25 -04:00
}
2015-04-24 15:36:57 -04:00
else
{
2015-05-22 08:15:51 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Unable to generate long package name for %s because %s " ) , * StandardCookedFilename , * FailureReason ) , EMessageSeverity : : Warning ) ;
UE_LOG ( LogCook , Warning , TEXT ( " Unable to generate long package name for %s because %s " ) , * StandardCookedFilename , * FailureReason ) ;
2015-04-24 15:36:57 -04:00
}
}
2014-04-23 18:33:25 -04:00
}
}
// Collect garbage to ensure we don't have any packages hanging around from dependent time stamp determination
2015-06-16 18:42:56 -04:00
CollectGarbage ( GARBAGE_COLLECTION_KEEPFLAGS ) ;
2014-04-23 18:33:25 -04:00
}
}
2014-12-10 10:12:47 -05:00
# if OUTPUT_TIMING
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Sandbox cleanup took %5.3f seconds " ) , SandboxCleanTime ) ;
# endif
2014-04-23 18:33:25 -04:00
}
void UCookOnTheFlyServer : : GenerateAssetRegistry ( const TArray < ITargetPlatform * > & Platforms )
{
2015-06-16 12:43:26 -04:00
if ( IsChildCooker ( ) )
{
// don't generate the asset registry
return ;
}
2015-05-18 12:51:46 -04:00
if ( IsCookingInEditor ( ) = = false )
{
// we want to register the temporary save directory if we are cooking outside the editor.
// If we are cooking inside the editor we never use this directory so don't worry about registring it
FPackageName : : RegisterMountPoint ( TEXT ( " /TempAutosave/ " ) , FPaths : : GameSavedDir ( ) / GEngine - > PlayOnConsoleSaveDir ) ;
}
2015-05-15 14:34:41 -04:00
2014-04-23 18:33:25 -04:00
// load the interface
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
double GenerateAssetRegistryTime = 0.0 ;
{
SCOPE_SECONDS_COUNTER ( GenerateAssetRegistryTime ) ;
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Creating asset registry [is editor: %d] " ) , GIsEditor ) ;
# endif
2014-04-23 18:33:25 -04:00
// Perform a synchronous search of any .ini based asset paths (note that the per-game delegate may
// have already scanned paths on its own)
// We want the registry to be fully initialized when generating streaming manifests too.
2014-11-10 11:39:19 -05:00
bool bEditor = IsRealtimeMode ( ) ;
2015-05-18 12:51:46 -04:00
// editor will scan asset registry automagically
2014-11-10 11:39:19 -05:00
if ( ! bEditor )
2014-04-23 18:33:25 -04:00
{
2014-11-10 11:39:19 -05:00
TArray < FString > ScanPaths ;
if ( GConfig - > GetArray ( TEXT ( " AssetRegistry " ) , TEXT ( " PathsToScanForCook " ) , ScanPaths , GEngineIni ) > 0 )
2014-11-07 13:17:07 -05:00
{
AssetRegistry . ScanPathsSynchronous ( ScanPaths ) ;
}
else
{
2014-11-10 11:39:19 -05:00
AssetRegistry . SearchAllAssets ( true ) ;
2014-11-07 13:17:07 -05:00
}
2014-04-23 18:33:25 -04:00
}
}
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Done creating registry. It took %5.2fs. " ) , GenerateAssetRegistryTime ) ;
2014-04-23 18:33:25 -04:00
}
2015-04-24 15:36:57 -04:00
void UCookOnTheFlyServer : : GenerateLongPackageNames ( TArray < FName > & FilesInPath )
2014-04-23 18:33:25 -04:00
{
2015-04-13 16:14:12 -04:00
#if 0
2014-04-23 18:33:25 -04:00
TArray < FString > FilesInPathReverse ;
FilesInPathReverse . Reserve ( FilesInPath . Num ( ) ) ;
for ( int32 FileIndex = 0 ; FileIndex < FilesInPath . Num ( ) ; FileIndex + + )
{
const FString & FileInPath = FilesInPath [ FilesInPath . Num ( ) - FileIndex - 1 ] ;
if ( FPackageName : : IsValidLongPackageName ( FileInPath ) )
{
FilesInPathReverse . AddUnique ( FileInPath ) ;
}
else
{
FString LongPackageName ;
if ( FPackageName : : TryConvertFilenameToLongPackageName ( FileInPath , LongPackageName ) )
{
FilesInPathReverse . AddUnique ( LongPackageName ) ;
}
else
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Unable to generate long package name for %s " ) , * FileInPath ) , EMessageSeverity : : Warning ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " Unable to generate long package name for %s " ) , * FileInPath ) ;
2014-04-23 18:33:25 -04:00
}
}
}
Exchange ( FilesInPathReverse , FilesInPath ) ;
2015-04-13 16:14:12 -04:00
# else
TArray < FName > FilesInPathReverse ;
FilesInPathReverse . Reserve ( FilesInPath . Num ( ) ) ;
for ( int32 FileIndex = 0 ; FileIndex < FilesInPath . Num ( ) ; FileIndex + + )
{
2015-04-24 15:36:57 -04:00
const FString & FileInPath = FilesInPath [ FilesInPath . Num ( ) - FileIndex - 1 ] . ToString ( ) ;
2015-04-13 16:14:12 -04:00
if ( FPackageName : : IsValidLongPackageName ( FileInPath ) )
{
const FName FileInPathFName ( * FileInPath ) ;
FilesInPathReverse . AddUnique ( FileInPathFName ) ;
}
else
{
FString LongPackageName ;
2015-04-27 14:10:18 -04:00
FString FailureReason ;
if ( FPackageName : : TryConvertFilenameToLongPackageName ( FileInPath , LongPackageName , & FailureReason ) )
2015-04-13 16:14:12 -04:00
{
const FName LongPackageFName ( * LongPackageName ) ;
FilesInPathReverse . AddUnique ( LongPackageFName ) ;
}
else
{
2015-04-27 14:10:18 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Unable to generate long package name for %s because %s " ) , * FileInPath , * FailureReason ) , EMessageSeverity : : Warning ) ;
UE_LOG ( LogCook , Warning , TEXT ( " Unable to generate long package name for %s because %s " ) , * FileInPath , * FailureReason ) ;
2015-04-13 16:14:12 -04:00
}
}
}
// Exchange(FilesInPathReverse, FilesInPath);
2015-04-24 15:36:57 -04:00
FilesInPath . Empty ( FilesInPathReverse . Num ( ) ) ;
2015-04-13 16:14:12 -04:00
for ( const auto & Files : FilesInPathReverse )
{
2015-04-24 15:36:57 -04:00
FilesInPath . Add ( Files ) ;
2015-04-13 16:14:12 -04:00
}
# endif
2014-04-23 18:33:25 -04:00
}
2015-04-24 15:36:57 -04:00
void UCookOnTheFlyServer : : AddFileToCook ( TArray < FName > & InOutFilesToCook , const FString & InFilename ) const
2014-10-22 13:37:17 -04:00
{
if ( ! FPackageName : : IsScriptPackage ( InFilename ) )
{
2015-03-06 15:15:01 -05:00
#if 0 // randomize cook file order, don't check in enabled...
2015-03-06 13:31:19 -05:00
if ( ! InOutFilesToCook . Contains ( InFilename ) )
2015-02-13 15:34:55 -05:00
{
int Index = FMath : : RandRange ( 0 , InOutFilesToCook . Num ( ) - 1 ) ;
InOutFilesToCook . Insert ( InFilename , Index ) ;
2015-03-06 13:31:19 -05:00
}
# else
2015-04-24 15:36:57 -04:00
InOutFilesToCook . AddUnique ( FName ( * InFilename ) ) ;
2015-03-06 13:31:19 -05:00
# endif
2014-10-22 13:37:17 -04:00
}
}
2015-06-29 11:44:58 -04:00
void UCookOnTheFlyServer : : CollectFilesToCook ( TArray < FName > & FilesInPath , const TArray < FString > & CookMaps , const TArray < FString > & InCookDirectories , const TArray < FString > & CookCultures , const TArray < FString > & IniMapSections , bool bCookAll , bool bMapsOnly , bool bNoDev )
2014-09-16 12:15:46 -04:00
{
2015-06-16 12:43:26 -04:00
if ( CookByTheBookOptions - > bIsChildCooker )
{
2015-06-29 11:44:58 -04:00
const FString ChildCookFilename = CookByTheBookOptions - > ChildCookFilename ;
2015-06-16 12:43:26 -04:00
check ( ChildCookFilename . Len ( ) ) ;
FString ChildCookString ;
ensure ( FFileHelper : : LoadFileToString ( ChildCookString , * ChildCookFilename ) ) ;
2014-12-10 15:23:55 -05:00
2015-06-16 12:43:26 -04:00
TArray < FString > ChildCookArray ;
ChildCookString . ParseIntoArrayLines ( ChildCookArray ) ;
for ( const FString & ChildFile : ChildCookArray )
{
AddFileToCook ( FilesInPath , ChildFile ) ;
}
// if we are a child cooker then just add the files for the child cooker and early out
return ;
}
TArray < FString > CookDirectories = InCookDirectories ;
2014-12-10 15:23:55 -05:00
2015-04-27 14:10:18 -04:00
if ( ! IsCookingDLC ( ) )
2014-12-12 12:59:47 -05:00
{
2015-04-27 14:10:18 -04:00
TArray < FString > MapList ;
// Add the default map section
GEditor - > LoadMapListFromIni ( TEXT ( " AlwaysCookMaps " ) , MapList ) ;
2014-12-12 12:59:47 -05:00
2015-04-27 14:10:18 -04:00
for ( const auto & IniMapSection : IniMapSections )
2014-09-16 12:15:46 -04:00
{
2015-04-27 14:10:18 -04:00
GEditor - > LoadMapListFromIni ( * IniMapSection , MapList ) ;
}
for ( int32 MapIdx = 0 ; MapIdx < MapList . Num ( ) ; MapIdx + + )
{
AddFileToCook ( FilesInPath , MapList [ MapIdx ] ) ;
}
// Also append any cookdirs from the project ini files; these dirs are relative to the game content directory
{
const FString AbsoluteGameContentDir = FPaths : : ConvertRelativePathToFull ( FPaths : : GameContentDir ( ) ) ;
const UProjectPackagingSettings * const PackagingSettings = GetDefault < UProjectPackagingSettings > ( ) ;
for ( const auto & DirToCook : PackagingSettings - > DirectoriesToAlwaysCook )
{
CookDirectories . Add ( AbsoluteGameContentDir / DirToCook . Path ) ;
}
2014-09-16 12:15:46 -04:00
}
}
2015-04-27 14:10:18 -04:00
2014-09-16 12:15:46 -04:00
for ( const auto & CurrEntry : CookMaps )
{
if ( FPackageName : : IsShortPackageName ( CurrEntry ) )
{
FString OutFilename ;
if ( FPackageName : : SearchForPackageOnDisk ( CurrEntry , NULL , & OutFilename ) = = false )
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Unable to find package for map %s. " ) , * CurrEntry ) , EMessageSeverity : : Warning ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " Unable to find package for map %s. " ) , * CurrEntry ) ;
2014-09-16 12:15:46 -04:00
}
else
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , OutFilename ) ;
2014-09-16 12:15:46 -04:00
}
}
else
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , CurrEntry ) ;
2014-09-16 12:15:46 -04:00
}
}
const FString ExternalMountPointName ( TEXT ( " /Game/ " ) ) ;
for ( const auto & CurrEntry : CookDirectories )
{
TArray < FString > Files ;
IFileManager : : Get ( ) . FindFilesRecursive ( Files , * CurrEntry , * ( FString ( TEXT ( " * " ) ) + FPackageName : : GetAssetPackageExtension ( ) ) , true , false ) ;
for ( int32 Index = 0 ; Index < Files . Num ( ) ; Index + + )
{
FString StdFile = Files [ Index ] ;
FPaths : : MakeStandardFilename ( StdFile ) ;
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , StdFile ) ;
2014-09-16 12:15:46 -04:00
// this asset may not be in our currently mounted content directories, so try to mount a new one now
FString LongPackageName ;
if ( ! FPackageName : : IsValidLongPackageName ( StdFile ) & & ! FPackageName : : TryConvertFilenameToLongPackageName ( StdFile , LongPackageName ) )
{
FPackageName : : RegisterMountPoint ( ExternalMountPointName , CurrEntry ) ;
}
}
}
2014-12-01 16:53:12 -05:00
if ( IsCookingDLC ( ) )
{
// get the dlc and make sure we cook that directory
2015-04-13 16:14:12 -04:00
FString DLCPath = FPaths : : GamePluginsDir ( ) / CookByTheBookOptions - > DlcName / FString ( TEXT ( " Content " ) ) ;
2014-12-01 16:53:12 -05:00
TArray < FString > Files ;
IFileManager : : Get ( ) . FindFilesRecursive ( Files , * DLCPath , * ( FString ( TEXT ( " * " ) ) + FPackageName : : GetAssetPackageExtension ( ) ) , true , false ) ;
IFileManager : : Get ( ) . FindFilesRecursive ( Files , * DLCPath , * ( FString ( TEXT ( " * " ) ) + FPackageName : : GetMapPackageExtension ( ) ) , true , false ) ;
for ( int32 Index = 0 ; Index < Files . Num ( ) ; Index + + )
{
FString StdFile = Files [ Index ] ;
FPaths : : MakeStandardFilename ( StdFile ) ;
AddFileToCook ( FilesInPath , StdFile ) ;
// this asset may not be in our currently mounted content directories, so try to mount a new one now
FString LongPackageName ;
if ( ! FPackageName : : IsValidLongPackageName ( StdFile ) & & ! FPackageName : : TryConvertFilenameToLongPackageName ( StdFile , LongPackageName ) )
{
FPackageName : : RegisterMountPoint ( ExternalMountPointName , DLCPath ) ;
}
}
}
2014-09-16 12:15:46 -04:00
if ( ( FilesInPath . Num ( ) = = 0 ) | | bCookAll )
{
TArray < FString > Tokens ;
Tokens . Empty ( 2 ) ;
Tokens . Add ( FString ( " * " ) + FPackageName : : GetAssetPackageExtension ( ) ) ;
Tokens . Add ( FString ( " * " ) + FPackageName : : GetMapPackageExtension ( ) ) ;
uint8 PackageFilter = NORMALIZE_DefaultFlags | NORMALIZE_ExcludeEnginePackages ;
if ( bMapsOnly )
{
PackageFilter | = NORMALIZE_ExcludeContentPackages ;
}
if ( bNoDev )
{
PackageFilter | = NORMALIZE_ExcludeDeveloperPackages ;
}
// assume the first token is the map wildcard/pathname
TArray < FString > Unused ;
for ( int32 TokenIndex = 0 ; TokenIndex < Tokens . Num ( ) ; TokenIndex + + )
{
TArray < FString > TokenFiles ;
if ( ! NormalizePackageNames ( Unused , TokenFiles , Tokens [ TokenIndex ] , PackageFilter ) )
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " No packages found for parameter %i: '%s' " ) , TokenIndex , * Tokens [ TokenIndex ] ) ;
2014-09-16 12:15:46 -04:00
continue ;
}
for ( int32 TokenFileIndex = 0 ; TokenFileIndex < TokenFiles . Num ( ) ; + + TokenFileIndex )
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , TokenFiles [ TokenFileIndex ] ) ;
2014-09-16 12:15:46 -04:00
}
}
}
// make sure we cook the default maps
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
static const TArray < ITargetPlatform * > & Platforms = TPM . GetTargetPlatforms ( ) ;
for ( int32 Index = 0 ; Index < Platforms . Num ( ) ; Index + + )
{
// load the platform specific ini to get its DefaultMap
FConfigFile PlatformEngineIni ;
FConfigCacheIni : : LoadLocalIniFile ( PlatformEngineIni , TEXT ( " Engine " ) , true , * Platforms [ Index ] - > IniPlatformName ( ) ) ;
// get the server and game default maps and cook them
FString Obj ;
if ( PlatformEngineIni . GetString ( TEXT ( " /Script/EngineSettings.GameMapsSettings " ) , TEXT ( " GameDefaultMap " ) , Obj ) )
{
if ( Obj ! = FName ( NAME_None ) . ToString ( ) )
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , Obj ) ;
2014-09-16 12:15:46 -04:00
}
}
if ( IsCookFlagSet ( ECookInitializationFlags : : IncludeServerMaps ) )
{
if ( PlatformEngineIni . GetString ( TEXT ( " /Script/EngineSettings.GameMapsSettings " ) , TEXT ( " ServerDefaultMap " ) , Obj ) )
{
if ( Obj ! = FName ( NAME_None ) . ToString ( ) )
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , Obj ) ;
2014-09-16 12:15:46 -04:00
}
}
}
if ( PlatformEngineIni . GetString ( TEXT ( " /Script/EngineSettings.GameMapsSettings " ) , TEXT ( " GlobalDefaultGameMode " ) , Obj ) )
{
if ( Obj ! = FName ( NAME_None ) . ToString ( ) )
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , Obj ) ;
2014-09-16 12:15:46 -04:00
}
}
if ( PlatformEngineIni . GetString ( TEXT ( " /Script/EngineSettings.GameMapsSettings " ) , TEXT ( " GlobalDefaultServerGameMode " ) , Obj ) )
{
if ( Obj ! = FName ( NAME_None ) . ToString ( ) )
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , Obj ) ;
2014-09-16 12:15:46 -04:00
}
2015-01-07 12:12:42 -05:00
}
if ( PlatformEngineIni . GetString ( TEXT ( " /Script/EngineSettings.GameMapsSettings " ) , TEXT ( " GameInstanceClass " ) , Obj ) )
{
if ( Obj ! = FName ( NAME_None ) . ToString ( ) )
{
AddFileToCook ( FilesInPath , Obj ) ;
}
2014-09-16 12:15:46 -04:00
}
}
// make sure we cook any extra assets for the default touch interface
// @todo need a better approach to cooking assets which are dynamically loaded by engine code based on settings
FConfigFile InputIni ;
FString InterfaceFile ;
FConfigCacheIni : : LoadLocalIniFile ( InputIni , TEXT ( " Input " ) , true ) ;
if ( InputIni . GetString ( TEXT ( " /Script/Engine.InputSettings " ) , TEXT ( " DefaultTouchInterface " ) , InterfaceFile ) )
{
if ( InterfaceFile ! = TEXT ( " None " ) & & InterfaceFile ! = TEXT ( " " ) )
{
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , InterfaceFile ) ;
2014-09-16 12:15:46 -04:00
}
}
//@todo SLATE: This is a hack to ensure all slate referenced assets get cooked.
// Slate needs to be refactored to properly identify required assets at cook time.
// Simply jamming everything in a given directory into the cook list is error-prone
// on many levels - assets not required getting cooked/shipped; assets not put under
// the correct folder; etc.
{
TArray < FString > UIContentPaths ;
2015-04-02 14:54:19 -04:00
TSet < FName > ContentDirectoryAssets ;
2014-09-16 12:15:46 -04:00
if ( GConfig - > GetArray ( TEXT ( " UI " ) , TEXT ( " ContentDirectories " ) , UIContentPaths , GEditorIni ) > 0 )
{
for ( int32 DirIdx = 0 ; DirIdx < UIContentPaths . Num ( ) ; DirIdx + + )
{
FString ContentPath = FPackageName : : LongPackageNameToFilename ( UIContentPaths [ DirIdx ] ) ;
TArray < FString > Files ;
IFileManager : : Get ( ) . FindFilesRecursive ( Files , * ContentPath , * ( FString ( TEXT ( " * " ) ) + FPackageName : : GetAssetPackageExtension ( ) ) , true , false ) ;
for ( int32 Index = 0 ; Index < Files . Num ( ) ; Index + + )
{
FString StdFile = Files [ Index ] ;
2015-04-02 14:54:19 -04:00
FName PackageName = FName ( * FPackageName : : FilenameToLongPackageName ( StdFile ) ) ;
ContentDirectoryAssets . Add ( PackageName ) ;
2014-09-16 12:15:46 -04:00
FPaths : : MakeStandardFilename ( StdFile ) ;
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , StdFile ) ;
2014-09-16 12:15:46 -04:00
}
}
}
2015-04-02 14:54:19 -04:00
2015-04-20 15:19:16 -04:00
if ( CookByTheBookOptions & & CookByTheBookOptions - > bGenerateDependenciesForMaps )
{
2015-06-23 11:24:52 -04:00
for ( auto & MapDependencyGraph : CookByTheBookOptions - > MapDependencyGraphs )
{
MapDependencyGraph . Value . Add ( FName ( TEXT ( " ContentDirectoryAssets " ) ) , ContentDirectoryAssets ) ;
}
2015-04-20 15:19:16 -04:00
}
2014-09-16 12:15:46 -04:00
}
}
bool UCookOnTheFlyServer : : IsCookByTheBookRunning ( ) const
{
return CookByTheBookOptions & & CookByTheBookOptions - > bRunning ;
}
void UCookOnTheFlyServer : : SaveGlobalShaderMapFiles ( const TArray < ITargetPlatform * > & Platforms )
{
2014-12-10 10:12:47 -05:00
// we don't support this behavior
check ( ! IsCookingDLC ( ) ) ;
2014-09-16 12:15:46 -04:00
for ( int32 Index = 0 ; Index < Platforms . Num ( ) ; Index + + )
{
// make sure global shaders are up to date!
TArray < FString > Files ;
FShaderRecompileData RecompileData ;
RecompileData . PlatformName = Platforms [ Index ] - > PlatformName ( ) ;
// Compile for all platforms
RecompileData . ShaderPlatform = - 1 ;
RecompileData . ModifiedFiles = & Files ;
RecompileData . MeshMaterialMaps = NULL ;
check ( IsInGameThread ( ) ) ;
2014-12-10 10:12:47 -05:00
FString OutputDir = GetSandboxDirectory ( RecompileData . PlatformName ) ;
2014-09-16 12:15:46 -04:00
RecompileShadersForRemote
( RecompileData . PlatformName ,
RecompileData . ShaderPlatform = = - 1 ? SP_NumPlatforms : ( EShaderPlatform ) RecompileData . ShaderPlatform ,
OutputDir ,
RecompileData . MaterialsToLoad ,
RecompileData . SerializedShaderResources ,
RecompileData . MeshMaterialMaps ,
RecompileData . ModifiedFiles ) ;
}
}
2014-12-10 10:12:47 -05:00
FString UCookOnTheFlyServer : : GetSandboxDirectory ( const FString & PlatformName ) const
{
FString Result ;
Result = SandboxFile - > GetSandboxDirectory ( ) ;
Result . ReplaceInline ( TEXT ( " [Platform] " ) , * PlatformName ) ;
/*if ( IsCookingDLC() )
{
check ( IsCookByTheBookRunning ( ) ) ;
Result . ReplaceInline ( TEXT ( " /Cooked/ " ) , * FString : : Printf ( TEXT ( " /CookedDLC_%s/ " ) , * CookByTheBookOptions - > DlcName ) ) ;
} */
return Result ;
}
2014-09-16 12:15:46 -04:00
2014-12-01 16:53:12 -05:00
FString UCookOnTheFlyServer : : ConvertToFullSandboxPath ( const FString & FileName , bool bForWrite ) const
{
2014-12-10 10:12:47 -05:00
check ( SandboxFile ) ;
2014-12-01 16:53:12 -05:00
FString Result ;
if ( bForWrite )
{
Result = SandboxFile - > ConvertToAbsolutePathForExternalAppForWrite ( * FileName ) ;
}
else
{
Result = SandboxFile - > ConvertToAbsolutePathForExternalAppForRead ( * FileName ) ;
}
2014-12-10 10:12:47 -05:00
/*if ( IsCookingDLC() )
2014-12-01 16:53:12 -05:00
{
2014-12-10 10:12:47 -05:00
check ( IsCookByTheBookRunning ( ) ) ;
2014-12-01 16:53:12 -05:00
Result . ReplaceInline ( TEXT ( " /Cooked/ " ) , * FString : : Printf ( TEXT ( " /CookedDLC_%s/ " ) , * CookByTheBookOptions - > DlcName ) ) ;
2014-12-10 10:12:47 -05:00
} */
2014-12-01 16:53:12 -05:00
return Result ;
}
2014-12-10 10:12:47 -05:00
FString UCookOnTheFlyServer : : ConvertToFullSandboxPath ( const FString & FileName , bool bForWrite , const FString & PlatformName ) const
{
FString Result = ConvertToFullSandboxPath ( FileName , bForWrite ) ;
Result . ReplaceInline ( TEXT ( " [Platform] " ) , * PlatformName ) ;
return Result ;
}
2015-04-24 15:36:57 -04:00
const FString UCookOnTheFlyServer : : GetSandboxAssetRegistryFilename ( )
{
static const FString RegistryFilename = FPaths : : GameDir ( ) / TEXT ( " AssetRegistry.bin " ) ;
const FString SandboxRegistryFilename = ConvertToFullSandboxPath ( * RegistryFilename , true ) ;
return SandboxRegistryFilename ;
}
const FString UCookOnTheFlyServer : : GetCookedAssetRegistryFilename ( const FString & PlatformName )
{
const FString CookedAssetRegistryFilename = GetSandboxAssetRegistryFilename ( ) . Replace ( TEXT ( " [Platform] " ) , * PlatformName ) ;
return CookedAssetRegistryFilename ;
}
2014-09-16 12:15:46 -04:00
void UCookOnTheFlyServer : : CookByTheBookFinished ( )
{
2014-09-22 14:29:26 -04:00
check ( IsInGameThread ( ) ) ;
2014-09-16 12:15:46 -04:00
check ( IsCookByTheBookMode ( ) ) ;
check ( CookByTheBookOptions - > bRunning = = true ) ;
UPackage : : WaitForAsyncFileWrites ( ) ;
GetDerivedDataCacheRef ( ) . WaitForQuiescence ( true ) ;
2015-04-27 14:10:18 -04:00
2015-06-16 12:43:26 -04:00
2015-06-29 11:44:58 -04:00
if ( IsChildCooker ( ) )
2014-09-16 12:15:46 -04:00
{
2015-06-29 11:44:58 -04:00
// if we are the child cooker create a list of all the packages which we think wes hould have cooked but didn't
FString UncookedPackageList ;
for ( const auto & UncookedPackage : CookByTheBookOptions - > ChildUnsolicitedPackages )
2015-06-16 12:43:26 -04:00
{
2015-06-29 11:44:58 -04:00
UncookedPackageList . Append ( UncookedPackage . ToString ( ) + TEXT ( " \n \r " ) ) ;
2015-06-16 12:43:26 -04:00
}
2015-06-29 11:44:58 -04:00
FFileHelper : : SaveStringToFile ( UncookedPackageList , * GetChildCookerResultFilename ( CookByTheBookOptions - > ChildCookFilename ) ) ;
}
else
{
check ( CookByTheBookOptions - > ChildUnsolicitedPackages . Num ( ) = = 0 ) ;
2015-06-16 12:43:26 -04:00
}
if ( IsChildCooker ( ) = = false )
{
SCOPE_TIMER ( SavingAssetRegistry ) ;
2014-09-16 12:15:46 -04:00
// Save modified asset registry with all streaming chunk info generated during cook
2015-04-24 15:36:57 -04:00
const FString & SandboxRegistryFilename = GetSandboxAssetRegistryFilename ( ) ;
2014-09-16 12:15:46 -04:00
// the registry filename will be modified when we call save asset registry
2014-09-24 14:40:38 -04:00
2014-12-10 10:12:47 -05:00
const FString CookedAssetRegistry = FPaths : : GameDir ( ) / TEXT ( " CookedAssetRegistry.json " ) ;
const FString SandboxCookedAssetRegistryFilename = ConvertToFullSandboxPath ( * CookedAssetRegistry , true ) ;
2014-09-16 12:15:46 -04:00
for ( auto & Manifest : CookByTheBookOptions - > ManifestGenerators )
{
2015-06-23 11:24:52 -04:00
TArray < FName > CookedPackagesForPlatform ;
CookedPackages . GetCookedFilesForPlatform ( Manifest . Key , CookedPackagesForPlatform ) ;
TArray < FName > LongCookedPackageNames ;
for ( const auto & CookedPackageFileName : CookedPackagesForPlatform )
{
FString LongPackageName ;
verify ( FPackageName : : TryConvertFilenameToLongPackageName ( CookedPackageFileName . ToString ( ) , LongPackageName ) ) ;
LongCookedPackageNames . Add ( FName ( * LongPackageName ) ) ;
}
Manifest . Value - > BuildChunkManifest ( LongCookedPackageNames , SandboxFile , CookByTheBookOptions - > bGenerateStreamingInstallManifests ) ;
2014-09-16 12:15:46 -04:00
// Always try to save the manifests, this is required to make the asset registry work, but doesn't necessarily write a file
Manifest . Value - > SaveManifests ( SandboxFile . GetOwnedPointer ( ) ) ;
2015-04-27 14:10:18 -04:00
const FName & PlatformName = Manifest . Key ;
const TArray < FName > & PackageFilenames = CookByTheBookOptions - > BasedOnReleaseCookedPackages . FindRef ( PlatformName ) ;
TArray < FName > LongPackageNames ;
LongPackageNames . Empty ( PackageFilenames . Num ( ) ) ;
for ( const auto & PackageFilename : PackageFilenames )
{
FString LongPackageName ;
verify ( FPackageName : : TryConvertFilenameToLongPackageName ( PackageFilename . ToString ( ) , LongPackageName ) ) ;
LongPackageNames . Add ( FName ( * LongPackageName ) ) ;
}
Manifest . Value - > SaveAssetRegistry ( SandboxRegistryFilename , & LongPackageNames ) ;
2014-09-24 14:40:38 -04:00
Manifest . Value - > SaveCookedPackageAssetRegistry ( SandboxCookedAssetRegistryFilename , true ) ;
2014-12-10 10:12:47 -05:00
if ( IsCreatingReleaseVersion ( ) )
{
const FString VersionedRegistryPath = GetReleaseVersionAssetRegistryPath ( CookByTheBookOptions - > CreateReleaseVersion , Manifest . Key ) ;
IFileManager : : Get ( ) . MakeDirectory ( * VersionedRegistryPath , true ) ;
const FString VersionedRegistryFilename = VersionedRegistryPath / GetAssetRegistryFilename ( ) ;
const FString CookedAssetRegistryFilename = SandboxRegistryFilename . Replace ( TEXT ( " [Platform] " ) , * Manifest . Key . ToString ( ) ) ;
IFileManager : : Get ( ) . Copy ( * VersionedRegistryFilename , * CookedAssetRegistryFilename , true , true ) ;
// Manifest.Value->SaveManifests( VersionedRegistryFilename );
}
2014-09-16 12:15:46 -04:00
}
}
2015-06-29 11:44:58 -04:00
if ( CookByTheBookOptions - > bGenerateDependenciesForMaps & & ( IsChildCooker ( ) = = false ) )
2015-04-02 14:54:19 -04:00
{
2015-06-23 11:24:52 -04:00
for ( auto & MapDependencyGraphIt : CookByTheBookOptions - > MapDependencyGraphs )
2015-04-02 14:54:19 -04:00
{
2015-06-23 11:24:52 -04:00
BuildMapDependencyGraph ( MapDependencyGraphIt . Key ) ;
WriteMapDependencyGraph ( MapDependencyGraphIt . Key ) ;
2015-04-02 14:54:19 -04:00
}
}
2014-09-16 12:15:46 -04:00
CookByTheBookOptions - > LastGCItems . Empty ( ) ;
2014-10-03 14:56:20 -04:00
const float TotalCookTime = ( float ) ( FPlatformTime : : Seconds ( ) - CookByTheBookOptions - > CookStartTime ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Cook by the book total time in tick %fs total time %f " ) , CookByTheBookOptions - > CookTime , TotalCookTime ) ;
2014-09-16 12:15:46 -04:00
2015-04-27 14:10:18 -04:00
CookByTheBookOptions - > BasedOnReleaseCookedPackages . Empty ( ) ;
2014-09-16 12:15:46 -04:00
CookByTheBookOptions - > bRunning = false ;
2015-06-01 11:34:55 -04:00
OUTPUT_HIERARCHYTIMERS ( ) ;
2014-09-16 12:15:46 -04:00
}
2015-06-23 11:24:52 -04:00
void UCookOnTheFlyServer : : BuildMapDependencyGraph ( const FName & PlatformName )
{
auto & MapDependencyGraph = CookByTheBookOptions - > MapDependencyGraphs . FindChecked ( PlatformName ) ;
TArray < FName > PlatformCookedPackages ;
CookedPackages . GetCookedFilesForPlatform ( PlatformName , PlatformCookedPackages ) ;
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
// assign chunks for all the map packages
for ( const auto & CookedPackage : PlatformCookedPackages )
{
TArray < FAssetData > PackageAssets ;
ensure ( AssetRegistry . GetAssetsByPackageName ( CookedPackage , PackageAssets ) ) ;
bool bIsMap = false ;
for ( const auto & Asset : PackageAssets )
{
if ( Asset . GetClass ( ) - > IsChildOf ( UWorld : : StaticClass ( ) ) | |
Asset . GetClass ( ) - > IsChildOf ( ULevel : : StaticClass ( ) ) )
{
bIsMap = true ;
}
}
// if we are not a map we don't care about this pacakge
if ( ! bIsMap )
{
continue ;
}
TSet < FName > DependentPackages ;
for ( const auto & Asset : PackageAssets )
{
DependentPackages . Add ( Asset . PackageName ) ;
}
MapDependencyGraph . Add ( CookedPackage , DependentPackages ) ;
}
}
void UCookOnTheFlyServer : : WriteMapDependencyGraph ( const FName & PlatformName )
{
auto & MapDependencyGraph = CookByTheBookOptions - > MapDependencyGraphs . FindChecked ( PlatformName ) ;
FString MapDependencyGraphFile = FPaths : : GameDir ( ) / TEXT ( " MapDependencyGraph.json " ) ;
// dump dependency graph.
FString DependencyString ;
DependencyString + = " { " ;
for ( auto & Ele : MapDependencyGraph )
{
TSet < FName > & Deps = Ele . Value ;
FName MapName = Ele . Key ;
DependencyString + = TEXT ( " \t \" " ) + MapName . ToString ( ) + TEXT ( " \" : \n \t [ \n " ) ;
for ( auto & Val : Deps )
{
DependencyString + = TEXT ( " \t \t \" " ) + Val . ToString ( ) + TEXT ( " \" , \n " ) ;
}
DependencyString . RemoveFromEnd ( TEXT ( " , \n " ) ) ;
DependencyString + = TEXT ( " \n \t ], \n " ) ;
}
DependencyString . RemoveFromEnd ( TEXT ( " , \n " ) ) ;
DependencyString + = " \n } " ;
FString CookedMapDependencyGraphFilePlatform = ConvertToFullSandboxPath ( MapDependencyGraphFile , true ) . Replace ( TEXT ( " [Platform] " ) , * PlatformName . ToString ( ) ) ;
FFileHelper : : SaveStringToFile ( DependencyString , * CookedMapDependencyGraphFilePlatform , FFileHelper : : EEncodingOptions : : ForceUnicode ) ;
}
2014-09-22 14:29:26 -04:00
void UCookOnTheFlyServer : : QueueCancelCookByTheBook ( )
{
if ( IsCookByTheBookMode ( ) )
{
check ( CookByTheBookOptions ! = NULL ) ;
CookByTheBookOptions - > bCancel = true ;
}
}
void UCookOnTheFlyServer : : CancelCookByTheBook ( )
{
if ( IsCookByTheBookMode ( ) & & CookByTheBookOptions - > bRunning )
{
check ( CookByTheBookOptions ) ;
check ( IsInGameThread ( ) ) ;
// save the cook requests
CookRequests . DequeueAllRequests ( CookByTheBookOptions - > PreviousCookRequests ) ;
CookByTheBookOptions - > bRunning = false ;
2015-01-26 17:07:06 -05:00
SandboxFile = NULL ;
2014-09-22 14:29:26 -04:00
}
}
void UCookOnTheFlyServer : : StopAndClearCookedData ( )
{
if ( IsCookByTheBookMode ( ) )
{
check ( CookByTheBookOptions ! = NULL ) ;
check ( CookByTheBookOptions - > bRunning = = false ) ;
CancelCookByTheBook ( ) ;
CookByTheBookOptions - > PreviousCookRequests . Empty ( ) ;
}
RecompileRequests . Empty ( ) ;
CookRequests . Empty ( ) ;
UnsolicitedCookedPackages . Empty ( ) ;
CookedPackages . Empty ( ) ; // set of files which have been cooked when needing to recook a file the entry will need to be removed from here
}
2014-12-01 11:58:48 -05:00
void UCookOnTheFlyServer : : ClearAllCookedData ( )
{
// if we are going to clear the cooked packages it is conceivable that we will recook the packages which we just cooked
// that means it's also conceivable that we will recook the same package which currently has an outstanding async write request
UPackage : : WaitForAsyncFileWrites ( ) ;
UnsolicitedCookedPackages . Empty ( ) ;
CookedPackages . Empty ( ) ; // set of files which have been cooked when needing to recook a file the entry will need to be removed from here
}
void UCookOnTheFlyServer : : ClearPlatformCookedData ( const FName & PlatformName )
{
// if we are going to clear the cooked packages it is conceivable that we will recook the packages which we just cooked
// that means it's also conceivable that we will recook the same package which currently has an outstanding async write request
UPackage : : WaitForAsyncFileWrites ( ) ;
2014-12-10 10:12:47 -05:00
CookedPackages . RemoveAllFilesForPlatform ( PlatformName ) ;
2014-12-01 11:58:48 -05:00
TArray < FName > PackageNames ;
UnsolicitedCookedPackages . GetPackagesForPlatformAndRemove ( PlatformName , PackageNames ) ;
}
2014-12-10 10:12:47 -05:00
void UCookOnTheFlyServer : : CreateSandboxFile ( )
2014-09-16 12:15:46 -04:00
{
2014-12-10 10:12:47 -05:00
// initialize the sandbox file after determining if we are cooking dlc
// Local sandbox file wrapper. This will be used to handle path conversions,
// but will not be used to actually write/read files so we can safely
// use [Platform] token in the sandbox directory name and then replace it
// with the actual platform name.
check ( SandboxFile = = NULL ) ;
SandboxFile = new FSandboxPlatformFile ( false ) ;
// Output directory override.
FString OutputDirectory = GetOutputDirectoryOverride ( ) ;
// Use SandboxFile to do path conversion to properly handle sandbox paths (outside of standard paths in particular).
SandboxFile - > Initialize ( & FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) , * FString : : Printf ( TEXT ( " -sandbox= \" %s \" " ) , * OutputDirectory ) ) ;
}
2014-12-12 12:59:47 -05:00
void UCookOnTheFlyServer : : InitializeSandbox ( )
{
if ( SandboxFile = = NULL )
{
ITargetPlatformManagerModule & TPM = GetTargetPlatformManagerRef ( ) ;
const TArray < ITargetPlatform * > & TargetPlatforms = TPM . GetCookingTargetPlatforms ( ) ;
CreateSandboxFile ( ) ;
2015-06-16 12:43:26 -04:00
if ( ! IsChildCooker ( ) )
2014-12-12 12:59:47 -05:00
{
2015-06-16 12:43:26 -04:00
if ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) )
{
PopulateCookedPackagesFromDisk ( TargetPlatforms ) ;
}
2014-12-12 12:59:47 -05:00
2015-06-16 12:43:26 -04:00
CleanSandbox ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) ) ;
}
2014-12-12 12:59:47 -05:00
}
}
void UCookOnTheFlyServer : : TermSandbox ( )
{
ClearAllCookedData ( ) ;
ClearPackageFilenameCache ( ) ;
SandboxFile = NULL ;
}
2015-06-23 11:24:52 -04:00
void UCookOnTheFlyServer : : ValidateCookByTheBookSettings ( ) const
{
if ( IsChildCooker ( ) )
{
// should never be generating dependency maps / streaming install manifests for child cookers
check ( CookByTheBookOptions - > bGenerateDependenciesForMaps = = false ) ;
check ( CookByTheBookOptions - > bGenerateStreamingInstallManifests = = false ) ;
}
}
2014-12-10 10:12:47 -05:00
void UCookOnTheFlyServer : : StartCookByTheBook ( const FCookByTheBookStartupOptions & CookByTheBookStartupOptions )
{
const TArray < ITargetPlatform * > & TargetPlatforms = CookByTheBookStartupOptions . TargetPlatforms ;
const TArray < FString > & CookMaps = CookByTheBookStartupOptions . CookMaps ;
const TArray < FString > & CookDirectories = CookByTheBookStartupOptions . CookDirectories ;
const TArray < FString > & CookCultures = CookByTheBookStartupOptions . CookCultures ;
const TArray < FString > & IniMapSections = CookByTheBookStartupOptions . IniMapSections ;
const ECookByTheBookOptions & CookOptions = CookByTheBookStartupOptions . CookOptions ;
const FString & DLCName = CookByTheBookStartupOptions . DLCName ;
const FString & CreateReleaseVersion = CookByTheBookStartupOptions . CreateReleaseVersion ;
const FString & BasedOnReleaseVersion = CookByTheBookStartupOptions . BasedOnReleaseVersion ;
2014-09-22 14:29:26 -04:00
check ( IsInGameThread ( ) ) ;
2014-09-16 12:15:46 -04:00
check ( IsCookByTheBookMode ( ) ) ;
2015-06-16 12:43:26 -04:00
CookByTheBookOptions - > bRunning = true ;
CookByTheBookOptions - > bCancel = false ;
CookByTheBookOptions - > CookTime = 0.0f ;
CookByTheBookOptions - > CookStartTime = FPlatformTime : : Seconds ( ) ;
CookByTheBookOptions - > bGenerateStreamingInstallManifests = CookByTheBookStartupOptions . bGenerateStreamingInstallManifests ;
CookByTheBookOptions - > bGenerateDependenciesForMaps = CookByTheBookStartupOptions . bGenerateDependenciesForMaps ;
CookByTheBookOptions - > CreateReleaseVersion = CreateReleaseVersion ;
CookByTheBookOptions - > bForceEnableCompressedPackages = ! ! ( CookOptions & ECookByTheBookOptions : : ForceEnableCompressed ) ;
CookByTheBookOptions - > bForceDisableCompressedPackages = ! ! ( CookOptions & ECookByTheBookOptions : : ForceDisableCompressed ) ;
CookByTheBookOptions - > bIsChildCooker = CookByTheBookStartupOptions . ChildCookFileName . Len ( ) > 0 ? true : false ;
2015-06-29 11:44:58 -04:00
CookByTheBookOptions - > ChildCookFilename = CookByTheBookStartupOptions . ChildCookFileName ;
CookByTheBookOptions - > TargetPlatformNames . Empty ( ) ;
for ( const auto & Platform : TargetPlatforms )
{
FName PlatformName = FName ( * Platform - > PlatformName ( ) ) ;
CookByTheBookOptions - > TargetPlatformNames . Add ( PlatformName ) ; // build list of all target platform names
}
const TArray < FName > & TargetPlatformNames = CookByTheBookOptions - > TargetPlatformNames ;
2015-06-16 12:43:26 -04:00
bool bCookAll = ( CookOptions & ECookByTheBookOptions : : CookAll ) ! = ECookByTheBookOptions : : None ;
bool bMapsOnly = ( CookOptions & ECookByTheBookOptions : : MapsOnly ) ! = ECookByTheBookOptions : : None ;
bool bNoDev = ( CookOptions & ECookByTheBookOptions : : NoDevContent ) ! = ECookByTheBookOptions : : None ;
2015-06-23 11:24:52 -04:00
ValidateCookByTheBookSettings ( ) ;
2015-06-16 12:43:26 -04:00
2014-12-10 10:12:47 -05:00
if ( CookByTheBookOptions - > DlcName ! = DLCName )
{
// we are going to change the state of dlc we need to clean out our package filename cache (the generated filename cache is dependent on this key)
CookByTheBookOptions - > DlcName = DLCName ;
check ( OutputDirectoryOverride . Len ( ) = = 0 ) ;
2014-12-12 12:59:47 -05:00
TermSandbox ( ) ;
2014-12-10 10:12:47 -05:00
}
2014-12-12 12:59:47 -05:00
InitializeSandbox ( ) ;
2014-12-10 10:12:47 -05:00
2015-06-29 11:44:58 -04:00
2014-10-22 13:37:17 -04:00
CookByTheBookOptions - > bLeakTest = ( CookOptions & ECookByTheBookOptions : : LeakTest ) ! = ECookByTheBookOptions : : None ; // this won't work from the editor this needs to be standalone
2015-06-29 11:44:58 -04:00
check ( ! CookByTheBookOptions - > bLeakTest | | CurrentCookMode = = ECookMode : : CookByTheBook ) ;
2014-10-22 13:37:17 -04:00
2014-09-16 12:15:46 -04:00
CookByTheBookOptions - > LastGCItems . Empty ( ) ;
2015-06-29 11:44:58 -04:00
if ( CookByTheBookOptions - > bLeakTest )
2014-09-16 12:15:46 -04:00
{
for ( FObjectIterator It ; It ; + + It )
{
CookByTheBookOptions - > LastGCItems . Add ( FWeakObjectPtr ( * It ) ) ;
}
}
2015-06-16 12:43:26 -04:00
if ( ! IsChildCooker ( ) )
{
2015-06-29 11:44:58 -04:00
// iteratively clean any old files out of the sandbox (check if ini settings are out of date and clean out any stale files)
CleanSandbox ( true ) ;
2015-06-16 12:43:26 -04:00
for ( const auto & Platform : TargetPlatforms )
{
FName PlatformName = FName ( * Platform - > PlatformName ( ) ) ;
// make sure we have a manifest for all the platforms
// we want a seperate manifest for each platform because they can all be in different states of cooked content
FChunkManifestGenerator * ManifestGenerator = CookByTheBookOptions - > ManifestGenerators . FindRef ( PlatformName ) ;
if ( ManifestGenerator = = NULL )
{
TArray < ITargetPlatform * > Platforms ;
Platforms . Add ( Platform ) ;
ManifestGenerator = new FChunkManifestGenerator ( Platforms ) ;
ManifestGenerator - > CleanManifestDirectories ( ) ;
2015-06-23 11:24:52 -04:00
TArray < FName > StartupPackages ;
2015-06-16 12:43:26 -04:00
2015-06-23 11:24:52 -04:00
for ( TObjectIterator < UPackage > It ; It ; + + It )
2015-06-16 12:43:26 -04:00
{
2015-06-23 11:24:52 -04:00
StartupPackages . Add ( It - > GetFName ( ) ) ;
2015-06-16 12:43:26 -04:00
}
2015-06-23 11:24:52 -04:00
ManifestGenerator - > Initialize ( StartupPackages ) ;
2015-06-16 12:43:26 -04:00
CookByTheBookOptions - > ManifestGenerators . Add ( PlatformName , ManifestGenerator ) ;
}
2015-06-23 11:24:52 -04:00
if ( CookByTheBookOptions - > bGenerateDependenciesForMaps )
{
CookByTheBookOptions - > MapDependencyGraphs . Add ( PlatformName ) ;
}
2015-06-16 12:43:26 -04:00
}
}
2015-06-29 11:44:58 -04:00
2014-12-01 16:53:12 -05:00
if ( IsCookingDLC ( ) )
{
2014-12-10 10:12:47 -05:00
// if we are cooking dlc we must be based of a release version cook
check ( ! BasedOnReleaseVersion . IsEmpty ( ) ) ;
2014-12-01 16:53:12 -05:00
2014-12-10 10:12:47 -05:00
for ( const auto & PlatformName : TargetPlatformNames )
{
const FString OriginalSandboxRegistryFilename = GetReleaseVersionAssetRegistryPath ( BasedOnReleaseVersion , PlatformName ) / GetAssetRegistryFilename ( ) ;
2015-04-27 14:10:18 -04:00
TArray < FName > PackageList ;
2014-12-10 10:12:47 -05:00
// if this check fails probably because the asset registry can't be found or read
2015-04-27 14:10:18 -04:00
bool bSucceeded = GetAllPackagesFromAssetRegistry ( OriginalSandboxRegistryFilename , PackageList ) ;
2014-12-10 10:12:47 -05:00
check ( bSucceeded ) ;
if ( bSucceeded )
{
2015-04-27 14:10:18 -04:00
TArray < FName > PlatformNames ;
PlatformNames . Add ( PlatformName ) ;
for ( const auto & PackageFilename : PackageList )
2014-12-10 10:12:47 -05:00
{
2015-04-27 14:10:18 -04:00
CookedPackages . Add ( MoveTemp ( FFilePlatformRequest ( PackageFilename , PlatformNames ) ) ) ;
2014-12-10 10:12:47 -05:00
}
}
2015-04-27 14:10:18 -04:00
CookByTheBookOptions - > BasedOnReleaseCookedPackages . Add ( PlatformName , MoveTemp ( PackageList ) ) ;
2014-12-10 10:12:47 -05:00
}
2014-12-01 16:53:12 -05:00
}
2014-12-10 10:12:47 -05:00
2015-04-24 15:36:57 -04:00
TArray < FName > FilesInPath ;
2015-06-16 12:43:26 -04:00
if ( ! IsChildCooker ( ) )
2015-04-24 15:36:57 -04:00
{
2015-06-16 12:43:26 -04:00
// allow the game to fill out the asset registry, as well as get a list of objects to always cook
TArray < FString > FilesInPathStrings ;
FGameDelegates : : Get ( ) . GetCookModificationDelegate ( ) . ExecuteIfBound ( FilesInPathStrings ) ;
for ( const auto & FileString : FilesInPathStrings )
{
FilesInPath . Add ( FName ( * FileString ) ) ;
}
2015-04-24 15:36:57 -04:00
}
2014-12-01 16:53:12 -05:00
2014-12-10 10:12:47 -05:00
// don't resave the global shader map files in dlc
2015-06-16 12:43:26 -04:00
if ( ! IsCookingDLC ( ) & & ! IsChildCooker ( ) )
2014-12-10 10:12:47 -05:00
{
SaveGlobalShaderMapFiles ( TargetPlatforms ) ;
}
2015-04-24 15:36:57 -04:00
2015-06-29 11:44:58 -04:00
CollectFilesToCook ( FilesInPath , CookMaps , CookDirectories , CookCultures , IniMapSections , bCookAll , bMapsOnly , bNoDev ) ;
2014-12-01 16:53:12 -05:00
if ( FilesInPath . Num ( ) = = 0 )
{
LogCookerMessage ( FString : : Printf ( TEXT ( " No files found to cook. " ) ) , EMessageSeverity : : Warning ) ;
UE_LOG ( LogCook , Warning , TEXT ( " No files found. " ) ) ;
}
2015-04-13 16:14:12 -04:00
{
# if OUTPUT_TIMING
SCOPE_TIMER ( GenerateLongPackageName ) ;
# endif
GenerateLongPackageNames ( FilesInPath ) ;
}
2014-09-16 12:15:46 -04:00
// add all the files for the requested platform to the cook list
2015-04-24 15:36:57 -04:00
for ( const auto & FileFName : FilesInPath )
2014-09-16 12:15:46 -04:00
{
2015-04-24 15:36:57 -04:00
// FName FileFName = FName(*FileName);
FString FileName = FileFName . ToString ( ) ;
2014-09-22 14:29:26 -04:00
FName PackageFileFName = GetCachedStandardPackageFileFName ( FileFName ) ;
2014-09-16 12:15:46 -04:00
2014-09-22 14:29:26 -04:00
if ( PackageFileFName ! = NAME_None )
2014-09-16 12:15:46 -04:00
{
2014-09-22 14:29:26 -04:00
CookRequests . EnqueueUnique ( MoveTemp ( FFilePlatformRequest ( PackageFileFName , TargetPlatformNames ) ) ) ;
2014-09-16 12:15:46 -04:00
}
else
{
2014-09-16 21:12:55 -04:00
LogCookerMessage ( FString : : Printf ( TEXT ( " Unable to find package for cooking %s " ) , * FileName ) , EMessageSeverity : : Warning ) ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " Unable to find package for cooking %s " ) , * FileName )
2014-09-22 14:29:26 -04:00
}
2014-09-16 12:15:46 -04:00
}
2014-12-10 10:12:47 -05:00
2015-06-16 12:43:26 -04:00
if ( ! IsCookingDLC ( ) & & ! IsChildCooker ( ) )
2014-12-10 10:12:47 -05:00
{
// if we are not cooking dlc then basedOfRelease version just needs to make sure that we cook all the packages which are in the previous release (as well as the new ones)
if ( ! BasedOnReleaseVersion . IsEmpty ( ) )
{
// if we are based of a release and we are not cooking dlc then we should always be creating a new one (note that we could be creating the same one we are based of).
2015-04-13 16:14:12 -04:00
// note that we might erroneously enter here if we are generating a patch instead and we accidentally passed in BasedOnReleaseVersion to the cooker instead of to unrealpak
2014-12-10 10:12:47 -05:00
check ( ! CreateReleaseVersion . IsEmpty ( ) ) ;
for ( const auto & PlatformName : TargetPlatformNames )
{
TArray < FName > PlatformArray ;
PlatformArray . Add ( PlatformName ) ;
// if we are based of a cook and we are creating a new one we need to make sure that at least all the old packages are cooked as well as the new ones
FString OriginalAssetRegistryPath = GetReleaseVersionAssetRegistryPath ( BasedOnReleaseVersion , PlatformName ) / GetAssetRegistryFilename ( ) ;
TArray < FName > PackageFiles ;
verify ( ! GetAllPackagesFromAssetRegistry ( OriginalAssetRegistryPath , PackageFiles ) ) ;
for ( const auto & PackageFilename : PackageFiles )
{
CookRequests . EnqueueUnique ( MoveTemp ( FFilePlatformRequest ( PackageFilename , PlatformArray ) ) ) ;
}
}
}
}
2014-12-01 16:53:12 -05:00
// this is to support canceling cooks from the editor
// this is required to make sure that the cooker is in a good state after cancel occurs
// if too many packages are being recooked after resume then we may need to figure out a different way to do this
2014-09-22 14:29:26 -04:00
for ( const auto & PreviousRequest : CookByTheBookOptions - > PreviousCookRequests )
{
CookRequests . EnqueueUnique ( MoveTemp ( PreviousRequest ) ) ;
}
CookByTheBookOptions - > PreviousCookRequests . Empty ( ) ;
2015-06-16 12:43:26 -04:00
if ( CookByTheBookStartupOptions . NumProcesses )
{
StartChildCookers ( CookByTheBookStartupOptions . NumProcesses , TargetPlatformNames ) ;
}
}
// sue chefs away!!
void UCookOnTheFlyServer : : StartChildCookers ( int32 NumCookersToSpawn , const TArray < FName > & TargetPlatformNames )
{
SCOPE_TIMER ( StartingChildCookers ) ;
// create a comprehensive list of all the files we need to cook
// then get the packages with least dependencies and give them to some sue chefs to handle
check ( ! IsChildCooker ( ) ) ;
2015-06-29 11:44:58 -04:00
// PackageNames contains a sorted list of the packages we want to distribute to child cookers
2015-06-16 12:43:26 -04:00
TArray < FName > PackageNames ;
2015-06-29 11:44:58 -04:00
// PackageNamesSet is a set of the same information for quick lookup into packagenames array
TSet < FName > PackageNamesSet ;
2015-06-16 12:43:26 -04:00
PackageNames . Empty ( CookRequests . Num ( ) ) ;
// TArray<FFilePlatformRequest>;
2015-06-29 11:44:58 -04:00
2015-06-16 12:43:26 -04:00
for ( const auto & CookRequest : CookRequests . GetQueue ( ) )
{
FString LongPackageName = FPackageName : : FilenameToLongPackageName ( CookRequest . ToString ( ) ) ;
2015-06-29 11:44:58 -04:00
const FName PackageFName = FName ( * LongPackageName ) ;
PackageNames . Add ( PackageFName ) ;
PackageNamesSet . Add ( PackageFName ) ;
2015-06-16 12:43:26 -04:00
}
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
int32 PackageCounter = 0 ;
while ( PackageCounter < PackageNames . Num ( ) )
{
const auto & PackageName = PackageNames [ PackageCounter ] ;
+ + PackageCounter ;
TArray < FName > UnfilteredDependencies ;
AssetRegistry . GetDependencies ( PackageName , UnfilteredDependencies ) ;
2015-06-29 11:44:58 -04:00
for ( const auto & Dependency : UnfilteredDependencies )
2015-06-16 12:43:26 -04:00
{
2015-06-29 11:44:58 -04:00
if ( FPackageName : : IsScriptPackage ( Dependency . ToString ( ) ) = = false )
2015-06-16 12:43:26 -04:00
{
2015-06-29 11:44:58 -04:00
if ( PackageNamesSet . Contains ( Dependency ) = = false )
{
PackageNamesSet . Add ( Dependency ) ;
PackageNames . Insert ( Dependency , PackageCounter ) ;
}
2015-06-16 12:43:26 -04:00
}
}
}
TArray < FName > DistributeStandardFilenames ;
2015-06-29 11:44:58 -04:00
for ( const auto & DistributeCandidate : PackageNames )
2015-06-16 12:43:26 -04:00
{
FText OutReason ;
FString LongPackageName = DistributeCandidate . ToString ( ) ;
if ( ! FPackageName : : IsValidLongPackageName ( LongPackageName , true , & OutReason ) )
{
const FText FailMessage = FText : : Format ( LOCTEXT ( " UnableToGeneratePackageName " , " Unable to generate long package name for {0}. {1} " ) ,
FText : : FromString ( LongPackageName ) , OutReason ) ;
LogCookerMessage ( FailMessage . ToString ( ) , EMessageSeverity : : Warning ) ;
UE_LOG ( LogCook , Warning , TEXT ( " %s " ) , * ( FailMessage . ToString ( ) ) ) ;
continue ;
}
else if ( FPackageName : : IsScriptPackage ( LongPackageName ) )
{
continue ;
}
DistributeStandardFilenames . Add ( FName ( * LongPackageName ) ) ;
}
UE_LOG ( LogCook , Display , TEXT ( " Distributing %d packages to %d cookers for processing " ) , DistributeStandardFilenames . Num ( ) , NumCookersToSpawn ) ;
FString TargetPlatformString ;
for ( const auto & TargetPlatformName : TargetPlatformNames )
{
if ( TargetPlatformString . Len ( ) ! = 0 )
{
TargetPlatformString + = TEXT ( " + " ) ;
}
TargetPlatformString + = TargetPlatformName . ToString ( ) ;
}
// start the child cookers and give them each some distribution candidates
for ( int32 CookerCounter = 0 ; CookerCounter < NumCookersToSpawn ; + + CookerCounter )
{
2015-06-29 11:44:58 -04:00
// count our selves as a cooker
int32 NumFilesForCooker = DistributeStandardFilenames . Num ( ) / ( ( NumCookersToSpawn + 1 ) - CookerCounter ) ;
// don't spawn a cooker unless it has a minimum amount of files to do
2015-06-16 12:43:26 -04:00
if ( NumFilesForCooker < 5 )
{
continue ;
}
int32 ChildCookerIndex = CookByTheBookOptions - > ChildCookers . AddDefaulted ( 1 ) ;
auto & ChildCooker = CookByTheBookOptions - > ChildCookers [ ChildCookerIndex ] ;
// starting child cookers
//FProcHandle ProcessHandle = FPlatformProcess::CreateProc(*ExecutablePath, *CommandLine, false, true, true, NULL, 0, NULL, WritePipe);
// ChildCooker.
ChildCooker . ResponseFileName = FPaths : : CreateTempFilename ( * ( FPaths : : GameSavedDir ( ) / TEXT ( " CookingTemp " ) ) ) ;
ChildCooker . BaseResponseFileName = FPaths : : GetBaseFilename ( ChildCooker . ResponseFileName ) ;
// FArchive* ResponseFile = IFileManager::CreateFileWriter(ChildCooker.UniqueTempName);
FString ResponseFileText ;
for ( int32 I = 0 ; I < NumFilesForCooker ; + + I )
{
FName PackageFName = DistributeStandardFilenames [ I ] ;
FString PackageName = PackageFName . ToString ( ) ;
ResponseFileText + = FString : : Printf ( TEXT ( " %s%s " ) , * PackageName , LINE_TERMINATOR ) ;
// these are long package names
FName StandardPackageName = GetCachedStandardPackageFileFName ( PackageFName ) ;
if ( StandardPackageName = = NAME_None )
continue ;
#if 0 // validation code can be disabled
PackageName = FPackageName : : LongPackageNameToFilename ( PackageName , FPaths : : GetExtension ( PackageName ) ) ;
FPaths : : MakeStandardFilename ( PackageName ) ;
FName PackageFName = FName ( * PackageName ) ;
check ( PackageFName = = StandardPackageName ) ;
# endif
/*PackageName = FPackageName::LongPackageNameToFilename(PackageName, FPaths::GetExtension(PackageName));
FPaths : : MakeStandardFilename ( PackageName ) ;
FName StandardPackageName = FName ( * PackageName ) ; */
CookedPackages . Add ( FFilePlatformRequest ( StandardPackageName , TargetPlatformNames ) ) ;
}
DistributeStandardFilenames . RemoveAt ( 0 , NumFilesForCooker ) ;
UE_LOG ( LogCook , Display , TEXT ( " Child cooker %d working on %d files " ) , CookerCounter , NumFilesForCooker ) ;
FFileHelper : : SaveStringToFile ( ResponseFileText , * ChildCooker . ResponseFileName ) ;
FString CommandLine = FString : : Printf ( TEXT ( " %s -run=cook -targetplatform=%s -cookchild=%s -abslog=%sLog.txt " ) , * FPaths : : GetProjectFilePath ( ) , * TargetPlatformString , * ChildCooker . ResponseFileName , * ChildCooker . ResponseFileName ) ;
FString DDCCommandline ;
if ( FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " ddc= " ) , DDCCommandline ) )
{
CommandLine + = TEXT ( " -ddc= " ) ;
CommandLine + = DDCCommandline ;
}
FString ExecutablePath = FPlatformProcess : : ExecutableName ( true ) ;
// FString ExeFileName = FPaths::EngineDir() / TEXT("Binaries") / PlatformConfig / FString(FPlatformProcess::ExecutableName()) + TEXT(".exe");
UE_LOG ( LogCook , Display , TEXT ( " Launching cooker using commandline %s %s " ) , * ExecutablePath , * CommandLine ) ;
void * ReadPipe = NULL ;
void * WritePipe = NULL ;
FPlatformProcess : : CreatePipe ( ReadPipe , WritePipe ) ;
//ChildCooker.ProcessHandle = FPlatformProcess::CreateProc(*ExecutablePath, *CommandLine, false, true, true, NULL, 0, NULL, WritePipe);
ChildCooker . ProcessHandle = FPlatformProcess : : CreateProc ( * ExecutablePath , * CommandLine , false , true , true , NULL , 0 , NULL , NULL ) ;
ChildCooker . ReadPipe = ReadPipe ;
}
2014-09-16 12:15:46 -04:00
}
2014-04-23 18:33:25 -04:00
/* UCookOnTheFlyServer callbacks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-06-16 12:43:26 -04:00
void UCookOnTheFlyServer : : MaybeMarkPackageAsAlreadyLoaded ( UPackage * Package )
{
// can't use this optimization while cooking in editor
check ( IsCookingInEditor ( ) = = false ) ;
check ( IsCookByTheBookMode ( ) ) ;
FName StandardName = GetCachedStandardPackageFileFName ( Package ) ;
2015-06-29 11:44:58 -04:00
bool bShouldMarkAsAlreadyProcessed = false ;
2015-06-16 12:43:26 -04:00
TArray < FName > CookedPlatforms ;
if ( CookedPackages . GetCookedPlatforms ( StandardName , CookedPlatforms ) )
{
FString Platforms ;
for ( const auto & CookedPlatform : CookedPlatforms )
{
Platforms + = TEXT ( " " ) ;
Platforms + = CookedPlatform . ToString ( ) ;
}
2015-06-29 11:44:58 -04:00
bShouldMarkAsAlreadyProcessed = true ;
2015-06-16 12:43:26 -04:00
UE_LOG ( LogCook , Display , TEXT ( " Marking %s as reloading for cooker because it's been cooked for platforms%s. " ) , * StandardName . ToString ( ) , * Platforms ) ;
2015-06-29 11:44:58 -04:00
}
/*
// if we are currently loading a package then the request would already be dequed so this check doesn't work
// need to figure out a better way to do this
if ( IsChildCooker ( ) )
{
// if we are the child cooker then we will never save anything that isn't in the cook requests
if ( CookRequests . Exists ( StandardName ) = = false )
{
bShouldMarkAsAlreadyProcessed = true ;
}
}
*/
if ( bShouldMarkAsAlreadyProcessed )
{
2015-06-16 12:43:26 -04:00
Package - > PackageFlags | = PKG_ReloadingForCooker ;
}
/*FString Name = Package->GetName();
if ( PackagesToNotReload . Contains ( Name ) )
{
UE_LOG ( LogCookCommandlet , Verbose , TEXT ( " Marking %s already loaded. " ) , * Name ) ;
Package - > PackageFlags | = PKG_ReloadingForCooker ;
} */
}
2014-04-23 18:33:25 -04:00
void UCookOnTheFlyServer : : HandleNetworkFileServerFileRequest ( const FString & Filename , const FString & Platformname , TArray < FString > & UnsolicitedFiles )
{
2015-01-19 10:58:24 -05:00
check ( IsCookOnTheFlyMode ( ) ) ;
2014-09-16 12:15:46 -04:00
2014-04-23 18:33:25 -04:00
bool bIsCookable = FPackageName : : IsPackageExtension ( * FPaths : : GetExtension ( Filename , true ) ) ;
2014-05-02 10:44:16 -04:00
FName PlatformFname = FName ( * Platformname ) ;
2014-04-23 18:33:25 -04:00
if ( ! bIsCookable )
{
2014-09-16 12:15:46 -04:00
TArray < FName > UnsolicitedFilenames ;
UnsolicitedCookedPackages . GetPackagesForPlatformAndRemove ( PlatformFname , UnsolicitedFilenames ) ;
for ( const auto & UnsolicitedFile : UnsolicitedFilenames )
{
FString StandardFilename = UnsolicitedFile . ToString ( ) ;
FPaths : : MakeStandardFilename ( StandardFilename ) ;
UnsolicitedFiles . Add ( StandardFilename ) ;
2014-04-23 18:33:25 -04:00
}
UPackage : : WaitForAsyncFileWrites ( ) ;
return ;
}
2014-09-16 12:15:46 -04:00
2014-05-02 10:44:16 -04:00
FString StandardFileName = Filename ;
FPaths : : MakeStandardFilename ( StandardFileName ) ;
2014-09-16 12:15:46 -04:00
FName StandardFileFname = FName ( * StandardFileName ) ;
TArray < FName > Platforms ;
Platforms . Add ( PlatformFname ) ;
FFilePlatformRequest FileRequest ( StandardFileFname , Platforms ) ;
CookRequests . EnqueueUnique ( FileRequest , true ) ;
2014-04-23 18:33:25 -04:00
do
{
FPlatformProcess : : Sleep ( 0.0f ) ;
}
2014-09-16 12:15:46 -04:00
while ( ! CookedPackages . Exists ( FileRequest ) ) ;
2014-04-23 18:33:25 -04:00
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Cook complete %s " ) , * FileRequest . GetFilename ( ) . ToString ( ) )
2014-05-02 10:44:16 -04:00
2014-09-16 12:15:46 -04:00
TArray < FName > UnsolicitedFilenames ;
UnsolicitedCookedPackages . GetPackagesForPlatformAndRemove ( PlatformFname , UnsolicitedFilenames ) ;
UnsolicitedFilenames . Remove ( FileRequest . GetFilename ( ) ) ;
for ( const auto & UnsolicitedFile : UnsolicitedFilenames )
{
FString StandardFilename = UnsolicitedFile . ToString ( ) ;
FPaths : : MakeStandardFilename ( StandardFilename ) ;
UnsolicitedFiles . Add ( StandardFilename ) ;
2014-04-23 18:33:25 -04:00
}
2014-05-02 10:44:16 -04:00
2014-04-23 18:33:25 -04:00
UPackage : : WaitForAsyncFileWrites ( ) ;
# if DEBUG_COOKONTHEFLY
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Processed file request %s " ) , * Filename ) ;
2014-04-23 18:33:25 -04:00
# endif
}
void UCookOnTheFlyServer : : HandleNetworkFileServerRecompileShaders ( const FShaderRecompileData & RecompileData )
{
2014-09-16 12:15:46 -04:00
// shouldn't receive network requests unless we are in cook on the fly mode
2014-12-10 10:12:47 -05:00
check ( IsCookOnTheFlyMode ( ) ) ;
check ( ! IsCookingDLC ( ) ) ;
2014-04-23 18:33:25 -04:00
// if we aren't in the game thread, we need to push this over to the game thread and wait for it to finish
if ( ! IsInGameThread ( ) )
{
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Got a recompile request on non-game thread " ) ) ;
2014-04-23 18:33:25 -04:00
// make a new request
FRecompileRequest * Request = new FRecompileRequest ;
Request - > RecompileData = RecompileData ;
Request - > bComplete = false ;
// push the request for the game thread to process
RecompileRequests . Enqueue ( Request ) ;
// wait for it to complete (the game thread will pull it out of the TArray, but I will delete it)
while ( ! Request - > bComplete )
{
FPlatformProcess : : Sleep ( 0 ) ;
}
delete Request ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Display , TEXT ( " Completed recompile... " ) ) ;
2014-04-23 18:33:25 -04:00
// at this point, we are done on the game thread, and ModifiedFiles will have been filled out
return ;
}
2014-12-10 10:12:47 -05:00
FString OutputDir = GetSandboxDirectory ( RecompileData . PlatformName ) ;
2014-04-23 18:33:25 -04:00
RecompileShadersForRemote
( RecompileData . PlatformName ,
RecompileData . ShaderPlatform = = - 1 ? SP_NumPlatforms : ( EShaderPlatform ) RecompileData . ShaderPlatform ,
OutputDir ,
RecompileData . MaterialsToLoad ,
RecompileData . SerializedShaderResources ,
RecompileData . MeshMaterialMaps ,
2014-06-23 10:23:52 -04:00
RecompileData . ModifiedFiles ,
RecompileData . bCompileChangedShaders ) ;
2014-04-23 18:33:25 -04:00
}
2014-10-14 14:38:00 -04:00
2014-12-10 10:12:47 -05:00
/*void UCookOnTheFlyServer::WarmCookedPackages(const FString& AssetRegistryPath, const TArray<FName>& TargetPlatformNames)
2014-10-14 14:38:00 -04:00
{
FArrayReader SerializedAssetData ;
if ( FFileHelper : : LoadFileToArray ( SerializedAssetData , * AssetRegistryPath ) )
{
int32 LocalNumAssets = 0 ;
SerializedAssetData < < LocalNumAssets ;
// allocate one single block for all asset data structs (to reduce tens of thousands of heap allocations)
FAssetData * PreallocatedAssetDataBuffer = new FAssetData [ LocalNumAssets ] ;
CookedPackages . Empty ( LocalNumAssets ) ;
FFilePlatformRequest FileRequest ;
for ( const auto & Platform : TargetPlatformNames )
{
FileRequest . AddPlatform ( Platform ) ;
}
for ( int32 AssetIndex = 0 ; AssetIndex < LocalNumAssets ; AssetIndex + + )
{
// make a new asset data object
FAssetData * NewAssetData = & PreallocatedAssetDataBuffer [ AssetIndex ] ;
// load it
SerializedAssetData < < * NewAssetData ;
2014-12-01 16:53:12 -05:00
UE_LOG ( LogCook , Verbose , TEXT ( " Read package %s from %s " ) , * GetCachedStandardPackageFilename ( NewAssetData - > ObjectPath ) , * AssetRegistryPath ) ;
2014-10-14 14:38:00 -04:00
FileRequest . SetFilename ( GetCachedStandardPackageFilename ( NewAssetData - > ObjectPath ) ) ;
2014-10-30 17:08:43 -04:00
if ( FileRequest . IsValid ( ) )
{
CookedPackages . Add ( FileRequest ) ;
}
2014-10-14 14:38:00 -04:00
}
delete [ ] PreallocatedAssetDataBuffer ;
}
2014-12-10 10:12:47 -05:00
} */
bool UCookOnTheFlyServer : : GetAllPackagesFromAssetRegistry ( const FString & AssetRegistryPath , TArray < FName > & OutPackageNames ) const
{
FArrayReader SerializedAssetData ;
if ( FFileHelper : : LoadFileToArray ( SerializedAssetData , * AssetRegistryPath ) )
{
int32 LocalNumAssets = 0 ;
SerializedAssetData < < LocalNumAssets ;
// allocate one single block for all asset data structs (to reduce tens of thousands of heap allocations)
FAssetData * PreallocatedAssetDataBuffer = new FAssetData [ LocalNumAssets ] ;
for ( int32 AssetIndex = 0 ; AssetIndex < LocalNumAssets ; AssetIndex + + )
{
// make a new asset data object
FAssetData * NewAssetData = & PreallocatedAssetDataBuffer [ AssetIndex ] ;
// load it
SerializedAssetData < < * NewAssetData ;
UE_LOG ( LogCook , Verbose , TEXT ( " Read package %s from %s " ) , * GetCachedStandardPackageFilename ( NewAssetData - > ObjectPath ) , * AssetRegistryPath ) ;
2015-01-20 11:39:23 -05:00
FName CachedPackageFileFName = GetCachedStandardPackageFileFName ( NewAssetData - > ObjectPath ) ;
if ( CachedPackageFileFName ! = NAME_None )
{
OutPackageNames . Add ( CachedPackageFileFName ) ;
}
else
{
UE_LOG ( LogCook , Warning , TEXT ( " Could not resolve package %s from %s " ) , * NewAssetData - > ObjectPath . ToString ( ) , * AssetRegistryPath ) ;
}
2014-12-10 10:12:47 -05:00
}
delete [ ] PreallocatedAssetDataBuffer ;
return true ;
}
return false ;
2015-04-24 14:41:13 -04:00
}
# undef LOCTEXT_NAMESPACE