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"
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
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
2014-12-03 14:35:48 -05:00
# define OUTPUT_TIMING 0
2014-08-18 16:20:23 -04:00
# if OUTPUT_TIMING
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
2014-08-18 16:20:23 -04:00
static TArray < FTimerInfo > GTimerInfo ;
struct FScopeTimer
{
private :
bool Started ;
bool DecrementScope ;
static int GScopeDepth ;
public :
FScopeTimer ( const FScopeTimer & outer )
{
Index = outer . Index ;
DecrementScope = false ;
Started = false ;
}
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 ;
}
2014-08-18 16:20:23 -04:00
Index = GTimerInfo . Emplace ( MoveTemp ( Name ) , 0.0 ) ;
Started = false ;
}
void Start ( )
{
if ( ! Started )
{
GTimerInfo [ Index ] . Length - = FPlatformTime : : Seconds ( ) ;
Started = true ;
}
}
void Stop ( )
{
if ( Started )
{
GTimerInfo [ Index ] . Length + = FPlatformTime : : Seconds ( ) ;
Started = false ;
}
}
~ FScopeTimer ( )
{
Stop ( ) ;
if ( DecrementScope )
{
- - GScopeDepth ;
}
}
int Index ;
} ;
int FScopeTimer : : GScopeDepth = 0 ;
void OutputTimers ( )
{
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 ) ;
}
static FString NewLine = FString ( TEXT ( " \n " ) ) ;
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 ( ) ;
}
# 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();
# define OUTPUT_TIMERS() OutputTimers();
# 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)
# define OUTPUT_TIMERS()
# 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 ;
}
/**
* 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 ) ;
MessageLog . Notify ( ) ;
}
/* 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
{
check ( Package - > GetName ( ) = = Package - > GetFName ( ) . ToString ( ) ) ;
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
{
check ( Package - > GetName ( ) = = Package - > GetFName ( ) . ToString ( ) ) ;
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
{
check ( Package - > GetName ( ) = = Package - > GetFName ( ) . ToString ( ) ) ;
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 ) )
2014-11-18 15:49:39 -05: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 ) ;
}
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
}
2014-12-10 10:12:47 -05:00
void UCookOnTheFlyServer : : ClearPackageFilenameCache ( ) const
{
2014-12-01 16:53:12 -05:00
PackageFilenameCache . 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 ;
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
*/
2014-09-16 14:41:25 -04:00
FArchive & operator < < ( UObject * & Obj )
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
check ( RootSetArray . Find ( Object ) = = INDEX_NONE ) ;
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 ;
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 ) ;
}
}
/**
* Returns the name of the Archive . Useful for getting the name of the package a struct or object
* is in when a loading error occurs .
*
* This is overridden for the specific Archive Types
* */
virtual FString GetArchiveName ( ) const { return TEXT ( " FArchiveFindReferences " ) ; }
} ;
void UCookOnTheFlyServer : : GetDependencies ( const TSet < UPackage * > & Packages , TSet < UObject * > & Found )
{
TSet < UObject * > RootSet ;
// Iterate through the object list
for ( FObjectIterator It ; It ; + + It )
{
2014-11-20 17:26:12 -05:00
if ( * It )
2014-09-16 12:15:46 -04:00
{
2014-12-01 16:53:12 -05:00
UPackage * Package = It - > GetOutermost ( ) ;
if ( Packages . Find ( Package ) )
{
RootSet . Add ( * It ) ;
Found . Add ( * It ) ;
}
2014-09-16 12:15:46 -04:00
}
}
TArray < UObject * > Exclude ;
FArchiveFindReferences ArFindReferences ( RootSet , Found , Exclude ) ;
// Iterate through the object list
/*for( FObjectIterator It; It; ++It )
{
// if this object is within the package specified, serialize the object
// into a specialized archive which logs object names encountered during
// serialization -- rjp
if ( It - > IsIn ( Pkg ) )
{
if ( It - > GetOuter ( ) = = Pkg )
{
FArchiveFindReferences ArFindReferences ( Pkg , * It , Found , Exclude ) ;
}
else if ( bRecurse )
{
// Two options -
// a) this object is a function or something (which we don't care about)
// b) this object is inside a group inside the specified package (which we do care about)
UObject * CurrentObject = * It ;
UObject * CurrentOuter = It - > GetOuter ( ) ;
while ( CurrentObject & & CurrentOuter )
{
// this object is a UPackage (a group inside a package)
// abort
if ( CurrentObject - > GetClass ( ) = = UPackage : : StaticClass ( ) )
break ;
// see if this object's outer is a UPackage
if ( CurrentOuter - > GetClass ( ) = = UPackage : : StaticClass ( ) )
{
// if this object's outer is our original package, the original object (It)
// wasn't inside a group, it just wasn't at the base level of the package
// (its Outer wasn't the Pkg, it was something else e.g. a function, state, etc.)
/// ....just skip it
if ( CurrentOuter = = Pkg )
break ;
// otherwise, we've successfully found an object that was in the package we
// were searching, but would have been hidden within a group - let's log it
FArchiveFindReferences ArFindReferences ( CurrentOuter , CurrentObject , Found , Exclude ) ;
break ;
}
CurrentObject = CurrentOuter ;
CurrentOuter = CurrentObject - > GetOuter ( ) ;
}
}
}
} */
}
void UCookOnTheFlyServer : : GenerateManifestInfo ( UPackage * Package , const TArray < FName > & TargetPlatformNames )
{
if ( ! CookByTheBookOptions )
return ;
// generate dependency information for this package
TSet < UPackage * > RootPackages ;
RootPackages . Add ( Package ) ;
FString LastLoadedMapName ;
// load sublevels
UWorld * World = UWorld : : FindWorldInPackage ( Package ) ;
if ( World )
{
for ( const auto & StreamingLevel : World - > StreamingLevels )
{
2014-12-01 16:53:12 -05:00
if ( StreamingLevel - > GetLoadedLevel ( ) )
{
RootPackages . Add ( StreamingLevel - > GetLoadedLevel ( ) - > GetOutermost ( ) ) ;
}
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 ) ;
}
for ( const auto & PackageName : NewPackagesToCook )
{
2015-03-02 13:41:53 -05:00
UPackage * PackageToCook = LoadPackage ( NULL , * PackageName , LOAD_None ) ;
2014-09-16 12:15:46 -04:00
2015-03-02 13:41:53 -05:00
RootPackages . Add ( PackageToCook ) ;
//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 ( ) ;
}
TSet < UObject * > Dependencies ;
GetDependencies ( RootPackages , Dependencies ) ;
FName StandardFilename = GetCachedStandardPackageFileFName ( Package ) ;
TSet < UPackage * > Packages ;
for ( const auto & Object : Dependencies )
{
Packages . Add ( Object - > GetOutermost ( ) ) ;
}
// update the manifests with generated dependencies
for ( const auto & PlatformName : TargetPlatformNames )
{
FChunkManifestGenerator * ManifestGenerator = CookByTheBookOptions - > ManifestGenerators . FindChecked ( PlatformName ) ;
if ( CookByTheBookOptions - > bGenerateStreamingInstallManifests )
{
ManifestGenerator - > PrepareToLoadNewPackage ( StandardFilename . ToString ( ) ) ;
}
for ( const auto & DependentPackage : Packages )
{
ManifestGenerator - > OnLastPackageLoaded ( DependentPackage ) ;
}
for ( const auto & DependentPackage : Packages )
{
FString Filename = GetCachedPackageFilename ( DependentPackage ) ;
if ( ! Filename . IsEmpty ( ) )
{
// Populate streaming install manifests
2014-12-01 16:53:12 -05:00
FString SandboxFilename = ConvertToFullSandboxPath ( * Filename , true ) ;
//UE_LOG(LogCook, Display, TEXT("Adding package to manifest %s, %s, %s"), *DependentPackage->GetName(), *SandboxFilename, *LastLoadedMapName);
2014-09-16 12:15:46 -04:00
ManifestGenerator - > AddPackageToChunkManifest ( DependentPackage , SandboxFilename , LastLoadedMapName , SandboxFile . GetOwnedPointer ( ) ) ;
}
}
}
}
2015-01-19 10:58:24 -05:00
bool UCookOnTheFlyServer : : IsCookingInEditor ( ) const
{
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-03-06 13:31:19 -05:00
COREUOBJECT_API extern bool GOutputCookingWarnings ;
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
2014-11-19 10:11:00 -05:00
static const FName AssetRegistryName ( " AssetRegistry " ) ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryName ) ;
2014-11-07 13:17:07 -05:00
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
2014-11-10 11:39:19 -05:00
if ( AssetRegistry . IsLoadingAssets ( ) )
2014-11-07 13:17:07 -05:00
{
// early out
return Result ;
}
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 ;
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
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 ) ;
}
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 ( ) )
{
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 ) )
{
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 )
{
for ( int I = 0 ; I < ObjectsInPackage . Num ( ) ; + + I )
{
const auto & Obj = ObjectsInPackage [ I ] ;
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 ;
}
}
return true ;
} ;
auto FinishPackageCacheForCookedPlatformData = [ & ] ( const TArray < UObject * > & ObjectsInPackage )
{
// if we get here and bIsAllDataCached is true then BeginCacheFOrCookedPlatformData has been called once on every object
// so now
CurrentReentryData . bBeginCacheFinished = true ;
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
if ( bIsAllDataCached & & ( CurrentCookMode = = ECookMode : : CookByTheBook ) )
{
// 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
if ( CookByTheBookOptions )
{
ACCUMULATE_TIMER_START ( AddUnassignedPackageToManifest ) ;
for ( const auto & TargetPlatform : AllTargetPlatformNames )
{
FChunkManifestGenerator * & Manifest = CookByTheBookOptions - > ManifestGenerators . FindChecked ( TargetPlatform ) ;
FString Filename = GetCachedPackageFilename ( Package ) ;
if ( ! Filename . IsEmpty ( ) )
{
// Populate streaming install manifests
2014-09-22 14:29:26 -04:00
const FString & SandboxFilename = GetCachedSandboxFilename ( Package , SandboxFile ) ;
2014-09-16 12:15:46 -04:00
Manifest - > AddUnassignedPackageToManifest ( Package , SandboxFilename ) ;
}
}
ACCUMULATE_TIMER_STOP ( AddUnassignedPackageToManifest ) ;
2014-08-18 16:20:23 -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
{
2014-09-16 12:15:46 -04:00
// check if the package has already been saved
2014-09-22 14:29:26 -04:00
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 ( ) )
{
SCOPE_TIMER ( SavingPackages ) ;
for ( int32 I = 0 ; I < PackagesToSave . Num ( ) ; + + I )
{
// 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
{
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
}
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 ;
}
}
2015-02-24 16:20:50 -05:00
{
SCOPE_TIMER ( GenerateManifestInfo ) ;
// update manifest with cooked package info
GenerateManifestInfo ( PackagesToSave [ I ] , AllTargetPlatformNames ) ;
}
2014-09-16 12:15:46 -04:00
UPackage * Package = PackagesToSave [ I ] ;
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 )
{
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( NextPackage , ObjectsInPackage ) ;
BeginPackageCacheForCookedPlatformData ( ObjectsInPackage ) ;
}
if ( NextNextPackage ! = NextPackage )
{
TArray < UObject * > ObjectsInPackage ;
GetObjectsWithOuter ( NextNextPackage , ObjectsInPackage ) ;
BeginPackageCacheForCookedPlatformData ( ObjectsInPackage ) ;
}
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
SCOPE_TIMER ( SaveCookedPackage ) ;
2015-03-06 13:31:19 -05:00
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
{
// Update flags used to determine garbage collection.
if ( Package - > ContainsMap ( ) )
{
Result | = COSR_CookedMap ;
}
else
{
+ + CookedPackageCount ;
Result | = COSR_CookedPackage ;
}
}
2015-01-22 20:35:27 -05:00
Timer . SavedPackage ( ) ;
2014-09-16 12:15:46 -04:00
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
2014-10-22 13:39:24 -04:00
CollectGarbage ( RF_Native ) ;
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 ( ) & &
( CookRequests . HasItems ( ) = = false ) )
{
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-01-29 17:25:52 -05:00
FString PackageFilename = GetCachedStandardPackageFilename ( Package ) ;
2015-01-19 10:58:24 -05:00
ClearPackageFilenameCacheForPackage ( Package ) ;
2014-12-01 16:53:12 -05:00
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Modification detected to package %s " ) , * PackageFilename ) ;
# endif
2014-10-22 13:37:17 -04:00
const FName PackageFFileName = FName ( * PackageFilename ) ;
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 ;
}
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 ;
UWorld * World = NULL ;
EObjectFlags Flags = RF_NoFlags ;
bool bPackageFullyLoaded = false ;
2014-09-16 12:15:46 -04:00
if ( IsCookFlagSet ( ECookInitializationFlags : : Compressed ) )
2014-04-23 18:33:25 -04:00
{
Package - > PackageFlags | = PKG_StoreCompressed ;
}
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
}
}
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 ;
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 ;
}
2014-11-18 15:49:39 -05:00
bool bDidInitializeWorld = false ;
2014-04-23 18:33:25 -04:00
if ( World )
{
World - > PersistentLevel - > OwningWorld = World ;
2014-10-10 10:31:37 -04:00
if ( ! World - > bIsWorldInitialized )
{
// we need to initialize the world - at least need physics scene since BP construction script runs during cooking, otherwise trace won't work
2015-01-14 10:56:48 -05:00
World - > InitWorld ( UWorld : : InitializationValues ( ) . RequiresHitProxies ( false ) . ShouldSimulatePhysics ( false ) . EnableTraceCollision ( false ) . CreateNavigation ( false ) . CreateAISystem ( false ) . AllowAudioPlayback ( false ) . CreatePhysicsScene ( true ) ) ;
2014-11-18 15:49:39 -05:00
bDidInitializeWorld = true ;
2014-10-10 10:31:37 -04:00
}
2014-04-23 18:33:25 -04:00
}
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 ) ;
2014-04-23 18:33:25 -04:00
}
2014-11-18 15:49:39 -05:00
// if we initialized the world we are responsible for cleaning it up.
if ( World & & World - > bIsWorldInitialized & & bDidInitializeWorld )
{
// Make sure we clean up the physics scene here. If we leave too many scenes in memory, undefined behavior occurs when locking a scene for read/write.
World - > SetPhysicsScene ( nullptr ) ;
if ( GPhysCommandHandler )
{
GPhysCommandHandler - > Flush ( ) ;
}
}
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
TArray < FString > FullGCAssetClassNames ;
GConfig - > GetArray ( TEXT ( " CookSettings " ) , TEXT ( " FullGCAssetClassNames " ) , FullGCAssetClassNames , GEditorIni ) ;
for ( const auto & FullGCAssetClassName : FullGCAssetClassNames )
{
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 ) ;
}
}
if ( FullGCAssetClasses . Num ( ) = = 0 )
{
// default to UWorld
FullGCAssetClasses . Add ( UWorld : : StaticClass ( ) ) ;
}
2014-04-23 18:33:25 -04:00
2014-09-16 12:15:46 -04:00
if ( IsCookByTheBookMode ( ) )
{
CookByTheBookOptions = new FCookByTheBookOptions ( ) ;
CookByTheBookOptions - > bGenerateStreamingInstallManifests = IsCookFlagSet ( ECookInitializationFlags : : GenerateStreamingInstallManifest ) ;
}
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 ) ) ;
}
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-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
{
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
{
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 ] ;
FString SandboxDirectory = GetSandboxDirectory ( Target - > PlatformName ( ) ) ;
FName PlatformFName ( * Target - > PlatformName ( ) ) ;
// use the timestamp grabbing visitor
IPlatformFile & PlatformFile = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
FLocalTimestampDirectoryVisitor Visitor ( PlatformFile , DirectoriesToSkip , DirectoriesToNotRecurse , false ) ;
PlatformFile . IterateDirectory ( * SandboxDirectory , Visitor ) ;
for ( TMap < FString , FDateTime > : : TIterator TimestampIt ( Visitor . FileTimes ) ; TimestampIt ; + + TimestampIt )
{
FString CookedFilename = TimestampIt . Key ( ) ;
FDateTime CookedTimestamp = TimestampIt . Value ( ) ;
2015-03-02 10:16:16 -05:00
CookedFilename = FPaths : : ConvertRelativePathToFull ( CookedFilename ) ;
2014-12-12 12:59:47 -05:00
FString StandardCookedFilename = CookedFilename . Replace ( * SandboxDirectory , * ( FPaths : : GetRelativePathToRoot ( ) ) ) ;
FDateTime DependentTimestamp ;
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 )
{
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 ;
// See what files are out of date in the sandbox folder
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 ( ) ) ;
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
2014-04-23 18:33:25 -04:00
PlatformFile . IterateDirectory ( * SandboxDirectory , Visitor ) ;
for ( TMap < FString , FDateTime > : : TIterator TimestampIt ( Visitor . FileTimes ) ; TimestampIt ; + + TimestampIt )
{
FString CookedFilename = TimestampIt . Key ( ) ;
FDateTime CookedTimestamp = TimestampIt . Value ( ) ;
FString StandardCookedFilename = CookedFilename . Replace ( * SandboxDirectory , * ( FPaths : : GetRelativePathToRoot ( ) ) ) ;
FDateTime DependentTimestamp ;
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
CookedPackages . RemoveFileForPlatform ( FName ( * StandardCookedFilename ) , PlatformFName ) ;
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
CollectGarbage ( RF_Native ) ;
}
}
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 )
{
// 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 ( ) ;
// editor will scan asset registry automagically
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
}
void UCookOnTheFlyServer : : GenerateLongPackageNames ( TArray < FString > & FilesInPath )
{
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 ) ;
}
2014-10-22 13:37:17 -04:00
void UCookOnTheFlyServer : : AddFileToCook ( TArray < FString > & InOutFilesToCook , const FString & InFilename ) const
{
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
2014-10-22 13:37:17 -04:00
InOutFilesToCook . AddUnique ( InFilename ) ;
2015-03-06 13:31:19 -05:00
# endif
2014-10-22 13:37:17 -04:00
}
}
2014-09-16 12:15:46 -04:00
void UCookOnTheFlyServer : : CollectFilesToCook ( TArray < FString > & FilesInPath , const TArray < FString > & CookMaps , const TArray < FString > & InCookDirectories , const TArray < FString > & CookCultures , const TArray < FString > & IniMapSections , bool bCookAll , bool bMapsOnly , bool bNoDev )
{
TArray < FString > CookDirectories = InCookDirectories ;
2014-12-10 15:23:55 -05:00
2014-12-12 12:59:47 -05:00
TArray < FString > MapList ;
// Add the default map section
GEditor - > LoadMapListFromIni ( TEXT ( " AlwaysCookMaps " ) , MapList ) ;
for ( const auto & IniMapSection : IniMapSections )
{
GEditor - > LoadMapListFromIni ( * IniMapSection , MapList ) ;
}
for ( int32 MapIdx = 0 ; MapIdx < MapList . Num ( ) ; MapIdx + + )
{
AddFileToCook ( FilesInPath , MapList [ MapIdx ] ) ;
}
2014-09-16 12:15:46 -04:00
// 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 ) ;
}
}
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
2014-12-10 10:12:47 -05: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 ;
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 ] ;
FPaths : : MakeStandardFilename ( StdFile ) ;
2014-10-22 13:37:17 -04:00
AddFileToCook ( FilesInPath , StdFile ) ;
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 ;
}
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 ) ;
{
// Save modified asset registry with all streaming chunk info generated during cook
2014-12-10 10:12:47 -05:00
const FString RegistryFilename = FPaths : : GameDir ( ) / TEXT ( " AssetRegistry.bin " ) ;
const FString SandboxRegistryFilename = ConvertToFullSandboxPath ( * RegistryFilename , true ) ;
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 )
{
// 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 ( ) ) ;
Manifest . Value - > SaveAssetRegistry ( SandboxRegistryFilename ) ;
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
}
}
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
CookByTheBookOptions - > bRunning = false ;
}
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 ( ) ;
if ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) )
{
PopulateCookedPackagesFromDisk ( TargetPlatforms ) ;
}
CleanSandbox ( IsCookFlagSet ( ECookInitializationFlags : : Iterative ) ) ;
}
}
void UCookOnTheFlyServer : : TermSandbox ( )
{
ClearAllCookedData ( ) ;
ClearPackageFilenameCache ( ) ;
SandboxFile = NULL ;
}
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 ( ) ) ;
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
2014-12-12 12:59:47 -05: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 ) ;
2014-12-01 11:58:48 -05:00
2014-09-16 12:15:46 -04:00
CookByTheBookOptions - > bRunning = true ;
2014-09-22 14:29:26 -04:00
CookByTheBookOptions - > bCancel = false ;
2014-09-16 12:15:46 -04:00
CookByTheBookOptions - > CookTime = 0.0f ;
2014-10-03 14:56:20 -04:00
CookByTheBookOptions - > CookStartTime = FPlatformTime : : Seconds ( ) ;
2014-12-10 10:12:47 -05:00
CookByTheBookOptions - > CreateReleaseVersion = CreateReleaseVersion ;
2014-09-16 12:15:46 -04:00
2014-10-22 13:37:17 -04:00
bool bCookAll = ( CookOptions & ECookByTheBookOptions : : CookAll ) ! = ECookByTheBookOptions : : None ;
bool bMapsOnly = ( CookOptions & ECookByTheBookOptions : : MapsOnly ) ! = ECookByTheBookOptions : : None ;
bool bNoDev = ( CookOptions & ECookByTheBookOptions : : NoDevContent ) ! = ECookByTheBookOptions : : None ;
CookByTheBookOptions - > bLeakTest = ( CookOptions & ECookByTheBookOptions : : LeakTest ) ! = ECookByTheBookOptions : : None ; // this won't work from the editor this needs to be standalone
check ( ! CookByTheBookOptions - > bLeakTest | | CurrentCookMode = = ECookMode : : CookByTheBook ) ;
2014-09-16 12:15:46 -04:00
CookByTheBookOptions - > LastGCItems . Empty ( ) ;
2014-10-22 13:37:17 -04:00
if ( CookByTheBookOptions - > bLeakTest )
2014-09-16 12:15:46 -04:00
{
for ( FObjectIterator It ; It ; + + It )
{
CookByTheBookOptions - > LastGCItems . Add ( FWeakObjectPtr ( * It ) ) ;
}
}
TArray < FName > TargetPlatformNames ;
for ( const auto & Platform : TargetPlatforms )
{
FName PlatformName = FName ( * Platform - > PlatformName ( ) ) ;
TargetPlatformNames . Add ( PlatformName ) ; // build list of all target platform names
// 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 ( ) ;
ManifestGenerator - > Initialize ( CookByTheBookOptions - > bGenerateStreamingInstallManifests ) ;
CookByTheBookOptions - > ManifestGenerators . Add ( PlatformName , ManifestGenerator ) ;
}
}
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 ( ) ;
TArray < FName > PackageFiles ;
// if this check fails probably because the asset registry can't be found or read
bool bSucceeded = GetAllPackagesFromAssetRegistry ( OriginalSandboxRegistryFilename , PackageFiles ) ;
check ( bSucceeded ) ;
if ( bSucceeded )
{
for ( const auto & PackageFilename : PackageFiles )
{
CookedPackages . Add ( MoveTemp ( FFilePlatformRequest ( PackageFilename , TargetPlatformNames ) ) ) ;
}
}
}
2014-12-01 16:53:12 -05:00
}
2014-12-10 10:12:47 -05:00
2014-12-01 16:53:12 -05:00
// allow the game to fill out the asset registry, as well as get a list of objects to always cook
TArray < FString > FilesInPath ;
FGameDelegates : : Get ( ) . GetCookModificationDelegate ( ) . ExecuteIfBound ( FilesInPath ) ;
2014-12-10 10:12:47 -05:00
// don't resave the global shader map files in dlc
if ( ! IsCookingDLC ( ) )
{
SaveGlobalShaderMapFiles ( TargetPlatforms ) ;
}
2014-12-01 16:53:12 -05:00
CollectFilesToCook ( FilesInPath , CookMaps , CookDirectories , CookCultures , IniMapSections , bCookAll , bMapsOnly , bNoDev ) ;
if ( FilesInPath . Num ( ) = = 0 )
{
LogCookerMessage ( FString : : Printf ( TEXT ( " No files found to cook. " ) ) , EMessageSeverity : : Warning ) ;
UE_LOG ( LogCook , Warning , TEXT ( " No files found. " ) ) ;
}
2014-09-16 12:15:46 -04:00
GenerateLongPackageNames ( FilesInPath ) ;
// add all the files for the requested platform to the cook list
2014-09-22 14:29:26 -04:00
for ( const auto & FileName : FilesInPath )
2014-09-16 12:15:46 -04:00
{
2014-09-22 14:29:26 -04:00
FName FileFName = FName ( * FileName ) ;
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
if ( ! IsCookingDLC ( ) )
{
// 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).
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 ( ) ;
2014-09-16 12:15:46 -04:00
}
2014-04-23 18:33:25 -04:00
/* UCookOnTheFlyServer callbacks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 ;
2014-10-14 14:38:00 -04:00
}