2020-06-23 18:40:00 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "CookPackageData.h"
2020-08-11 01:36:57 -04:00
# include "Algo/AnyOf.h"
2021-08-22 22:12:47 -04:00
# include "Algo/Count.h"
2021-12-04 16:14:37 -05:00
# include "Algo/Find.h"
2021-01-11 16:21:09 -04:00
# include "AssetCompilingManager.h"
2021-12-04 16:14:37 -05:00
# include "AssetRegistry/IAssetRegistry.h"
2021-08-31 17:28:15 -04:00
# include "Async/ParallelFor.h"
2021-08-31 14:20:48 -04:00
# include "Cooker/CookPlatformManager.h"
# include "Cooker/CookRequestCluster.h"
2020-06-23 18:40:00 -04:00
# include "CookOnTheSide/CookOnTheFlyServer.h"
# include "Containers/StringView.h"
2021-05-14 08:38:08 -04:00
# include "EditorDomain/EditorDomain.h"
2021-11-07 23:43:01 -05:00
# include "Engine/Console.h"
2021-05-11 21:03:22 -04:00
# include "HAL/FileManager.h"
2021-11-07 23:43:01 -05:00
# include "HAL/PlatformTime.h"
2021-11-18 14:37:34 -05:00
# include "Misc/CommandLine.h"
2020-06-23 18:40:00 -04:00
# include "Misc/CoreMiscDefines.h"
2021-11-23 21:16:10 -05:00
# include "Misc/PackageAccessTrackingOps.h"
2021-11-18 14:37:34 -05:00
# include "Misc/PackageName.h"
# include "Misc/Parse.h"
2020-06-23 18:40:00 -04:00
# include "Misc/Paths.h"
# include "Misc/PreloadableFile.h"
2021-12-06 13:24:26 -05:00
# include "Misc/ScopeExit.h"
2021-12-04 16:14:37 -05:00
# include "Misc/ScopeLock.h"
2020-06-23 18:40:00 -04:00
# include "ShaderCompiler.h"
# include "UObject/Object.h"
# include "UObject/Package.h"
2021-06-07 18:42:35 -04:00
# include "UObject/ReferenceChainSearch.h"
2020-06-23 18:40:00 -04:00
# include "UObject/UObjectGlobals.h"
# include "UObject/UObjectHash.h"
2021-12-04 16:14:37 -05:00
# include "UObject/ObjectRedirector.h"
2020-06-23 18:40:00 -04:00
2021-11-07 23:43:01 -05:00
namespace UE : : Cook
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
float GPollAsyncPeriod = .100f ;
static FAutoConsoleVariableRef CVarPollAsyncPeriod (
TEXT ( " cook.PollAsyncPeriod " ) ,
GPollAsyncPeriod ,
TEXT ( " Minimum time in seconds between PollPendingCookedPlatformDatas. " ) ,
ECVF_Default ) ;
2021-11-07 23:43:01 -05:00
2021-11-30 14:37:31 -05:00
//////////////////////////////////////////////////////////////////////////
// FPackageData
FPackageData : : FPlatformData : : FPlatformData ( )
2022-05-11 18:03:33 -04:00
: bRequested ( false ) , bCookAttempted ( false ) , bCookSucceeded ( false ) , bExplored ( false ) , bSaveTimedOut ( false )
2021-11-30 14:37:31 -05:00
{
}
FPackageData : : FPackageData ( FPackageDatas & PackageDatas , const FName & InPackageName , const FName & InFileName )
: GeneratedOwner ( nullptr ) , PackageName ( InPackageName ) , FileName ( InFileName ) , PackageDatas ( PackageDatas )
, Instigator ( EInstigator : : NotYetRequested ) , bIsUrgent ( 0 )
, bIsVisited ( 0 ) , bIsPreloadAttempted ( 0 )
, bIsPreloaded ( 0 ) , bHasSaveCache ( 0 ) , bHasBeginPrepareSaveFailed ( 0 ) , bCookedPlatformDataStarted ( 0 )
, bCookedPlatformDataCalled ( 0 ) , bCookedPlatformDataComplete ( 0 ) , bMonitorIsCooked ( 0 )
2022-04-25 08:36:56 -04:00
, bInitializedGeneratorSave ( 0 ) , bCompletedGeneration ( 0 ) , bGenerated ( 0 ) , bKeepReferencedDuringGC ( 0 )
2021-11-30 14:37:31 -05:00
{
SetState ( EPackageState : : Idle ) ;
SendToState ( EPackageState : : Idle , ESendFlags : : QueueAdd ) ;
}
FPackageData : : ~ FPackageData ( )
{
// ClearReferences should have been called earlier, but call it here in case it was missed
ClearReferences ( ) ;
// We need to send OnLastCookedPlatformRemoved message to the monitor, so call SetPlatformsNotCooked
2022-02-07 01:52:26 -05:00
ClearCookProgress ( ) ;
2021-11-30 14:37:31 -05:00
// Update the monitor's counters and call exit functions
SendToState ( EPackageState : : Idle , ESendFlags : : QueueNone ) ;
}
void FPackageData : : ClearReferences ( )
{
DestroyGeneratorPackage ( ) ;
}
const FName & FPackageData : : GetPackageName ( ) const
{
return PackageName ;
}
const FName & FPackageData : : GetFileName ( ) const
{
return FileName ;
}
void FPackageData : : SetFileName ( const FName & InFileName )
{
FileName = InFileName ;
}
int32 FPackageData : : GetNumRequestedPlatforms ( ) const
{
int32 Result = 0 ;
for ( const TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
2021-08-22 22:12:47 -04:00
{
2021-11-30 14:37:31 -05:00
Result + = Pair . Value . bRequested ? 1 : 0 ;
}
return Result ;
}
void FPackageData : : SetPlatformsRequested ( TConstArrayView < const ITargetPlatform * > TargetPlatforms , bool bRequested )
{
for ( const ITargetPlatform * TargetPlatform : TargetPlatforms )
{
PlatformDatas . FindOrAdd ( TargetPlatform ) . bRequested = true ;
}
}
void FPackageData : : ClearRequestedPlatforms ( )
{
for ( TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
{
Pair . Value . bRequested = false ;
}
}
bool FPackageData : : HasAllRequestedPlatforms ( const TArrayView < const ITargetPlatform * const > & Platforms ) const
{
if ( Platforms . Num ( ) = = 0 )
{
return true ;
}
if ( PlatformDatas . Num ( ) = = 0 )
{
return false ;
2021-08-22 22:12:47 -04:00
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
for ( const ITargetPlatform * QueryPlatform : Platforms )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
const FPlatformData * PlatformData = PlatformDatas . Find ( QueryPlatform ) ;
if ( ! PlatformData | | ! PlatformData - > bRequested )
2020-06-23 18:40:00 -04:00
{
return false ;
}
2021-08-22 22:12:47 -04:00
}
2021-11-30 14:37:31 -05:00
return true ;
}
2021-08-22 22:12:47 -04:00
2021-11-30 14:37:31 -05:00
bool FPackageData : : AreAllRequestedPlatformsCooked ( bool bAllowFailedCooks ) const
{
for ( const TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
2021-08-22 22:12:47 -04:00
{
2021-11-30 14:37:31 -05:00
if ( Pair . Value . bRequested & & ( ! Pair . Value . bCookAttempted | | ( ! bAllowFailedCooks & & ! Pair . Value . bCookSucceeded ) ) )
2021-08-31 14:20:48 -04:00
{
return false ;
}
2021-11-30 14:37:31 -05:00
}
return true ;
}
2021-08-31 14:20:48 -04:00
2021-11-30 14:37:31 -05:00
bool FPackageData : : AreAllRequestedPlatformsExplored ( ) const
{
for ( const TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
{
if ( Pair . Value . bRequested & & ! Pair . Value . bExplored )
2021-08-31 14:20:48 -04:00
{
2021-11-30 14:37:31 -05:00
return false ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
}
return true ;
}
bool FPackageData : : HasAllExploredPlatforms ( const TArrayView < const ITargetPlatform * const > & Platforms ) const
{
if ( Platforms . Num ( ) = = 0 )
{
2020-06-23 18:40:00 -04:00
return true ;
}
2021-11-30 14:37:31 -05:00
if ( PlatformDatas . Num ( ) = = 0 )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
return false ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
for ( const ITargetPlatform * QueryPlatform : Platforms )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
const FPlatformData * PlatformData = FindPlatformData ( QueryPlatform ) ;
if ( ! PlatformData | | ! PlatformData - > bExplored )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
return false ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
return true ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
void FPackageData : : SetIsUrgent ( bool Value )
{
bool OldValue = static_cast < bool > ( bIsUrgent ) ;
if ( OldValue ! = Value )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
bIsUrgent = Value ! = 0 ;
PackageDatas . GetMonitor ( ) . OnUrgencyChanged ( * this ) ;
}
}
2021-08-22 22:12:47 -04:00
2021-11-30 14:37:31 -05:00
void FPackageData : : UpdateRequestData ( const TConstArrayView < const ITargetPlatform * > InRequestedPlatforms ,
bool bInIsUrgent , FCompletionCallback & & InCompletionCallback , FInstigator & & InInstigator , bool bAllowUpdateUrgency )
{
if ( IsInProgress ( ) )
{
2020-06-23 18:40:00 -04:00
AddCompletionCallback ( MoveTemp ( InCompletionCallback ) ) ;
2021-11-30 14:37:31 -05:00
bool bUrgencyChanged = false ;
if ( bInIsUrgent & & ! GetIsUrgent ( ) )
2021-11-07 23:43:01 -05:00
{
2021-11-30 14:37:31 -05:00
bUrgencyChanged = true ;
SetIsUrgent ( true ) ;
2021-11-07 23:43:01 -05:00
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
if ( ! HasAllRequestedPlatforms ( InRequestedPlatforms ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
// Send back to the Request state (canceling any current operations) and then add the new platforms
if ( GetState ( ) ! = EPackageState : : Request )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
SendToState ( EPackageState : : Request , ESendFlags : : QueueAddAndRemove ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
SetPlatformsRequested ( InRequestedPlatforms , true ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
else if ( bUrgencyChanged & & bAllowUpdateUrgency )
2021-08-31 14:20:48 -04:00
{
2021-11-30 14:37:31 -05:00
SendToState ( GetState ( ) , ESendFlags : : QueueAddAndRemove ) ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
else if ( InRequestedPlatforms . Num ( ) > 0 )
2020-06-23 18:40:00 -04:00
{
2022-01-10 11:09:44 -05:00
SetRequestData ( InRequestedPlatforms , bInIsUrgent , MoveTemp ( InCompletionCallback ) , MoveTemp ( InInstigator ) ) ;
2021-11-30 14:37:31 -05:00
SendToState ( EPackageState : : Request , ESendFlags : : QueueAddAndRemove ) ;
}
}
void FPackageData : : SetRequestData ( const TArrayView < const ITargetPlatform * const > & InRequestedPlatforms ,
bool bInIsUrgent , FCompletionCallback & & InCompletionCallback , FInstigator & & InInstigator )
{
check ( ! CompletionCallback ) ;
check ( GetNumRequestedPlatforms ( ) = = 0 )
check ( ! bIsUrgent ) ;
check ( InRequestedPlatforms . Num ( ) ! = 0 ) ;
SetPlatformsRequested ( InRequestedPlatforms , true ) ;
SetIsUrgent ( bInIsUrgent ) ;
AddCompletionCallback ( MoveTemp ( InCompletionCallback ) ) ;
if ( Instigator . Category = = EInstigator : : NotYetRequested )
{
2022-05-23 10:13:54 -04:00
OnPackageDataFirstRequested ( MoveTemp ( InInstigator ) ) ;
2021-11-30 14:37:31 -05:00
}
}
void FPackageData : : ClearInProgressData ( )
{
ClearRequestedPlatforms ( ) ;
SetIsUrgent ( false ) ;
CompletionCallback = FCompletionCallback ( ) ;
}
void FPackageData : : SetPlatformsCooked ( const TConstArrayView < const ITargetPlatform * > TargetPlatforms ,
const TConstArrayView < bool > Succeeded )
{
check ( TargetPlatforms . Num ( ) = = Succeeded . Num ( ) ) ;
for ( int32 n = 0 ; n < TargetPlatforms . Num ( ) ; + + n )
{
SetPlatformCooked ( TargetPlatforms [ n ] , Succeeded [ n ] ) ;
}
}
void FPackageData : : SetPlatformsCooked ( const TConstArrayView < const ITargetPlatform * > TargetPlatforms ,
bool bSucceeded )
{
for ( const ITargetPlatform * TargetPlatform : TargetPlatforms )
{
SetPlatformCooked ( TargetPlatform , bSucceeded ) ;
}
}
void FPackageData : : SetPlatformCooked ( const ITargetPlatform * TargetPlatform , bool bSucceeded )
{
bool bHasAnyOthers = false ;
bool bModified = false ;
bool bExists = false ;
for ( TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
{
if ( Pair . Key = = TargetPlatform )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
bExists = true ;
bModified = bModified | ( Pair . Value . bCookAttempted = = false ) ;
Pair . Value . bCookAttempted = true ;
Pair . Value . bCookSucceeded = bSucceeded ;
2022-05-11 18:03:33 -04:00
// Clear the SaveTimedOut when get a cook result, in case we save again later and need to allow retry again
Pair . Value . bSaveTimedOut = false ;
2021-11-30 14:37:31 -05:00
}
else
{
bHasAnyOthers = bHasAnyOthers | ( Pair . Value . bCookAttempted ! = false ) ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
if ( ! bExists )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
FPlatformData & Value = PlatformDatas . FindOrAdd ( TargetPlatform ) ;
Value . bCookAttempted = true ;
Value . bCookSucceeded = bSucceeded ;
2022-05-11 18:03:33 -04:00
Value . bSaveTimedOut = false ;
2021-11-30 14:37:31 -05:00
bModified = true ;
}
if ( bModified & & ! bHasAnyOthers )
{
PackageDatas . GetMonitor ( ) . OnFirstCookedPlatformAdded ( * this ) ;
}
}
2022-02-07 01:52:26 -05:00
void FPackageData : : ClearCookProgress ( const TConstArrayView < const ITargetPlatform * > TargetPlatforms )
2021-11-30 14:37:31 -05:00
{
for ( const ITargetPlatform * TargetPlatform : TargetPlatforms )
{
2022-02-07 01:52:26 -05:00
ClearCookProgress ( TargetPlatform ) ;
2021-11-30 14:37:31 -05:00
}
}
2022-02-07 01:52:26 -05:00
void FPackageData : : ClearCookProgress ( )
2021-11-30 14:37:31 -05:00
{
2022-02-07 01:52:26 -05:00
bool bModifiedCookAttempted = false ;
2021-11-30 14:37:31 -05:00
for ( TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
{
2022-02-07 01:52:26 -05:00
bModifiedCookAttempted = bModifiedCookAttempted | ( Pair . Value . bCookAttempted ! = false ) ;
2021-11-30 14:37:31 -05:00
Pair . Value . bCookAttempted = false ;
Pair . Value . bCookSucceeded = false ;
2022-02-07 01:52:26 -05:00
Pair . Value . bExplored = false ;
2022-05-11 18:03:33 -04:00
Pair . Value . bSaveTimedOut = false ;
2021-11-30 14:37:31 -05:00
}
2022-02-07 01:52:26 -05:00
if ( bModifiedCookAttempted )
2021-11-30 14:37:31 -05:00
{
PackageDatas . GetMonitor ( ) . OnLastCookedPlatformRemoved ( * this ) ;
}
}
2022-02-07 01:52:26 -05:00
void FPackageData : : ClearCookProgress ( const ITargetPlatform * TargetPlatform )
2021-11-30 14:37:31 -05:00
{
bool bHasAnyOthers = false ;
2022-02-07 01:52:26 -05:00
bool bModifiedCookAttempted = false ;
2021-11-30 14:37:31 -05:00
for ( TPair < const ITargetPlatform * , FPlatformData > & Pair : PlatformDatas )
{
if ( Pair . Key = = TargetPlatform )
2021-08-22 22:12:47 -04:00
{
2022-02-07 01:52:26 -05:00
bModifiedCookAttempted = bModifiedCookAttempted | ( Pair . Value . bCookAttempted ! = false ) ;
2021-08-22 22:12:47 -04:00
Pair . Value . bCookAttempted = false ;
Pair . Value . bCookSucceeded = false ;
2022-02-07 01:52:26 -05:00
Pair . Value . bExplored = false ;
2022-05-11 18:03:33 -04:00
Pair . Value . bSaveTimedOut = false ;
2021-08-22 22:12:47 -04:00
}
2021-11-30 14:37:31 -05:00
else
2021-08-22 22:12:47 -04:00
{
2021-11-30 14:37:31 -05:00
bHasAnyOthers = bHasAnyOthers | ( Pair . Value . bCookAttempted ! = false ) ;
2021-08-22 22:12:47 -04:00
}
2020-06-23 18:40:00 -04:00
}
2022-02-07 01:52:26 -05:00
if ( bModifiedCookAttempted & & ! bHasAnyOthers )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
PackageDatas . GetMonitor ( ) . OnLastCookedPlatformRemoved ( * this ) ;
2021-08-22 22:12:47 -04:00
}
2021-11-30 14:37:31 -05:00
}
2021-08-22 22:12:47 -04:00
2021-11-30 14:37:31 -05:00
const TSortedMap < const ITargetPlatform * , FPackageData : : FPlatformData > & FPackageData : : GetPlatformDatas ( ) const
{
return PlatformDatas ;
}
FPackageData : : FPlatformData & FPackageData : : FindOrAddPlatformData ( const ITargetPlatform * TargetPlatform )
{
return PlatformDatas . FindOrAdd ( TargetPlatform ) ;
}
FPackageData : : FPlatformData * FPackageData : : FindPlatformData ( const ITargetPlatform * TargetPlatform )
{
return PlatformDatas . Find ( TargetPlatform ) ;
}
const FPackageData : : FPlatformData * FPackageData : : FindPlatformData ( const ITargetPlatform * TargetPlatform ) const
{
return PlatformDatas . Find ( TargetPlatform ) ;
}
bool FPackageData : : HasAnyCookedPlatform ( ) const
{
return Algo : : AnyOf ( PlatformDatas ,
[ ] ( const TPair < const ITargetPlatform * , FPlatformData > & Pair ) { return Pair . Value . bCookAttempted ; } ) ;
}
bool FPackageData : : HasAnyCookedPlatforms ( const TArrayView < const ITargetPlatform * const > & Platforms ,
bool bIncludeFailed ) const
{
if ( PlatformDatas . Num ( ) = = 0 )
2021-08-22 22:12:47 -04:00
{
2020-06-23 18:40:00 -04:00
return false ;
}
2021-11-30 14:37:31 -05:00
for ( const ITargetPlatform * QueryPlatform : Platforms )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
if ( HasCookedPlatform ( QueryPlatform , bIncludeFailed ) )
2020-06-23 18:40:00 -04:00
{
return true ;
}
2021-11-30 14:37:31 -05:00
}
return false ;
}
bool FPackageData : : HasAllCookedPlatforms ( const TArrayView < const ITargetPlatform * const > & Platforms ,
bool bIncludeFailed ) const
{
if ( Platforms . Num ( ) = = 0 )
{
return true ;
}
if ( PlatformDatas . Num ( ) = = 0 )
{
return false ;
}
for ( const ITargetPlatform * QueryPlatform : Platforms )
{
if ( ! HasCookedPlatform ( QueryPlatform , bIncludeFailed ) )
2020-06-23 18:40:00 -04:00
{
return false ;
}
2021-11-30 14:37:31 -05:00
}
return true ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
bool FPackageData : : HasCookedPlatform ( const ITargetPlatform * Platform , bool bIncludeFailed ) const
{
ECookResult Result = GetCookResults ( Platform ) ;
return ( Result = = ECookResult : : Succeeded ) | ( ( Result = = ECookResult : : Failed ) & ( bIncludeFailed ! = 0 ) ) ;
}
ECookResult FPackageData : : GetCookResults ( const ITargetPlatform * Platform ) const
{
const FPlatformData * PlatformData = PlatformDatas . Find ( Platform ) ;
if ( PlatformData & & PlatformData - > bCookAttempted )
{
return PlatformData - > bCookSucceeded ? ECookResult : : Succeeded : ECookResult : : Failed ;
}
return ECookResult : : Unseen ;
}
UPackage * FPackageData : : GetPackage ( ) const
{
return Package . Get ( ) ;
}
void FPackageData : : SetPackage ( UPackage * InPackage )
{
Package = InPackage ;
}
EPackageState FPackageData : : GetState ( ) const
{
return static_cast < EPackageState > ( State ) ;
}
/** Boilerplate-reduction struct that defines all multi-state properties and sets them based on the given state. */
struct FStateProperties
{
EPackageStateProperty Properties ;
explicit FStateProperties ( EPackageState InState )
{
switch ( InState )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
case EPackageState : : Idle :
Properties = EPackageStateProperty : : None ;
break ;
case EPackageState : : Request :
Properties = EPackageStateProperty : : InProgress ;
break ;
case EPackageState : : LoadPrepare :
Properties = EPackageStateProperty : : InProgress | EPackageStateProperty : : Loading ;
break ;
case EPackageState : : LoadReady :
Properties = EPackageStateProperty : : InProgress | EPackageStateProperty : : Loading ;
break ;
// TODO_SaveQueue: When we add state PrepareForSave, it will also have bHasPackage = true,
case EPackageState : : Save :
Properties = EPackageStateProperty : : InProgress | EPackageStateProperty : : HasPackage ;
break ;
default :
check ( false ) ;
Properties = EPackageStateProperty : : None ;
break ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
} ;
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
void FPackageData : : SendToState ( EPackageState NextState , ESendFlags SendFlags )
{
EPackageState OldState = GetState ( ) ;
switch ( OldState )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
case EPackageState : : Idle :
OnExitIdle ( ) ;
break ;
case EPackageState : : Request :
if ( ! ! ( SendFlags & ESendFlags : : QueueRemove ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
ensure ( PackageDatas . GetRequestQueue ( ) . Remove ( this ) = = 1 ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
OnExitRequest ( ) ;
break ;
case EPackageState : : LoadPrepare :
if ( ! ! ( SendFlags & ESendFlags : : QueueRemove ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
ensure ( PackageDatas . GetLoadPrepareQueue ( ) . Remove ( this ) = = 1 ) ;
}
OnExitLoadPrepare ( ) ;
break ;
case EPackageState : : LoadReady :
if ( ! ! ( SendFlags & ESendFlags : : QueueRemove ) )
{
ensure ( PackageDatas . GetLoadReadyQueue ( ) . Remove ( this ) = = 1 ) ;
}
OnExitLoadReady ( ) ;
break ;
case EPackageState : : Save :
if ( ! ! ( SendFlags & ESendFlags : : QueueRemove ) )
{
ensure ( PackageDatas . GetSaveQueue ( ) . Remove ( this ) = = 1 ) ;
}
OnExitSave ( ) ;
break ;
default :
check ( false ) ;
break ;
}
FStateProperties OldProperties ( OldState ) ;
FStateProperties NewProperties ( NextState ) ;
// Exit state properties from highest to lowest; enter state properties from lowest to highest.
// This ensures that properties that rely on earlier properties are constructed later and torn down earlier
// than the earlier properties.
for ( EPackageStateProperty Iterator = EPackageStateProperty : : Max ;
Iterator > = EPackageStateProperty : : Min ;
Iterator = static_cast < EPackageStateProperty > ( static_cast < uint32 > ( Iterator ) > > 1 ) )
{
if ( ( ( OldProperties . Properties & Iterator ) ! = EPackageStateProperty : : None ) &
( ( NewProperties . Properties & Iterator ) = = EPackageStateProperty : : None ) )
{
switch ( Iterator )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
case EPackageStateProperty : : InProgress :
OnExitInProgress ( ) ;
2020-06-23 18:40:00 -04:00
break ;
2021-11-30 14:37:31 -05:00
case EPackageStateProperty : : Loading :
OnExitLoading ( ) ;
2020-06-23 18:40:00 -04:00
break ;
2021-11-30 14:37:31 -05:00
case EPackageStateProperty : : HasPackage :
OnExitHasPackage ( ) ;
2020-06-23 18:40:00 -04:00
break ;
default :
check ( false ) ;
break ;
}
}
2021-11-30 14:37:31 -05:00
}
for ( EPackageStateProperty Iterator = EPackageStateProperty : : Min ;
Iterator < = EPackageStateProperty : : Max ;
Iterator = static_cast < EPackageStateProperty > ( static_cast < uint32 > ( Iterator ) < < 1 ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
if ( ( ( OldProperties . Properties & Iterator ) = = EPackageStateProperty : : None ) &
( ( NewProperties . Properties & Iterator ) ! = EPackageStateProperty : : None ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
switch ( Iterator )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
case EPackageStateProperty : : InProgress :
OnEnterInProgress ( ) ;
break ;
case EPackageStateProperty : : Loading :
OnEnterLoading ( ) ;
break ;
case EPackageStateProperty : : HasPackage :
OnEnterHasPackage ( ) ;
break ;
default :
check ( false ) ;
break ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
}
SetState ( NextState ) ;
switch ( NextState )
{
case EPackageState : : Idle :
OnEnterIdle ( ) ;
break ;
case EPackageState : : Request :
OnEnterRequest ( ) ;
if ( ( ( SendFlags & ESendFlags : : QueueAdd ) ! = ESendFlags : : QueueNone ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
PackageDatas . GetRequestQueue ( ) . AddRequest ( this ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
break ;
case EPackageState : : LoadPrepare :
OnEnterLoadPrepare ( ) ;
if ( ( SendFlags & ESendFlags : : QueueAdd ) ! = ESendFlags : : QueueNone )
2020-06-23 18:40:00 -04:00
{
if ( GetIsUrgent ( ) )
{
2021-11-30 14:37:31 -05:00
PackageDatas . GetLoadPrepareQueue ( ) . AddFront ( this ) ;
2020-06-23 18:40:00 -04:00
}
else
{
2021-11-30 14:37:31 -05:00
PackageDatas . GetLoadPrepareQueue ( ) . Add ( this ) ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
break ;
case EPackageState : : LoadReady :
OnEnterLoadReady ( ) ;
if ( ( SendFlags & ESendFlags : : QueueAdd ) ! = ESendFlags : : QueueNone )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
if ( GetIsUrgent ( ) )
{
PackageDatas . GetLoadReadyQueue ( ) . AddFront ( this ) ;
}
else
{
PackageDatas . GetLoadReadyQueue ( ) . Add ( this ) ;
}
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
break ;
case EPackageState : : Save :
OnEnterSave ( ) ;
if ( ( ( SendFlags & ESendFlags : : QueueAdd ) ! = ESendFlags : : QueueNone ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
if ( GetIsUrgent ( ) )
{
PackageDatas . GetSaveQueue ( ) . AddFront ( this ) ;
}
else
{
PackageDatas . GetSaveQueue ( ) . Add ( this ) ;
}
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
break ;
default :
check ( false ) ;
break ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
PackageDatas . GetMonitor ( ) . OnStateChanged ( * this , OldState ) ;
}
void FPackageData : : CheckInContainer ( ) const
{
switch ( GetState ( ) )
{
case EPackageState : : Idle :
break ;
case EPackageState : : Request :
check ( PackageDatas . GetRequestQueue ( ) . Contains ( this ) ) ;
break ;
case EPackageState : : LoadPrepare :
check ( PackageDatas . GetLoadPrepareQueue ( ) . Contains ( this ) ) ;
break ;
case EPackageState : : LoadReady :
check ( Algo : : Find ( PackageDatas . GetLoadReadyQueue ( ) , this ) ! = nullptr ) ;
break ;
case EPackageState : : Save :
// The save queue is huge and often pushed at end. Check last element first and then scan.
check ( PackageDatas . GetSaveQueue ( ) . Num ( ) & & ( PackageDatas . GetSaveQueue ( ) . Last ( ) = = this | | Algo : : Find ( PackageDatas . GetSaveQueue ( ) , this ) ) ) ;
break ;
default :
check ( false ) ;
break ;
}
}
bool FPackageData : : IsInProgress ( ) const
{
return IsInStateProperty ( EPackageStateProperty : : InProgress ) ;
}
bool FPackageData : : IsInStateProperty ( EPackageStateProperty Property ) const
{
return ( FStateProperties ( GetState ( ) ) . Properties & Property ) ! = EPackageStateProperty : : None ;
}
void FPackageData : : OnEnterIdle ( )
{
// Note that this might be on construction of the PackageData
}
void FPackageData : : OnExitIdle ( )
{
if ( PackageDatas . GetLogDiscoveredPackages ( ) )
{
UE_LOG ( LogCook , Warning , TEXT ( " Missing dependency: Package %s discovered after initial dependency search. " ) , * WriteToString < 256 > ( PackageName ) ) ;
}
}
void FPackageData : : OnEnterRequest ( )
{
// It is not valid to enter the request state without requested platforms; it indicates a bug due to e.g.
// calling SendToState without UpdateRequestData from Idle
check ( GetNumRequestedPlatforms ( ) > 0 ) ;
}
void FPackageData : : OnExitRequest ( )
{
}
void FPackageData : : OnEnterLoadPrepare ( )
{
}
void FPackageData : : OnExitLoadPrepare ( )
{
}
void FPackageData : : OnEnterLoadReady ( )
{
}
void FPackageData : : OnExitLoadReady ( )
{
}
void FPackageData : : OnEnterSave ( )
{
check ( GetPackage ( ) ! = nullptr & & GetPackage ( ) - > IsFullyLoaded ( ) ) ;
check ( ! GetHasBeginPrepareSaveFailed ( ) ) ;
CheckObjectCacheEmpty ( ) ;
CheckCookedPlatformDataEmpty ( ) ;
}
void FPackageData : : OnExitSave ( )
{
PackageDatas . GetCookOnTheFlyServer ( ) . ReleaseCookedPlatformData ( * this , false /* bCompletedSave */ ) ;
ClearObjectCache ( ) ;
SetHasBeginPrepareSaveFailed ( false ) ;
}
void FPackageData : : OnEnterInProgress ( )
{
PackageDatas . GetMonitor ( ) . OnInProgressChanged ( * this , true ) ;
}
void FPackageData : : OnExitInProgress ( )
{
PackageDatas . GetMonitor ( ) . OnInProgressChanged ( * this , false ) ;
UE : : Cook : : FCompletionCallback LocalCompletionCallback ( MoveTemp ( GetCompletionCallback ( ) ) ) ;
if ( LocalCompletionCallback )
{
LocalCompletionCallback ( this ) ;
}
ClearInProgressData ( ) ;
}
void FPackageData : : OnEnterLoading ( )
{
CheckPreloadEmpty ( ) ;
}
void FPackageData : : OnExitLoading ( )
{
ClearPreload ( ) ;
}
void FPackageData : : OnEnterHasPackage ( )
{
}
void FPackageData : : OnExitHasPackage ( )
{
SetPackage ( nullptr ) ;
}
2022-05-23 10:13:54 -04:00
void FPackageData : : OnPackageDataFirstRequested ( FInstigator & & InInstigator )
{
TracePackage ( GetPackageName ( ) . ToUnstableInt ( ) , GetPackageName ( ) . ToString ( ) ) ;
Instigator = MoveTemp ( InInstigator ) ;
PackageDatas . DebugInstigator ( * this ) ;
}
2021-11-30 14:37:31 -05:00
void FPackageData : : SetState ( EPackageState NextState )
{
State = static_cast < uint32 > ( NextState ) ;
}
FCompletionCallback & FPackageData : : GetCompletionCallback ( )
{
return CompletionCallback ;
}
void FPackageData : : AddCompletionCallback ( FCompletionCallback & & InCompletionCallback )
{
if ( InCompletionCallback )
{
// We don't yet have a mechanism for calling two completion callbacks.
// CompletionCallbacks only come from external requests, and it should not be possible to request twice,
// so a failed check here shouldn't happen.
check ( ! CompletionCallback ) ;
CompletionCallback = MoveTemp ( InCompletionCallback ) ;
}
}
bool FPackageData : : TryPreload ( )
{
check ( IsInStateProperty ( EPackageStateProperty : : Loading ) ) ;
if ( GetIsPreloadAttempted ( ) )
{
return true ;
}
if ( FindObjectFast < UPackage > ( nullptr , GetPackageName ( ) ) )
{
// If the package has already loaded, then there is no point in further preloading
ClearPreload ( ) ;
2020-06-23 18:40:00 -04:00
SetIsPreloadAttempted ( true ) ;
return true ;
}
2021-11-30 14:37:31 -05:00
if ( IsGenerated ( ) )
2021-03-04 11:12:34 -04:00
{
2021-11-30 14:37:31 -05:00
// Deferred populate generated packages are loaded from their generator, not from disk
ClearPreload ( ) ;
SetIsPreloadAttempted ( true ) ;
return true ;
2021-03-04 11:12:34 -04:00
}
2021-11-30 14:37:31 -05:00
if ( ! PreloadableFile . Get ( ) )
2021-03-04 11:12:34 -04:00
{
2021-11-30 14:37:31 -05:00
if ( FEditorDomain * EditorDomain = FEditorDomain : : Get ( ) )
2021-03-04 11:12:34 -04:00
{
2021-11-30 14:37:31 -05:00
EditorDomain - > PrecachePackageDigest ( GetPackageName ( ) ) ;
2021-03-04 11:12:34 -04:00
}
2021-11-30 14:37:31 -05:00
TStringBuilder < NAME_SIZE > FileNameString ;
GetFileName ( ) . ToString ( FileNameString ) ;
PreloadableFile . Set ( MakeShared < FPreloadableArchive > ( FileNameString . ToString ( ) ) , * this ) ;
PreloadableFile . Get ( ) - > InitializeAsync ( [ this ] ( )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
TStringBuilder < NAME_SIZE > FileNameString ;
// Note this async callback has an read of this->GetFilename and a write of PreloadableFileOpenResult
// outside of a critical section. This read and write is allowed because GetFilename does
// not change until this is destructed, and the destructor does not run and other threads do not read
// or write PreloadableFileOpenResult until after PreloadableFile.Get() has finished initialization
// and this callback is therefore complete.
// The code that accomplishes that waiting is in TryPreload (IsInitialized) and ClearPreload (ReleaseCache)
this - > GetFileName ( ) . ToString ( FileNameString ) ;
FPackagePath PackagePath = FPackagePath : : FromLocalPath ( FileNameString ) ;
FOpenPackageResult Result = IPackageResourceManager : : Get ( ) . OpenReadPackage ( PackagePath ) ;
if ( Result . Archive )
{
this - > PreloadableFileOpenResult . CopyMetaData ( Result ) ;
}
return Result . Archive . Release ( ) ;
} ,
FPreloadableFile : : Flags : : PreloadHandle | FPreloadableFile : : Flags : : Prime ) ;
}
const TSharedPtr < FPreloadableArchive > & FilePtr = PreloadableFile . Get ( ) ;
if ( ! FilePtr - > IsInitialized ( ) )
{
if ( GetIsUrgent ( ) )
{
// For urgent requests, wait on them to finish preloading rather than letting them run asynchronously
// and coming back to them later
FilePtr - > WaitForInitialization ( ) ;
check ( FilePtr - > IsInitialized ( ) ) ;
2020-06-23 18:40:00 -04:00
}
else
{
return false ;
}
}
2021-11-30 14:37:31 -05:00
if ( FilePtr - > TotalSize ( ) < 0 )
2021-04-28 07:45:12 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " Failed to find file when preloading %s. " ) , * GetFileName ( ) . ToString ( ) ) ;
SetIsPreloadAttempted ( true ) ;
PreloadableFile . Reset ( * this ) ;
PreloadableFileOpenResult = FOpenPackageResult ( ) ;
2021-04-28 07:45:12 -04:00
return true ;
}
2021-11-30 14:37:31 -05:00
TStringBuilder < NAME_SIZE > FileNameString ;
GetFileName ( ) . ToString ( FileNameString ) ;
if ( ! IPackageResourceManager : : TryRegisterPreloadableArchive ( FPackagePath : : FromLocalPath ( FileNameString ) ,
FilePtr , PreloadableFileOpenResult ) )
2020-11-30 11:57:28 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " Failed to register %s for preload. " ) , * GetFileName ( ) . ToString ( ) ) ;
SetIsPreloadAttempted ( true ) ;
PreloadableFile . Reset ( * this ) ;
PreloadableFileOpenResult = FOpenPackageResult ( ) ;
return true ;
}
SetIsPreloaded ( true ) ;
SetIsPreloadAttempted ( true ) ;
return true ;
}
void FPackageData : : FTrackedPreloadableFilePtr : : Set ( TSharedPtr < FPreloadableArchive > & & InPtr , FPackageData & Owner )
{
Reset ( Owner ) ;
if ( InPtr )
{
Ptr = MoveTemp ( InPtr ) ;
Owner . PackageDatas . GetMonitor ( ) . OnPreloadAllocatedChanged ( Owner , true ) ;
}
}
void FPackageData : : FTrackedPreloadableFilePtr : : Reset ( FPackageData & Owner )
{
if ( Ptr )
{
Owner . PackageDatas . GetMonitor ( ) . OnPreloadAllocatedChanged ( Owner , false ) ;
Ptr . Reset ( ) ;
}
}
void FPackageData : : ClearPreload ( )
{
const TSharedPtr < FPreloadableArchive > & FilePtr = PreloadableFile . Get ( ) ;
if ( GetIsPreloaded ( ) )
{
check ( FilePtr ) ;
TStringBuilder < NAME_SIZE > FileNameString ;
GetFileName ( ) . ToString ( FileNameString ) ;
if ( IPackageResourceManager : : UnRegisterPreloadableArchive ( FPackagePath : : FromLocalPath ( FileNameString ) ) )
2020-11-30 11:57:28 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Display , TEXT ( " PreloadableFile was created for %s but never used. This is wasteful and bad for cook performance. " ) ,
* PackageName . ToString ( ) ) ;
}
FilePtr - > ReleaseCache ( ) ; // ReleaseCache to conserve memory if the Linker still has a pointer to it
}
else
{
check ( ! FilePtr | | ! FilePtr - > IsCacheAllocated ( ) ) ;
}
PreloadableFile . Reset ( * this ) ;
PreloadableFileOpenResult = FOpenPackageResult ( ) ;
SetIsPreloaded ( false ) ;
SetIsPreloadAttempted ( false ) ;
}
void FPackageData : : CheckPreloadEmpty ( )
{
check ( ! GetIsPreloadAttempted ( ) ) ;
check ( ! PreloadableFile . Get ( ) ) ;
check ( ! GetIsPreloaded ( ) ) ;
}
TArray < FWeakObjectPtr > & FPackageData : : GetCachedObjectsInOuter ( )
{
return CachedObjectsInOuter ;
}
void FPackageData : : CheckObjectCacheEmpty ( ) const
{
check ( CachedObjectsInOuter . Num ( ) = = 0 ) ;
check ( ! GetHasSaveCache ( ) ) ;
}
void FPackageData : : CreateObjectCache ( )
{
if ( GetHasSaveCache ( ) )
{
return ;
}
UPackage * LocalPackage = GetPackage ( ) ;
if ( LocalPackage & & LocalPackage - > IsFullyLoaded ( ) )
{
PackageName = LocalPackage - > GetFName ( ) ;
TArray < UObject * > ObjectsInOuter ;
GetObjectsWithOuter ( LocalPackage , ObjectsInOuter ) ;
CachedObjectsInOuter . Reset ( ObjectsInOuter . Num ( ) ) ;
for ( UObject * Object : ObjectsInOuter )
{
FWeakObjectPtr ObjectWeakPointer ( Object ) ;
// ignore pending kill objects; they will not be serialized out so we don't need to call
// BeginCacheForCookedPlatformData on them
if ( ! ObjectWeakPointer . Get ( ) )
2021-04-28 07:45:12 -04:00
{
2021-11-30 14:37:31 -05:00
continue ;
}
CachedObjectsInOuter . Emplace ( MoveTemp ( ObjectWeakPointer ) ) ;
}
SetHasSaveCache ( true ) ;
}
else
{
check ( false ) ;
}
}
2022-05-19 16:16:15 -04:00
void FPackageData : : RecreateObjectCache ( )
{
check ( GetPackage ( ) ) ;
if ( GetHasSaveCache ( ) )
{
// It is not valid to recreate the ObjectCache when we have already started calling BeginCacheForCookedPlatformData on the objects in it.
// ReleaseCookedPlatformData must be called first to tear down all of the calls and reset GetCookedPlatformDataNextIndex to 0
check ( GetCookedPlatformDataNextIndex ( ) = = 0 ) ;
ClearObjectCache ( ) ;
}
CreateObjectCache ( ) ;
}
2021-11-30 14:37:31 -05:00
void FPackageData : : ClearObjectCache ( )
{
CachedObjectsInOuter . Empty ( ) ;
SetHasSaveCache ( false ) ;
}
const int32 & FPackageData : : GetNumPendingCookedPlatformData ( ) const
{
return NumPendingCookedPlatformData ;
}
int32 & FPackageData : : GetNumPendingCookedPlatformData ( )
{
return NumPendingCookedPlatformData ;
}
const int32 & FPackageData : : GetCookedPlatformDataNextIndex ( ) const
{
return CookedPlatformDataNextIndex ;
}
int32 & FPackageData : : GetCookedPlatformDataNextIndex ( )
{
return CookedPlatformDataNextIndex ;
}
void FPackageData : : CheckCookedPlatformDataEmpty ( ) const
{
check ( GetCookedPlatformDataNextIndex ( ) = = 0 ) ;
check ( ! GetCookedPlatformDataStarted ( ) ) ;
check ( ! GetCookedPlatformDataCalled ( ) ) ;
check ( ! GetCookedPlatformDataComplete ( ) ) ;
}
void FPackageData : : ClearCookedPlatformData ( )
{
CookedPlatformDataNextIndex = 0 ;
// Note that GetNumPendingCookedPlatformData is not cleared; it persists across Saves and CookSessions
SetCookedPlatformDataStarted ( false ) ;
SetCookedPlatformDataCalled ( false ) ;
SetCookedPlatformDataComplete ( false ) ;
}
void FPackageData : : ResetGenerationProgress ( )
{
SetInitializedGeneratorSave ( false ) ;
SetCompletedGeneration ( false ) ;
}
void FPackageData : : OnRemoveSessionPlatform ( const ITargetPlatform * Platform )
{
PlatformDatas . Remove ( Platform ) ;
}
bool FPackageData : : HasReferencedObjects ( ) const
{
return Package ! = nullptr | | CachedObjectsInOuter . Num ( ) > 0 ;
}
void FPackageData : : RemapTargetPlatforms ( const TMap < ITargetPlatform * , ITargetPlatform * > & Remap )
{
typedef TSortedMap < const ITargetPlatform * , FPlatformData > MapType ;
MapType NewPlatformDatas ;
NewPlatformDatas . Reserve ( PlatformDatas . Num ( ) ) ;
for ( TPair < const ITargetPlatform * , FPlatformData > & ExistingPair : PlatformDatas )
{
ITargetPlatform * NewKey = Remap [ ExistingPair . Key ] ;
NewPlatformDatas . FindOrAdd ( NewKey ) = MoveTemp ( ExistingPair . Value ) ;
}
// The save state (and maybe more in the future) depend on the order of the request platforms remaining
// unchanged, due to CookedPlatformDataNextIndex. If we change that order due to the remap, we need to
// demote back to request.
if ( IsInProgress ( ) & & GetState ( ) ! = EPackageState : : Request )
{
bool bDemote = true ;
MapType : : TConstIterator OldIter = PlatformDatas . CreateConstIterator ( ) ;
MapType : : TConstIterator NewIter = NewPlatformDatas . CreateConstIterator ( ) ;
for ( ; OldIter ; + + OldIter , + + NewIter )
{
if ( OldIter . Key ( ) ! = NewIter . Key ( ) )
{
bDemote = true ;
2021-04-28 07:45:12 -04:00
}
2020-11-30 11:57:28 -04:00
}
2021-11-30 14:37:31 -05:00
if ( bDemote )
{
SendToState ( EPackageState : : Request , ESendFlags : : QueueAddAndRemove ) ;
}
}
PlatformDatas = MoveTemp ( NewPlatformDatas ) ;
}
bool FPackageData : : IsSaveInvalidated ( ) const
{
if ( GetState ( ) ! = EPackageState : : Save )
{
return false ;
2021-04-28 07:45:12 -04:00
}
2021-11-30 14:37:31 -05:00
return GetPackage ( ) = = nullptr | | ! GetPackage ( ) - > IsFullyLoaded ( ) | |
Algo : : AnyOf ( CachedObjectsInOuter , [ ] ( const FWeakObjectPtr & WeakPtr )
2021-06-07 18:42:35 -04:00
{
2021-11-30 14:37:31 -05:00
// TODO: Keep track of which objects were public, and only invalidate the save if the object
// that has been deleted or marked pending kill was public
// Until we make that change, we will unnecessarily invalidate and demote some packages after a
// garbage collect
return WeakPtr . Get ( ) = = nullptr ;
} ) ;
}
2021-06-07 18:42:35 -04:00
2021-11-30 14:37:31 -05:00
void FPackageData : : SetGeneratedOwner ( FGeneratorPackage * InGeneratedOwner )
{
check ( IsGenerated ( ) ) ;
check ( ! ( GeneratedOwner & & InGeneratedOwner ) ) ;
GeneratedOwner = InGeneratedOwner ;
}
bool FPackageData : : GeneratorPackageRequiresGC ( ) const
{
// We consider that if a FPackageData has valid GeneratorPackage helper object,
// this means that COTFS's process of generating packages was not completed
// either due to an error or because it has exceeded a maximum memory threshold.
return IsGenerating ( ) & & ! GetHasBeginPrepareSaveFailed ( ) ;
}
UE : : Cook : : FGeneratorPackage * FPackageData : : CreateGeneratorPackage ( const UObject * InSplitDataObject ,
ICookPackageSplitter * InCookPackageSplitterInstance )
{
check ( ! GetGeneratorPackage ( ) ) ;
GeneratorPackage . Reset ( new UE : : Cook : : FGeneratorPackage ( * this , InSplitDataObject ,
InCookPackageSplitterInstance ) ) ;
return GetGeneratorPackage ( ) ;
}
//////////////////////////////////////////////////////////////////////////
// FGeneratorPackage
FGeneratorPackage : : FGeneratorPackage ( UE : : Cook : : FPackageData & InOwner , const UObject * InSplitDataObject ,
ICookPackageSplitter * InCookPackageSplitterInstance )
: Owner ( InOwner )
, SplitDataObjectName ( * InSplitDataObject - > GetFullName ( ) )
{
check ( InCookPackageSplitterInstance ) ;
CookPackageSplitterInstance . Reset ( InCookPackageSplitterInstance ) ;
}
FGeneratorPackage : : ~ FGeneratorPackage ( )
{
2022-04-25 08:36:56 -04:00
ConditionalNotifyCompletion ( ICookPackageSplitter : : ETeardown : : Canceled ) ;
2021-11-30 14:37:31 -05:00
ClearGeneratedPackages ( ) ;
}
2022-04-25 08:36:56 -04:00
void FGeneratorPackage : : ConditionalNotifyCompletion ( ICookPackageSplitter : : ETeardown Status )
{
if ( ! bNotifiedCompletion )
{
bNotifiedCompletion = true ;
CookPackageSplitterInstance - > Teardown ( Status ) ;
}
}
2021-11-30 14:37:31 -05:00
void FGeneratorPackage : : ClearGeneratedPackages ( )
{
for ( FGeneratedStruct & GeneratedStruct : PackagesToGenerate )
{
if ( GeneratedStruct . PackageData )
2021-06-07 18:42:35 -04:00
{
2021-11-30 14:37:31 -05:00
check ( GeneratedStruct . PackageData - > GetGeneratedOwner ( ) = = this ) ;
GeneratedStruct . PackageData - > SetGeneratedOwner ( nullptr ) ;
GeneratedStruct . PackageData = nullptr ;
2021-05-11 21:03:22 -04:00
}
}
2021-11-30 14:37:31 -05:00
}
2021-05-11 21:03:22 -04:00
2021-12-04 16:14:37 -05:00
bool FGeneratorPackage : : TryGenerateList ( UObject * OwnerObject , FPackageDatas & PackageDatas )
2021-11-30 14:37:31 -05:00
{
UPackage * OwnerPackage = Owner . GetPackage ( ) ;
check ( OwnerPackage ) ;
TArray < ICookPackageSplitter : : FGeneratedPackage > GeneratorDatas =
CookPackageSplitterInstance - > GetGenerateList ( OwnerPackage , OwnerObject ) ;
PackagesToGenerate . Reset ( GeneratorDatas . Num ( ) ) ;
for ( ICookPackageSplitter : : FGeneratedPackage & SplitterData : GeneratorDatas )
2021-05-17 22:22:59 -04:00
{
2021-11-30 14:37:31 -05:00
FGeneratedStruct & GeneratedStruct = PackagesToGenerate . Emplace_GetRef ( ) ;
GeneratedStruct . RelativePath = MoveTemp ( SplitterData . RelativePath ) ;
GeneratedStruct . Dependencies = MoveTemp ( SplitterData . Dependencies ) ;
FString PackageName = FPaths : : RemoveDuplicateSlashes ( FString : : Printf ( TEXT ( " %s/%s/%s " ) ,
* this - > Owner . GetPackageName ( ) . ToString ( ) , GeneratedPackageSubPath , * GeneratedStruct . RelativePath ) ) ;
2021-05-17 22:22:59 -04:00
2021-11-30 14:37:31 -05:00
if ( ! SplitterData . GetCreateAsMap ( ) . IsSet ( ) )
2021-06-07 18:42:35 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Error , TEXT ( " PackageSplitter did not specify whether CreateAsMap is true for generated package. Splitter=%s, Generated=%s. " ) ,
* this - > GetSplitDataObjectName ( ) . ToString ( ) , * PackageName ) ;
2020-06-23 18:40:00 -04:00
return false ;
}
2021-11-30 14:37:31 -05:00
GeneratedStruct . bCreateAsMap = * SplitterData . GetCreateAsMap ( ) ;
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
const FName PackageFName ( * PackageName ) ;
2021-12-04 16:14:37 -05:00
UE : : Cook : : FPackageData * PackageData = PackageDatas . TryAddPackageDataByPackageName ( PackageFName ,
false /* bRequireExists */ , GeneratedStruct . bCreateAsMap ) ;
if ( ! PackageData )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Error , TEXT ( " PackageSplitter could not find mounted filename for generated packagepath. Splitter=%s, Generated=%s. " ) ,
* this - > GetSplitDataObjectName ( ) . ToString ( ) , * PackageName ) ;
return false ;
2020-06-23 18:40:00 -04:00
}
2021-12-04 16:14:37 -05:00
if ( IFileManager : : Get ( ) . FileExists ( * PackageData - > GetFileName ( ) . ToString ( ) ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " PackageSplitter specified a generated package that already exists in the workspace domain. Splitter=%s, Generated=%s. " ) ,
* this - > GetSplitDataObjectName ( ) . ToString ( ) , * PackageName ) ;
return false ;
2020-06-23 18:40:00 -04:00
}
2021-12-04 16:14:37 -05:00
GeneratedStruct . PackageData = PackageData ;
PackageData - > SetGenerated ( true ) ;
2021-11-30 14:37:31 -05:00
// No package should be generated by two different splitters. If an earlier run of this splitter generated
// the package, the package's owner should have been reset to null when we called ClearGeneratedPackages
// between then and now
2021-12-04 16:14:37 -05:00
check ( PackageData - > GetGeneratedOwner ( ) = = nullptr ) ;
PackageData - > SetGeneratedOwner ( this ) ;
2021-11-30 14:37:31 -05:00
}
RemainingToPopulate = GeneratorDatas . Num ( ) ;
return true ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
FGeneratorPackage : : FGeneratedStruct * FGeneratorPackage : : FindGeneratedStruct ( FPackageData * PackageData )
{
for ( FGeneratedStruct & GeneratedStruct : PackagesToGenerate )
{
if ( GeneratedStruct . PackageData = = PackageData )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
return & GeneratedStruct ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
return nullptr ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
UObject * FGeneratorPackage : : FindSplitDataObject ( ) const
{
FString ObjectPath = GetSplitDataObjectName ( ) . ToString ( ) ;
// SplitDataObjectName is a FullObjectPath; strip off the leading <ClassName> in
// "<ClassName> <Package>.<Object>:<SubObject>"
int32 ClassDelimiterIndex = - 1 ;
if ( ObjectPath . FindChar ( ' ' , ClassDelimiterIndex ) )
2020-09-24 00:43:27 -04:00
{
2021-11-30 14:37:31 -05:00
ObjectPath . RightChopInline ( ClassDelimiterIndex + 1 ) ;
2020-09-24 00:43:27 -04:00
}
2021-11-30 14:37:31 -05:00
return FindObject < UObject > ( nullptr , * ObjectPath ) ;
}
2020-09-24 00:43:27 -04:00
2021-11-30 14:37:31 -05:00
void FGeneratorPackage : : PostGarbageCollect ( )
{
if ( ! bGeneratedList )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
return ;
}
if ( Owner . GetState ( ) = = EPackageState : : Save )
{
// UCookOnTheFlyServer::PreCollectGarbage adds references for the Generator package and all its public
// objects, so it should still be loaded
if ( ! Owner . GetPackage ( ) | | ! FindSplitDataObject ( ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Error , TEXT ( " PackageSplitter object was deleted by garbage collection while generation was still ongoing. This will break the generation. " )
TEXT ( " \n \t Splitter=%s. " ) , * GetSplitDataObjectName ( ) . ToString ( ) ) ;
}
}
else
{
2022-04-25 08:36:56 -04:00
// After the Generator Package is saved, we drop our references to it and it can be garbage collected
2021-11-30 14:37:31 -05:00
// If we have any packages left to populate, our splitter contract requires that it be garbage collected;
// we promise that the package is not partially GC'd during calls to TryPopulateGeneratedPackage
// The splitter can opt-out of this contract and keep it referenced itself if it desires.
UPackage * OwnerPackage = FindObject < UPackage > ( nullptr , * Owner . GetPackageName ( ) . ToString ( ) ) ;
if ( OwnerPackage )
{
if ( RemainingToPopulate > 0 & &
2022-04-25 08:36:56 -04:00
! Owner . IsKeepReferencedDuringGC ( ) & &
2021-11-30 14:37:31 -05:00
! CookPackageSplitterInstance - > UseInternalReferenceToAvoidGarbageCollect ( ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Error , TEXT ( " PackageSplitter found the Generator package still in memory after it should have been deleted by GC. " )
TEXT ( " \n \t This is unexpected since garbage has been collected and the package should have been unreferenced so it should have been collected, and will break population of Generated packages. " )
TEXT ( " \n \t Splitter=%s " ) , * GetSplitDataObjectName ( ) . ToString ( ) ) ;
EReferenceChainSearchMode SearchMode = EReferenceChainSearchMode : : Shortest
| EReferenceChainSearchMode : : PrintAllResults
| EReferenceChainSearchMode : : FullChain ;
FReferenceChainSearch RefChainSearch ( OwnerPackage , SearchMode ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
}
else
{
bWasOwnerReloaded = true ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
bool bHasIssuedWarning = false ;
for ( FGeneratedStruct & GeneratedStruct : PackagesToGenerate )
2020-06-23 18:40:00 -04:00
{
2022-04-25 08:36:56 -04:00
if ( FindObject < UPackage > ( nullptr , * GeneratedStruct . PackageData - > GetPackageName ( ) . ToString ( ) ) )
2020-06-23 18:40:00 -04:00
{
2022-04-25 08:36:56 -04:00
if ( ! GeneratedStruct . PackageData - > IsKeepReferencedDuringGC ( ) & &
! GeneratedStruct . bHasSaved & &
! bHasIssuedWarning )
2021-11-18 14:37:34 -05:00
{
2021-11-30 14:37:31 -05:00
UE_LOG ( LogCook , Warning , TEXT ( " PackageSplitter found a package it generated that was not removed from memory during garbage collection. This will cause errors later during population. " )
TEXT ( " \n \t Splitter=%s, Generated=%s. " ) , * GetSplitDataObjectName ( ) . ToString ( ) , * GeneratedStruct . PackageData - > GetPackageName ( ) . ToString ( ) ) ;
bHasIssuedWarning = true ; // Only issue the warning once per GC
}
}
2022-04-25 08:36:56 -04:00
else
{
GeneratedStruct . bHasCreatedPackage = false ;
}
2021-11-30 14:37:31 -05:00
}
}
UPackage * FGeneratorPackage : : CreateGeneratedUPackage ( FGeneratorPackage : : FGeneratedStruct & GeneratedStruct ,
const UPackage * OwnerPackage , const TCHAR * GeneratedPackageName )
{
UPackage * GeneratedPackage = CreatePackage ( GeneratedPackageName ) ;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
GeneratedPackage - > SetGuid ( OwnerPackage - > GetGuid ( ) ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
GeneratedPackage - > SetPersistentGuid ( OwnerPackage - > GetPersistentGuid ( ) ) ;
2022-05-02 16:01:27 -04:00
GeneratedPackage - > SetPackageFlags ( PKG_CookGenerated ) ;
2021-11-30 14:37:31 -05:00
GeneratedStruct . bHasCreatedPackage = true ;
return GeneratedPackage ;
}
2022-04-25 08:36:56 -04:00
void FGeneratorPackage : : SetGeneratorSaved ( UPackage * GeneratorUPackage )
{
UObject * SplitObject = FindSplitDataObject ( ) ;
if ( ! SplitObject | | ! GeneratorUPackage )
{
UE_LOG ( LogCook , Error , TEXT ( " PackageSplitter: %s was GarbageCollected before we finished saving it. This will cause a failure later when we attempt to save it again and generate a second time. Splitter=%s. " ) ,
( ! GeneratorUPackage ? TEXT ( " UPackage " ) : TEXT ( " SplitDataObject " ) ) , * GetSplitDataObjectName ( ) . ToString ( ) ) ;
}
else
{
GetCookPackageSplitterInstance ( ) - > PostSaveGeneratorPackage ( GeneratorUPackage , SplitObject ) ;
}
bOwnerHasSaved = true ;
if ( IsComplete ( ) )
{
ConditionalNotifyCompletion ( ICookPackageSplitter : : ETeardown : : Complete ) ;
}
}
2021-11-30 14:37:31 -05:00
void FGeneratorPackage : : SetGeneratedSaved ( FPackageData & PackageData )
{
FGeneratedStruct * GeneratedStruct = FindGeneratedStruct ( & PackageData ) ;
if ( ! GeneratedStruct )
{
UE_LOG ( LogCook , Warning , TEXT ( " PackageSplitter called SetGeneratedSaved on a package that does not belong to the splitter. " )
TEXT ( " \n \t Splitter=%s, Generated=%s. " ) , * GetSplitDataObjectName ( ) . ToString ( ) ,
* PackageData . GetPackageName ( ) . ToString ( ) ) ;
return ;
}
if ( GeneratedStruct - > bHasSaved )
{
return ;
}
GeneratedStruct - > bHasSaved = true ;
- - RemainingToPopulate ;
check ( RemainingToPopulate > = 0 ) ;
2022-04-25 08:36:56 -04:00
if ( IsComplete ( ) )
{
ConditionalNotifyCompletion ( ICookPackageSplitter : : ETeardown : : Complete ) ;
}
2021-11-30 14:37:31 -05:00
}
bool FGeneratorPackage : : IsComplete ( ) const
{
return bGeneratedList & & RemainingToPopulate = = 0 ;
}
void FGeneratorPackage : : GetIntermediateMountPoint ( FString & OutPackagePath , FString & OutLocalFilePath ) const
{
const FString OwnerShortName = FPackageName : : GetShortName ( Owner . GetPackageName ( ) . ToString ( ) ) ;
OutPackagePath = FPaths : : RemoveDuplicateSlashes ( FString : : Printf ( TEXT ( " /%s%s/ " ) ,
* OwnerShortName , UE : : Cook : : GeneratedPackageSubPath ) ) ;
OutLocalFilePath = FPaths : : RemoveDuplicateSlashes ( FString : : Printf ( TEXT ( " %s/Cooked/%s/%s/ " ) ,
* FPaths : : ProjectIntermediateDir ( ) , * OwnerShortName , UE : : Cook : : GeneratedPackageSubPath ) ) ;
}
FString FGeneratorPackage : : GetIntermediateLocalPath ( const FGeneratorPackage : : FGeneratedStruct & GeneratedStruct ) const
{
FString UnusedPackagePath ;
FString MountLocalFilePath ;
GetIntermediateMountPoint ( UnusedPackagePath , MountLocalFilePath ) ;
FString Extension = FPaths : : GetExtension ( GeneratedStruct . PackageData - > GetFileName ( ) . ToString ( ) ,
true /* bIncludeDot */ ) ;
return FPaths : : RemoveDuplicateSlashes ( FString : : Printf ( TEXT ( " %s/%s%s " ) ,
* MountLocalFilePath , * GeneratedStruct . RelativePath , * Extension ) ) ;
}
//////////////////////////////////////////////////////////////////////////
// FPendingCookedPlatformData
FPendingCookedPlatformData : : FPendingCookedPlatformData ( UObject * InObject , const ITargetPlatform * InTargetPlatform ,
FPackageData & InPackageData , bool bInNeedsResourceRelease , UCookOnTheFlyServer & InCookOnTheFlyServer )
: Object ( InObject ) , TargetPlatform ( InTargetPlatform ) , PackageData ( InPackageData )
, CookOnTheFlyServer ( InCookOnTheFlyServer ) , CancelManager ( nullptr ) , ClassName ( InObject - > GetClass ( ) - > GetFName ( ) )
, bHasReleased ( false ) , bNeedsResourceRelease ( bInNeedsResourceRelease )
{
check ( InObject ) ;
PackageData . GetNumPendingCookedPlatformData ( ) + = 1 ;
}
FPendingCookedPlatformData : : FPendingCookedPlatformData ( FPendingCookedPlatformData & & Other )
: Object ( Other . Object ) , TargetPlatform ( Other . TargetPlatform ) , PackageData ( Other . PackageData )
, CookOnTheFlyServer ( Other . CookOnTheFlyServer ) , CancelManager ( Other . CancelManager ) , ClassName ( Other . ClassName )
, bHasReleased ( Other . bHasReleased ) , bNeedsResourceRelease ( Other . bNeedsResourceRelease )
{
Other . Object = nullptr ;
}
FPendingCookedPlatformData : : ~ FPendingCookedPlatformData ( )
{
Release ( ) ;
}
bool FPendingCookedPlatformData : : PollIsComplete ( )
{
if ( bHasReleased )
{
return true ;
}
UObject * LocalObject = Object . Get ( ) ;
if ( ! LocalObject )
{
Release ( ) ;
return true ;
}
UE_TRACK_REFERENCING_PACKAGE_SCOPED ( LocalObject - > GetPackage ( ) , PackageAccessTrackingOps : : NAME_CookerBuildObject ) ;
2022-02-15 12:51:35 -05:00
if ( RouteIsCachedCookedPlatformDataLoaded ( LocalObject , TargetPlatform ) )
2021-11-30 14:37:31 -05:00
{
Release ( ) ;
return true ;
}
else
{
# if DEBUG_COOKONTHEFLY
UE_LOG ( LogCook , Display , TEXT ( " Object %s isn't cached yet " ) , * LocalObject - > GetFullName ( ) ) ;
# endif
/*if ( LocalObject->IsA(UMaterial::StaticClass()) )
{
if ( GShaderCompilingManager - > HasShaderJobs ( ) = = false )
{
UE_LOG ( LogCook , Warning , TEXT ( " Shader compiler is in a bad state! Shader %s is finished compile but shader compiling manager did not notify shader. " ) ,
* LocalObject - > GetPathName ( ) ) ;
}
} */
return false ;
}
}
void FPendingCookedPlatformData : : Release ( )
{
if ( bHasReleased )
{
return ;
}
if ( bNeedsResourceRelease )
{
int32 * CurrentAsyncCache = CookOnTheFlyServer . CurrentAsyncCacheForType . Find ( ClassName ) ;
// bNeedsRelease should not have been set if the AsyncCache does not have an entry for the class
check ( CurrentAsyncCache ! = nullptr ) ;
* CurrentAsyncCache + = 1 ;
}
PackageData . GetNumPendingCookedPlatformData ( ) - = 1 ;
check ( PackageData . GetNumPendingCookedPlatformData ( ) > = 0 ) ;
if ( CancelManager )
{
CancelManager - > Release ( * this ) ;
CancelManager = nullptr ;
}
Object = nullptr ;
bHasReleased = true ;
}
void FPendingCookedPlatformData : : RemapTargetPlatforms ( const TMap < ITargetPlatform * , ITargetPlatform * > & Remap )
{
TargetPlatform = Remap [ TargetPlatform ] ;
}
//////////////////////////////////////////////////////////////////////////
// FPendingCookedPlatformDataCancelManager
void FPendingCookedPlatformDataCancelManager : : Release ( FPendingCookedPlatformData & Data )
{
- - NumPendingPlatforms ;
if ( NumPendingPlatforms < = 0 )
{
check ( NumPendingPlatforms = = 0 ) ;
UObject * LocalObject = Data . Object . Get ( ) ;
if ( LocalObject )
{
LocalObject - > ClearAllCachedCookedPlatformData ( ) ;
}
delete this ;
}
}
//////////////////////////////////////////////////////////////////////////
// FPackageDataMonitor
FPackageDataMonitor : : FPackageDataMonitor ( )
{
FMemory : : Memset ( NumUrgentInState , 0 ) ;
}
int32 FPackageDataMonitor : : GetNumUrgent ( ) const
{
int32 NumUrgent = 0 ;
for ( EPackageState State = EPackageState : : Min ;
State < = EPackageState : : Max ;
State = static_cast < EPackageState > ( static_cast < uint32 > ( State ) + 1 ) )
{
NumUrgent + = NumUrgentInState [ static_cast < uint32 > ( State ) - static_cast < uint32 > ( EPackageState : : Min ) ] ;
}
return NumUrgent ;
}
int32 FPackageDataMonitor : : GetNumUrgent ( EPackageState InState ) const
{
check ( EPackageState : : Min < = InState & & InState < = EPackageState : : Max ) ;
return NumUrgentInState [ static_cast < uint32 > ( InState ) - static_cast < uint32 > ( EPackageState : : Min ) ] ;
}
int32 FPackageDataMonitor : : GetNumPreloadAllocated ( ) const
{
return NumPreloadAllocated ;
}
int32 FPackageDataMonitor : : GetNumInProgress ( ) const
{
return NumInProgress ;
}
int32 FPackageDataMonitor : : GetNumCooked ( ) const
{
return NumCooked ;
}
void FPackageDataMonitor : : OnInProgressChanged ( FPackageData & PackageData , bool bInProgress )
{
NumInProgress + = bInProgress ? 1 : - 1 ;
check ( NumInProgress > = 0 ) ;
}
void FPackageDataMonitor : : OnPreloadAllocatedChanged ( FPackageData & PackageData , bool bPreloadAllocated )
{
NumPreloadAllocated + = bPreloadAllocated ? 1 : - 1 ;
check ( NumPreloadAllocated > = 0 ) ;
}
void FPackageDataMonitor : : OnFirstCookedPlatformAdded ( FPackageData & PackageData )
{
if ( ! PackageData . GetMonitorIsCooked ( ) )
{
+ + NumCooked ;
PackageData . SetMonitorIsCooked ( true ) ;
}
}
void FPackageDataMonitor : : OnLastCookedPlatformRemoved ( FPackageData & PackageData )
{
if ( PackageData . GetMonitorIsCooked ( ) )
{
- - NumCooked ;
PackageData . SetMonitorIsCooked ( false ) ;
}
}
void FPackageDataMonitor : : OnUrgencyChanged ( FPackageData & PackageData )
{
int32 Delta = PackageData . GetIsUrgent ( ) ? 1 : - 1 ;
TrackUrgentRequests ( PackageData . GetState ( ) , Delta ) ;
}
void FPackageDataMonitor : : OnStateChanged ( FPackageData & PackageData , EPackageState OldState )
{
if ( ! PackageData . GetIsUrgent ( ) )
{
return ;
}
TrackUrgentRequests ( OldState , - 1 ) ;
TrackUrgentRequests ( PackageData . GetState ( ) , 1 ) ;
}
void FPackageDataMonitor : : TrackUrgentRequests ( EPackageState State , int32 Delta )
{
check ( EPackageState : : Min < = State & & State < = EPackageState : : Max ) ;
NumUrgentInState [ static_cast < uint32 > ( State ) - static_cast < uint32 > ( EPackageState : : Min ) ] + = Delta ;
check ( NumUrgentInState [ static_cast < uint32 > ( State ) - static_cast < uint32 > ( EPackageState : : Min ) ] > = 0 ) ;
}
//////////////////////////////////////////////////////////////////////////
// FPackageDatas
2021-12-04 16:14:37 -05:00
IAssetRegistry * FPackageDatas : : AssetRegistry = nullptr ;
2021-11-30 14:37:31 -05:00
FPackageDatas : : FPackageDatas ( UCookOnTheFlyServer & InCookOnTheFlyServer )
: CookOnTheFlyServer ( InCookOnTheFlyServer )
, LastPollAsyncTime ( 0 )
{
}
2022-05-02 16:31:37 -04:00
void FPackageDatas : : SetBeginCookConfigSettings ( )
2021-11-30 14:37:31 -05:00
{
FString FileOrPackageName ;
ShowInstigatorPackageData = nullptr ;
if ( FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " -CookShowInstigator= " ) , FileOrPackageName ) )
{
FString LocalPath ;
FString PackageName ;
if ( ! FPackageName : : TryConvertToMountedPath ( FileOrPackageName , & LocalPath , & PackageName , nullptr , nullptr , nullptr ) )
{
UE_LOG ( LogCook , Fatal , TEXT ( " -CookShowInstigator argument %s is not a mounted filename or packagename " ) ,
* FileOrPackageName ) ;
}
else
{
FName PackageFName ( * PackageName ) ;
2021-12-04 16:14:37 -05:00
ShowInstigatorPackageData = TryAddPackageDataByPackageName ( PackageFName ) ;
if ( ! ShowInstigatorPackageData )
2021-11-30 14:37:31 -05:00
{
UE_LOG ( LogCook , Fatal , TEXT ( " -CookShowInstigator argument %s could not be found on disk " ) ,
2021-11-18 14:37:34 -05:00
* FileOrPackageName ) ;
}
}
}
2022-05-02 16:31:37 -04:00
// Discoveries during the processing of the initial cluster are expected, so LogDiscoveredPackages must be off.
SetLogDiscoveredPackages ( false ) ;
2021-11-30 14:37:31 -05:00
}
2021-11-18 14:37:34 -05:00
2021-11-30 14:37:31 -05:00
FPackageDatas : : ~ FPackageDatas ( )
{
Clear ( ) ;
}
2021-12-04 16:14:37 -05:00
void FPackageDatas : : OnAssetRegistryGenerated ( IAssetRegistry & InAssetRegistry )
{
AssetRegistry = & InAssetRegistry ;
}
2021-11-30 14:37:31 -05:00
FString FPackageDatas : : GetReferencerName ( ) const
{
return TEXT ( " FPackageDatas " ) ;
}
void FPackageDatas : : AddReferencedObjects ( FReferenceCollector & Collector )
{
return CookOnTheFlyServer . CookerAddReferencedObjects ( Collector ) ;
}
FPackageDataMonitor & FPackageDatas : : GetMonitor ( )
{
return Monitor ;
}
UCookOnTheFlyServer & FPackageDatas : : GetCookOnTheFlyServer ( )
{
return CookOnTheFlyServer ;
}
FRequestQueue & FPackageDatas : : GetRequestQueue ( )
{
return RequestQueue ;
}
FPackageDataQueue & FPackageDatas : : GetSaveQueue ( )
{
return SaveQueue ;
}
FPackageData & FPackageDatas : : FindOrAddPackageData ( const FName & PackageName , const FName & NormalizedFileName )
{
2020-06-23 18:40:00 -04:00
{
2021-12-04 16:14:37 -05:00
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
FPackageData * * PackageDataMapAddr = PackageNameToPackageData . Find ( PackageName ) ;
if ( PackageDataMapAddr ! = nullptr )
{
FPackageData * * FileNameMapAddr = FileNameToPackageData . Find ( NormalizedFileName ) ;
2022-01-10 18:50:27 -05:00
checkf ( FileNameMapAddr , TEXT ( " Package %s is being added with filename %s, but it already exists with filename %s, " )
TEXT ( " and it is not present in FileNameToPackageData map under the new name. " ) ,
* PackageName . ToString ( ) , * NormalizedFileName . ToString ( ) , * ( * PackageDataMapAddr ) - > GetFileName ( ) . ToString ( ) ) ;
checkf ( * FileNameMapAddr = = * PackageDataMapAddr ,
TEXT ( " Package %s is being added with filename %s, but that filename maps to a different package %s. " ) ,
* PackageName . ToString ( ) , * NormalizedFileName . ToString ( ) , * ( * FileNameMapAddr ) - > GetPackageName ( ) . ToString ( ) ) ;
2021-12-04 16:14:37 -05:00
return * * PackageDataMapAddr ;
}
2020-06-23 18:40:00 -04:00
2021-12-04 16:14:37 -05:00
checkf ( FileNameToPackageData . Find ( NormalizedFileName ) = = nullptr ,
TEXT ( " Package \" %s \" and package \" %s \" share the same filename \" %s \" . " ) ,
* PackageName . ToString ( ) , * ( * FileNameToPackageData . Find ( NormalizedFileName ) ) - > GetPackageName ( ) . ToString ( ) ,
* NormalizedFileName . ToString ( ) ) ;
}
2021-11-30 14:37:31 -05:00
return CreatePackageData ( PackageName , NormalizedFileName ) ;
}
FPackageData * FPackageDatas : : FindPackageDataByPackageName ( const FName & PackageName )
{
if ( PackageName . IsNone ( ) )
2020-06-23 18:40:00 -04:00
{
return nullptr ;
}
2021-12-04 16:14:37 -05:00
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
2021-11-30 14:37:31 -05:00
FPackageData * * PackageDataMapAddr = PackageNameToPackageData . Find ( PackageName ) ;
return PackageDataMapAddr ? * PackageDataMapAddr : nullptr ;
}
2021-12-04 16:14:37 -05:00
FPackageData * FPackageDatas : : TryAddPackageDataByPackageName ( const FName & PackageName , bool bRequireExists ,
bool bCreateAsMap )
2021-11-30 14:37:31 -05:00
{
if ( PackageName . IsNone ( ) )
2021-08-31 14:20:48 -04:00
{
2021-11-30 14:37:31 -05:00
return nullptr ;
}
{
2021-12-04 16:14:37 -05:00
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
FPackageData * * PackageDataMapAddr = PackageNameToPackageData . Find ( PackageName ) ;
if ( PackageDataMapAddr ! = nullptr )
{
return * PackageDataMapAddr ;
}
2021-11-30 14:37:31 -05:00
}
2021-12-04 16:14:37 -05:00
FName FileName = LookupFileNameOnDisk ( PackageName , bRequireExists , bCreateAsMap ) ;
2021-11-30 14:37:31 -05:00
if ( FileName . IsNone ( ) )
{
2021-12-04 16:14:37 -05:00
// This will happen if PackageName does not exist on disk
2021-11-30 14:37:31 -05:00
return nullptr ;
}
2021-12-04 16:14:37 -05:00
{
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
checkf ( FileNameToPackageData . Find ( FileName ) = = nullptr ,
TEXT ( " Package \" %s \" and package \" %s \" share the same filename \" %s \" . " ) ,
* PackageName . ToString ( ) , * ( * FileNameToPackageData . Find ( FileName ) ) - > GetPackageName ( ) . ToString ( ) ,
* FileName . ToString ( ) ) ;
}
2021-11-30 14:37:31 -05:00
return & CreatePackageData ( PackageName , FileName ) ;
}
2021-12-04 16:14:37 -05:00
FPackageData & FPackageDatas : : AddPackageDataByPackageNameChecked ( const FName & PackageName , bool bRequireExists ,
bool bCreateAsMap )
2021-11-30 14:37:31 -05:00
{
2021-12-04 16:14:37 -05:00
FPackageData * PackageData = TryAddPackageDataByPackageName ( PackageName , bRequireExists , bCreateAsMap ) ;
2021-11-30 14:37:31 -05:00
check ( PackageData ) ;
return * PackageData ;
}
FPackageData * FPackageDatas : : FindPackageDataByFileName ( const FName & InFileName )
{
2021-12-04 16:14:37 -05:00
FName FileName ( GetStandardFileName ( InFileName ) ) ;
2021-11-30 14:37:31 -05:00
if ( FileName . IsNone ( ) )
{
return nullptr ;
}
2021-12-04 16:14:37 -05:00
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
2021-11-30 14:37:31 -05:00
FPackageData * * PackageDataMapAddr = FileNameToPackageData . Find ( FileName ) ;
return PackageDataMapAddr ? * PackageDataMapAddr : nullptr ;
}
FPackageData * FPackageDatas : : TryAddPackageDataByFileName ( const FName & InFileName )
{
2021-12-04 16:14:37 -05:00
return TryAddPackageDataByStandardFileName ( GetStandardFileName ( InFileName ) ) ;
}
2021-12-06 13:24:26 -05:00
FPackageData * FPackageDatas : : TryAddPackageDataByStandardFileName ( const FName & FileName , bool bExactMatchRequired ,
FName * OutFoundFileName )
2021-12-04 16:14:37 -05:00
{
2021-12-06 13:24:26 -05:00
FName FoundFileName = FileName ;
ON_SCOPE_EXIT { if ( OutFoundFileName ) { * OutFoundFileName = FoundFileName ; } } ;
2021-11-30 14:37:31 -05:00
if ( FileName . IsNone ( ) )
{
return nullptr ;
}
{
2021-12-04 16:14:37 -05:00
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
FPackageData * * PackageDataMapAddr = FileNameToPackageData . Find ( FileName ) ;
if ( PackageDataMapAddr ! = nullptr )
{
return * PackageDataMapAddr ;
}
2021-11-30 14:37:31 -05:00
}
2021-12-06 13:24:26 -05:00
FName ExistingFileName ;
FName PackageName = LookupPackageNameOnDisk ( FileName , bExactMatchRequired , ExistingFileName ) ;
2021-12-04 16:14:37 -05:00
if ( PackageName . IsNone ( ) )
2021-11-30 14:37:31 -05:00
{
return nullptr ;
}
2022-01-31 18:37:27 -05:00
if ( ExistingFileName . IsNone ( ) )
{
2022-02-02 01:47:31 -05:00
if ( ! bExactMatchRequired )
{
FReadScopeLock ExistenceReadLock ( ExistenceLock ) ;
FPackageData * * PackageDataMapAddr = PackageNameToPackageData . Find ( PackageName ) ;
if ( PackageDataMapAddr ! = nullptr )
{
FoundFileName = ( * PackageDataMapAddr ) - > GetFileName ( ) ;
return * PackageDataMapAddr ;
}
}
UE_LOG ( LogCook , Warning , TEXT ( " Unexpected failure to cook filename '%s'. It is mapped to PackageName '%s', but does not exist on disk and we cannot verify the extension. " ) ,
2022-01-31 18:37:27 -05:00
* FileName . ToString ( ) , * PackageName . ToString ( ) ) ;
return nullptr ;
}
2021-12-06 13:24:26 -05:00
FoundFileName = ExistingFileName ;
return & CreatePackageData ( PackageName , ExistingFileName ) ;
2021-11-30 14:37:31 -05:00
}
FPackageData & FPackageDatas : : CreatePackageData ( FName PackageName , FName FileName )
{
2021-12-04 16:14:37 -05:00
check ( ! PackageName . IsNone ( ) ) ;
check ( ! FileName . IsNone ( ) ) ;
2021-11-30 14:37:31 -05:00
FPackageData * PackageData = new FPackageData ( * this , PackageName , FileName ) ;
2021-12-04 16:14:37 -05:00
FWriteScopeLock ExistenceWriteLock ( ExistenceLock ) ;
FPackageData * & ExistingByPackageName = PackageNameToPackageData . FindOrAdd ( PackageName ) ;
FPackageData * & ExistingByFileName = FileNameToPackageData . FindOrAdd ( FileName ) ;
if ( ExistingByPackageName )
{
// The other CreatePackageData call should have added the FileName as well
check ( ExistingByFileName = = ExistingByPackageName ) ;
delete PackageData ;
return * ExistingByPackageName ;
}
// If no other CreatePackageData added the PackageName, then they should not have added
// the FileName either
check ( ! ExistingByFileName ) ;
ExistingByPackageName = PackageData ;
ExistingByFileName = PackageData ;
2021-11-30 14:37:31 -05:00
PackageDatas . Add ( PackageData ) ;
return * PackageData ;
}
FPackageData & FPackageDatas : : AddPackageDataByFileNameChecked ( const FName & FileName )
{
FPackageData * PackageData = TryAddPackageDataByFileName ( FileName ) ;
check ( PackageData ) ;
return * PackageData ;
}
2021-12-04 16:14:37 -05:00
FName FPackageDatas : : GetFileNameByPackageName ( FName PackageName , bool bRequireExists , bool bCreateAsMap )
2021-11-30 14:37:31 -05:00
{
2021-12-04 16:14:37 -05:00
FPackageData * PackageData = TryAddPackageDataByPackageName ( PackageName , bRequireExists , bCreateAsMap ) ;
return PackageData ? PackageData - > GetFileName ( ) : NAME_None ;
}
2021-11-30 14:37:31 -05:00
2021-12-04 16:14:37 -05:00
FName FPackageDatas : : GetFileNameByFlexName ( FName PackageOrFileName , bool bRequireExists , bool bCreateAsMap )
{
FString Buffer = PackageOrFileName . ToString ( ) ;
if ( ! FPackageName : : TryConvertFilenameToLongPackageName ( Buffer , Buffer ) )
2021-11-30 14:37:31 -05:00
{
2021-12-04 16:14:37 -05:00
return NAME_None ;
}
return GetFileNameByPackageName ( FName ( Buffer ) , bRequireExists , bCreateAsMap ) ;
}
2021-11-30 14:37:31 -05:00
2021-12-04 16:14:37 -05:00
FName FPackageDatas : : LookupFileNameOnDisk ( FName PackageName , bool bRequireExists , bool bCreateAsMap )
{
FString FilenameOnDisk ;
if ( TryLookupFileNameOnDisk ( PackageName , FilenameOnDisk ) )
{
}
else if ( ! bRequireExists )
{
FString Extension = bCreateAsMap ? FPackageName : : GetMapPackageExtension ( ) : FPackageName : : GetAssetPackageExtension ( ) ;
if ( ! FPackageName : : TryConvertLongPackageNameToFilename ( PackageName . ToString ( ) , FilenameOnDisk , Extension ) )
2021-08-31 14:20:48 -04:00
{
2021-12-04 16:14:37 -05:00
return NAME_None ;
}
}
else
{
return NAME_None ;
}
FilenameOnDisk = FPaths : : ConvertRelativePathToFull ( FilenameOnDisk ) ;
FPaths : : MakeStandardFilename ( FilenameOnDisk ) ;
return FName ( FilenameOnDisk ) ;
}
bool FPackageDatas : : TryLookupFileNameOnDisk ( FName PackageName , FString & OutFileName )
{
FString PackageNameStr = PackageName . ToString ( ) ;
// Verse packages are editor-generated in-memory packages which don't have a corresponding
// asset file (yet). However, we still want to cook these packages out, producing cooked
// asset files for packaged projects.
if ( FPackageName : : IsVersePackage ( PackageNameStr ) )
{
if ( FindPackage ( /*Outer =*/ nullptr , * PackageNameStr ) )
{
return FPackageName : : TryConvertLongPackageNameToFilename ( PackageNameStr , OutFileName ,
FPackageName : : GetAssetPackageExtension ( ) ) ;
}
// else, the cooker could be responding to a NotifyUObjectCreated() event, and the object hasn't
// been fully constructed yet (missing from the FindObject() list) -- in this case, we've found
// that the linker loader is creating a dummy object to fill a referencing import slot, not loading
// the proper object (which means we want to ignore it).
}
if ( ! AssetRegistry )
{
return FPackageName : : DoesPackageExist ( PackageNameStr , & OutFileName , false /* InAllowTextFormats */ ) ;
}
else
{
2022-03-14 13:20:30 -04:00
FString PackageExtension ;
if ( ! AssetRegistry - > DoesPackageExistOnDisk ( PackageName , nullptr , & PackageExtension ) )
2021-12-04 16:14:37 -05:00
{
return false ;
2021-11-30 14:37:31 -05:00
}
2021-12-04 16:14:37 -05:00
return FPackageName : : TryConvertLongPackageNameToFilename ( PackageNameStr , OutFileName , PackageExtension ) ;
}
}
2021-12-06 13:24:26 -05:00
FName FPackageDatas : : LookupPackageNameOnDisk ( FName NormalizedFileName , bool bExactMatchRequired , FName & FoundFileName )
2021-12-04 16:14:37 -05:00
{
2021-12-06 13:24:26 -05:00
FoundFileName = NormalizedFileName ;
2021-12-04 16:14:37 -05:00
if ( NormalizedFileName . IsNone ( ) )
{
return NAME_None ;
}
FString Buffer = NormalizedFileName . ToString ( ) ;
if ( ! FPackageName : : TryConvertFilenameToLongPackageName ( Buffer , Buffer ) )
{
return NAME_None ;
}
FName PackageName = FName ( * Buffer ) ;
FName DiscoveredFileName = LookupFileNameOnDisk ( PackageName , true /* bRequireExists */ , false /* bCreateAsMap */ ) ;
2021-12-06 13:24:26 -05:00
if ( DiscoveredFileName = = NormalizedFileName | | ! bExactMatchRequired )
2021-12-04 16:14:37 -05:00
{
2021-12-06 13:24:26 -05:00
FoundFileName = DiscoveredFileName ;
2021-12-04 16:14:37 -05:00
return PackageName ;
}
else
{
2021-12-06 13:24:26 -05:00
// Either the file does not exist on disk or NormalizedFileName did not match its format or extension
2021-12-04 16:14:37 -05:00
return NAME_None ;
}
}
FName FPackageDatas : : GetStandardFileName ( FName FileName )
{
FString FileNameString ( FileName . ToString ( ) ) ;
FPaths : : MakeStandardFilename ( FileNameString ) ;
return FName ( FileNameString ) ;
}
FName FPackageDatas : : GetStandardFileName ( FStringView InFileName )
{
FString FileName ( InFileName ) ;
FPaths : : MakeStandardFilename ( FileName ) ;
return FName ( FileName ) ;
}
void FPackageDatas : : AddExistingPackageDatasForPlatform ( TConstArrayView < FConstructPackageData > ExistingPackages ,
const ITargetPlatform * TargetPlatform )
{
int32 NumPackages = ExistingPackages . Num ( ) ;
// Make the list unique
TMap < FName , FName > UniquePackages ;
UniquePackages . Reserve ( NumPackages ) ;
for ( const FConstructPackageData & PackageToAdd : ExistingPackages )
{
FName & AddedFileName = UniquePackages . FindOrAdd ( PackageToAdd . PackageName , PackageToAdd . NormalizedFileName ) ;
check ( AddedFileName = = PackageToAdd . NormalizedFileName ) ;
}
TArray < FConstructPackageData > UniqueArray ;
if ( UniquePackages . Num ( ) ! = NumPackages )
{
NumPackages = UniquePackages . Num ( ) ;
UniqueArray . Reserve ( NumPackages ) ;
for ( TPair < FName , FName > & Pair : UniquePackages )
{
UniqueArray . Add ( FConstructPackageData { Pair . Key , Pair . Value } ) ;
}
ExistingPackages = UniqueArray ;
}
// parallelize the read-only operations (and write NewPackageDataObjects by index which has no threading issues)
TArray < FPackageData * > NewPackageDataObjects ;
NewPackageDataObjects . AddZeroed ( NumPackages ) ;
FWriteScopeLock ExistenceWriteLock ( ExistenceLock ) ;
ParallelFor ( NumPackages ,
[ & ExistingPackages , TargetPlatform , & NewPackageDataObjects , this ] ( int Index )
{
FName PackageName = ExistingPackages [ Index ] . PackageName ;
FName NormalizedFileName = ExistingPackages [ Index ] . NormalizedFileName ;
check ( ! PackageName . IsNone ( ) ) ;
check ( ! NormalizedFileName . IsNone ( ) ) ;
FPackageData * * PackageDataMapAddr = FileNameToPackageData . Find ( NormalizedFileName ) ;
2021-11-30 14:37:31 -05:00
FPackageData * PackageData = nullptr ;
if ( PackageDataMapAddr ! = nullptr )
{
PackageData = * PackageDataMapAddr ;
2021-08-31 14:20:48 -04:00
}
else
{
2021-11-30 14:37:31 -05:00
// create the package data and remember it for updating caches after the the ParallelFor
2021-12-04 16:14:37 -05:00
PackageData = new FPackageData ( * this , PackageName , NormalizedFileName ) ;
2021-11-30 14:37:31 -05:00
NewPackageDataObjects [ Index ] = PackageData ;
}
PackageData - > SetPlatformCooked ( TargetPlatform , true /* Succeeded */ ) ;
} ) ;
2021-12-04 16:14:37 -05:00
// update cache for all newly created objects (copied from CreatePackageData)
2021-11-30 14:37:31 -05:00
for ( FPackageData * PackageData : NewPackageDataObjects )
{
if ( PackageData )
{
2021-12-04 16:14:37 -05:00
FPackageData * ExistingByFileName = FileNameToPackageData . Add ( PackageData - > FileName , PackageData ) ;
// We looked up by FileName in the loop; it should still have been unset before the write we just did
check ( ExistingByFileName = = PackageData ) ;
FPackageData * ExistingByPackageName = PackageNameToPackageData . FindOrAdd ( PackageData - > PackageName , PackageData ) ;
// If no other CreatePackageData added the FileName, then they should not have added
// the PackageName either
check ( ExistingByPackageName = = PackageData ) ;
2021-11-30 14:37:31 -05:00
PackageDatas . Add ( PackageData ) ;
2021-08-31 14:20:48 -04:00
}
}
2021-11-30 14:37:31 -05:00
}
2021-08-31 14:20:48 -04:00
2021-12-04 16:14:37 -05:00
FPackageData * FPackageDatas : : UpdateFileName ( FName PackageName )
2021-11-30 14:37:31 -05:00
{
2021-12-04 16:14:37 -05:00
FWriteScopeLock ExistenceWriteLock ( ExistenceLock ) ;
2021-11-30 14:37:31 -05:00
FPackageData * * PackageDataAddr = PackageNameToPackageData . Find ( PackageName ) ;
if ( ! PackageDataAddr )
{
2021-12-04 16:14:37 -05:00
FName NewFileName = LookupFileNameOnDisk ( PackageName ) ;
check ( NewFileName . IsNone ( ) | | ! FileNameToPackageData . Find ( NewFileName ) ) ;
2021-11-30 14:37:31 -05:00
return nullptr ;
}
FPackageData * PackageData = * PackageDataAddr ;
2021-12-04 16:14:37 -05:00
FName OldFileName = PackageData - > GetFileName ( ) ;
bool bIsMap = FPackageName : : IsMapPackageExtension ( * FPaths : : GetExtension ( OldFileName . ToString ( ) ) ) ;
FName NewFileName = LookupFileNameOnDisk ( PackageName , false /* bRequireExists */ , bIsMap ) ;
2021-11-30 14:37:31 -05:00
if ( OldFileName = = NewFileName )
{
return PackageData ;
}
2021-12-04 16:14:37 -05:00
if ( NewFileName . IsNone ( ) )
{
UE_LOG ( LogCook , Error , TEXT ( " Cannot update FileName for package %s because the package is no longer mounted. " ) ,
* PackageName . ToString ( ) )
return PackageData ;
}
check ( ! OldFileName . IsNone ( ) ) ;
FPackageData * ExistingByFileName ;
ensure ( FileNameToPackageData . RemoveAndCopyValue ( OldFileName , ExistingByFileName ) ) ;
check ( ExistingByFileName = = PackageData ) ;
2021-11-30 14:37:31 -05:00
PackageData - > SetFileName ( NewFileName ) ;
2021-12-04 16:14:37 -05:00
FPackageData * AddedByFileName = FileNameToPackageData . FindOrAdd ( NewFileName , PackageData ) ;
check ( AddedByFileName = = PackageData ) ;
2021-11-30 14:37:31 -05:00
return PackageData ;
}
int32 FPackageDatas : : GetNumCooked ( )
{
return Monitor . GetNumCooked ( ) ;
}
2021-12-04 16:14:37 -05:00
void FPackageDatas : : GetCookedPackagesForPlatform ( const ITargetPlatform * Platform , TArray < FPackageData * > & CookedPackages ,
2021-11-30 14:37:31 -05:00
bool bGetFailedCookedPackages , bool bGetSuccessfulCookedPackages )
{
2021-12-04 16:14:37 -05:00
for ( FPackageData * PackageData : PackageDatas )
2021-11-30 14:37:31 -05:00
{
ECookResult CookResults = PackageData - > GetCookResults ( Platform ) ;
if ( ( ( CookResults = = ECookResult : : Succeeded ) & ( bGetSuccessfulCookedPackages ! = 0 ) ) |
( ( CookResults = = ECookResult : : Failed ) & ( bGetFailedCookedPackages ! = 0 ) ) )
2020-06-23 18:40:00 -04:00
{
2021-12-04 16:14:37 -05:00
CookedPackages . Add ( PackageData ) ;
2021-11-30 14:37:31 -05:00
}
}
}
void FPackageDatas : : Clear ( )
{
2021-12-04 16:14:37 -05:00
FWriteScopeLock ExistenceWriteLock ( ExistenceLock ) ;
2021-11-30 14:37:31 -05:00
PendingCookedPlatformDatas . Empty ( ) ; // These destructors will dereference PackageDatas
RequestQueue . Empty ( ) ;
SaveQueue . Empty ( ) ;
PackageNameToPackageData . Empty ( ) ;
FileNameToPackageData . Empty ( ) ;
for ( FPackageData * PackageData : PackageDatas )
{
PackageData - > ClearReferences ( ) ;
}
for ( FPackageData * PackageData : PackageDatas )
{
delete PackageData ;
}
PackageDatas . Empty ( ) ;
ShowInstigatorPackageData = nullptr ;
}
void FPackageDatas : : ClearCookedPlatforms ( )
{
for ( FPackageData * PackageData : PackageDatas )
{
2022-02-07 01:52:26 -05:00
PackageData - > ClearCookProgress ( ) ;
2021-11-30 14:37:31 -05:00
}
}
void FPackageDatas : : OnRemoveSessionPlatform ( const ITargetPlatform * TargetPlatform )
{
for ( FPackageData * PackageData : PackageDatas )
{
PackageData - > OnRemoveSessionPlatform ( TargetPlatform ) ;
}
}
TArray < FPendingCookedPlatformData > & FPackageDatas : : GetPendingCookedPlatformDatas ( )
{
return PendingCookedPlatformDatas ;
}
2022-02-17 04:54:33 -05:00
void FPackageDatas : : PollPendingCookedPlatformDatas ( bool bForce )
2021-11-30 14:37:31 -05:00
{
if ( PendingCookedPlatformDatas . Num ( ) = = 0 )
{
return ;
}
2022-02-17 04:54:33 -05:00
if ( ! bForce )
2021-11-30 14:37:31 -05:00
{
2022-02-17 04:54:33 -05:00
// ProcessAsyncResults and IsCachedCookedPlatformDataLoaded can be expensive to call
// Cap the frequency at which we call them.
double CurrentTime = FPlatformTime : : Seconds ( ) ;
if ( CurrentTime < LastPollAsyncTime + GPollAsyncPeriod )
{
return ;
}
LastPollAsyncTime = CurrentTime ;
2021-11-30 14:37:31 -05:00
}
GShaderCompilingManager - > ProcessAsyncResults ( true /* bLimitExecutionTime */ ,
false /* bBlockOnGlobalShaderCompletion */ ) ;
FAssetCompilingManager : : Get ( ) . ProcessAsyncTasks ( true ) ;
FPendingCookedPlatformData * Datas = PendingCookedPlatformDatas . GetData ( ) ;
for ( int Index = 0 ; Index < PendingCookedPlatformDatas . Num ( ) ; )
{
if ( Datas [ Index ] . PollIsComplete ( ) )
{
PendingCookedPlatformDatas . RemoveAtSwap ( Index , 1 /* Count */ , false /* bAllowShrinking */ ) ;
2020-06-23 18:40:00 -04:00
}
else
{
2021-11-30 14:37:31 -05:00
+ + Index ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
TArray < FPackageData * > : : RangedForIteratorType FPackageDatas : : begin ( )
{
return PackageDatas . begin ( ) ;
}
TArray < FPackageData * > : : RangedForIteratorType FPackageDatas : : end ( )
{
return PackageDatas . end ( ) ;
}
void FPackageDatas : : RemapTargetPlatforms ( const TMap < ITargetPlatform * , ITargetPlatform * > & Remap )
{
for ( FPackageData * PackageData : PackageDatas )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
PackageData - > RemapTargetPlatforms ( Remap ) ;
}
for ( FPendingCookedPlatformData & CookedPlatformData : PendingCookedPlatformDatas )
{
CookedPlatformData . RemapTargetPlatforms ( Remap ) ;
}
}
void FPackageDatas : : DebugInstigator ( FPackageData & PackageData )
{
if ( ShowInstigatorPackageData ! = & PackageData )
{
return ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
TArray < FInstigator > Chain = CookOnTheFlyServer . GetInstigatorChain ( PackageData . GetPackageName ( ) ) ;
TStringBuilder < 256 > ChainText ;
if ( Chain . Num ( ) = = 0 )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
ChainText < < TEXT ( " <NoInstigator> " ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
bool bFirst = true ;
for ( FInstigator & Instigator : Chain )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
if ( ! bFirst ) ChainText < < TEXT ( " <- " ) ;
ChainText < < TEXT ( " { " ) < < Instigator . ToString ( ) < < TEXT ( " } " ) ;
bFirst = false ;
}
UE_LOG ( LogCook , Display , TEXT ( " Instigator chain of %s: %s " ) , * PackageData . GetPackageName ( ) . ToString ( ) , ChainText . ToString ( ) ) ;
}
void FRequestQueue : : Empty ( )
{
NormalRequests . Empty ( ) ;
UrgentRequests . Empty ( ) ;
}
bool FRequestQueue : : IsEmpty ( ) const
{
return Num ( ) = = 0 ;
}
uint32 FRequestQueue : : Num ( ) const
{
uint32 Count = UnclusteredRequests . Num ( ) + ReadyRequestsNum ( ) ;
for ( const FRequestCluster & RequestCluster : RequestClusters )
{
Count + = RequestCluster . NumPackageDatas ( ) ;
}
return Count ;
}
bool FRequestQueue : : Contains ( const FPackageData * InPackageData ) const
{
FPackageData * PackageData = const_cast < FPackageData * > ( InPackageData ) ;
if ( UnclusteredRequests . Contains ( PackageData ) | | NormalRequests . Contains ( PackageData ) | | UrgentRequests . Contains ( PackageData ) )
{
return true ;
}
for ( const FRequestCluster & RequestCluster : RequestClusters )
{
if ( RequestCluster . Contains ( PackageData ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
return true ;
2020-06-23 18:40:00 -04:00
}
}
2021-11-30 14:37:31 -05:00
return false ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
uint32 FRequestQueue : : RemoveRequest ( FPackageData * PackageData )
{
uint32 OriginalNum = Num ( ) ;
UnclusteredRequests . Remove ( PackageData ) ;
NormalRequests . Remove ( PackageData ) ;
UrgentRequests . Remove ( PackageData ) ;
for ( FRequestCluster & RequestCluster : RequestClusters )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
RequestCluster . RemovePackageData ( PackageData ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
uint32 Result = OriginalNum - Num ( ) ;
check ( Result = = 0 | | Result = = 1 ) ;
return Result ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
uint32 FRequestQueue : : Remove ( FPackageData * PackageData )
{
return RemoveRequest ( PackageData ) ;
}
bool FRequestQueue : : IsReadyRequestsEmpty ( ) const
{
return ReadyRequestsNum ( ) = = 0 ;
}
uint32 FRequestQueue : : ReadyRequestsNum ( ) const
{
return UrgentRequests . Num ( ) + NormalRequests . Num ( ) ;
}
FPackageData * FRequestQueue : : PopReadyRequest ( )
{
2022-05-18 13:18:13 -04:00
for ( auto Iterator = UrgentRequests . CreateIterator ( ) ; Iterator ; + + Iterator )
2020-06-23 18:40:00 -04:00
{
2022-05-18 13:18:13 -04:00
FPackageData * PackageData = * Iterator ;
Iterator . RemoveCurrent ( ) ;
2021-11-30 14:37:31 -05:00
return PackageData ;
2020-06-23 18:40:00 -04:00
}
2022-05-18 13:18:13 -04:00
for ( auto Iterator = NormalRequests . CreateIterator ( ) ; Iterator ; + + Iterator )
2020-06-23 18:40:00 -04:00
{
2022-05-18 13:18:13 -04:00
FPackageData * PackageData = * Iterator ;
Iterator . RemoveCurrent ( ) ;
2021-11-30 14:37:31 -05:00
return PackageData ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
return nullptr ;
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
void FRequestQueue : : AddRequest ( FPackageData * PackageData , bool bForceUrgent )
{
if ( ! PackageData - > AreAllRequestedPlatformsExplored ( ) )
2020-06-23 18:40:00 -04:00
{
2021-11-30 14:37:31 -05:00
UnclusteredRequests . Add ( PackageData ) ;
2020-06-23 18:40:00 -04:00
}
2021-11-30 14:37:31 -05:00
else
{
AddReadyRequest ( PackageData , bForceUrgent ) ;
}
}
2020-06-23 18:40:00 -04:00
2021-11-30 14:37:31 -05:00
void FRequestQueue : : AddReadyRequest ( FPackageData * PackageData , bool bForceUrgent )
{
if ( bForceUrgent | | PackageData - > GetIsUrgent ( ) )
{
UrgentRequests . Add ( PackageData ) ;
}
else
{
NormalRequests . Add ( PackageData ) ;
}
}
bool FLoadPrepareQueue : : IsEmpty ( )
{
return Num ( ) = = 0 ;
}
int32 FLoadPrepareQueue : : Num ( ) const
{
return PreloadingQueue . Num ( ) + EntryQueue . Num ( ) ;
}
FPackageData * FLoadPrepareQueue : : PopFront ( )
{
if ( ! PreloadingQueue . IsEmpty ( ) )
{
return PreloadingQueue . PopFrontValue ( ) ;
}
else
{
return EntryQueue . PopFrontValue ( ) ;
}
}
void FLoadPrepareQueue : : Add ( FPackageData * PackageData )
{
EntryQueue . Add ( PackageData ) ;
}
void FLoadPrepareQueue : : AddFront ( FPackageData * PackageData )
{
PreloadingQueue . AddFront ( PackageData ) ;
}
bool FLoadPrepareQueue : : Contains ( const FPackageData * PackageData ) const
{
return ( Algo : : Find ( PreloadingQueue , PackageData ) ! = nullptr ) | |
( Algo : : Find ( EntryQueue , PackageData ) ! = nullptr ) ;
}
uint32 FLoadPrepareQueue : : Remove ( FPackageData * PackageData )
{
return PreloadingQueue . Remove ( PackageData ) + EntryQueue . Remove ( PackageData ) ;
}
FPoppedPackageDataScope : : FPoppedPackageDataScope ( FPackageData & InPackageData )
2020-06-23 18:40:00 -04:00
# if COOK_CHECKSLOW_PACKAGEDATA
2021-11-30 14:37:31 -05:00
: PackageData ( InPackageData )
2020-06-23 18:40:00 -04:00
# endif
2021-11-30 14:37:31 -05:00
{
}
2020-06-23 18:40:00 -04:00
# if COOK_CHECKSLOW_PACKAGEDATA
2021-11-30 14:37:31 -05:00
FPoppedPackageDataScope : : ~ FPoppedPackageDataScope ( )
{
PackageData . CheckInContainer ( ) ;
}
2020-06-23 18:40:00 -04:00
# endif
2022-01-06 14:36:20 -05:00
}