1598 lines
46 KiB
C++
1598 lines
46 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CookPackageData.h"
|
|
|
|
#include "Algo/AnyOf.h"
|
|
#include "CookOnTheSide/CookOnTheFlyServer.h"
|
|
#include "CookPlatformManager.h"
|
|
#include "Containers/StringView.h"
|
|
#include "Misc/CoreMiscDefines.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/PreloadableFile.h"
|
|
#include "ShaderCompiler.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/Package.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
#include "UObject/UObjectHash.h"
|
|
#include "Cooker/MPCookTrace.h"
|
|
#include "Materials/MaterialInstanceConstant.h"
|
|
namespace UE
|
|
{
|
|
namespace Cook
|
|
{
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FPackageData
|
|
|
|
FPackageData::FPackageData(FPackageDatas& PackageDatas, const FName& InPackageName, const FName& InFileName)
|
|
: PackageName(InPackageName), FileName(InFileName), PackageDatas(PackageDatas), bIsUrgent(0), bIsVisited(0), bIsPreloadAttempted(0), bIsPreloaded(0), bHasSaveCache(0), bCookedPlatformDataStarted(0), bCookedPlatformDataCalled(0), bCookedPlatformDataComplete(0), bMonitorIsCooked(0)
|
|
{
|
|
SetState(EPackageState::Idle);
|
|
SendToState(EPackageState::Idle, ESendFlags::QueueAdd);
|
|
}
|
|
|
|
FPackageData::~FPackageData()
|
|
{
|
|
ClearCookedPlatforms(); // We need to send OnCookedPlatformRemoved message to the monitor, so it is not valid to destruct without calling ClearCookedPlatforms
|
|
SendToState(EPackageState::Idle, ESendFlags::QueueNone); // Update the monitor's counters and call exit functions
|
|
}
|
|
|
|
const FName& FPackageData::GetPackageName() const
|
|
{
|
|
return PackageName;
|
|
}
|
|
|
|
const FName& FPackageData::GetFileName() const
|
|
{
|
|
return FileName;
|
|
}
|
|
|
|
void FPackageData::SetFileName(const FName& InFileName)
|
|
{
|
|
FileName = InFileName;
|
|
}
|
|
|
|
const TArray<const ITargetPlatform*>& FPackageData::GetRequestedPlatforms() const
|
|
{
|
|
return RequestedPlatforms;
|
|
}
|
|
|
|
void FPackageData::SetRequestedPlatforms(const TArrayView<const ITargetPlatform* const>& Platforms)
|
|
{
|
|
RequestedPlatforms.Empty(Platforms.Num());
|
|
AddRequestedPlatforms(Platforms);
|
|
}
|
|
|
|
void FPackageData::AddRequestedPlatforms(const TArrayView<const ITargetPlatform* const>& New)
|
|
{
|
|
for (const ITargetPlatform* TargetPlatform: New)
|
|
{
|
|
RequestedPlatforms.AddUnique(TargetPlatform);
|
|
}
|
|
}
|
|
|
|
void FPackageData::ClearRequestedPlatforms()
|
|
{
|
|
RequestedPlatforms.Empty();
|
|
}
|
|
|
|
bool FPackageData::ContainsAllRequestedPlatforms(const TArrayView<const ITargetPlatform* const>& Platforms) const
|
|
{
|
|
if (Platforms.Num() == 0)
|
|
{
|
|
return true;
|
|
}
|
|
if (RequestedPlatforms.Num() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (const ITargetPlatform* QueryPlatform: Platforms)
|
|
{
|
|
if (!RequestedPlatforms.Contains(QueryPlatform))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FPackageData::SetIsUrgent(bool Value)
|
|
{
|
|
bool OldValue = static_cast<bool>(bIsUrgent);
|
|
if (OldValue != Value)
|
|
{
|
|
bIsUrgent = Value != 0;
|
|
PackageDatas.GetMonitor().OnUrgencyChanged(*this);
|
|
}
|
|
}
|
|
|
|
void FPackageData::UpdateRequestData(const TArrayView<const ITargetPlatform* const>& InRequestedPlatforms, bool bInIsUrgent,
|
|
FCompletionCallback&& InCompletionCallback, ESendFlags SendFlags)
|
|
{
|
|
if (IsInProgress())
|
|
{
|
|
AddCompletionCallback(MoveTemp(InCompletionCallback));
|
|
|
|
bool bUrgencyChanged = false;
|
|
if (bInIsUrgent && !GetIsUrgent())
|
|
{
|
|
bUrgencyChanged = true;
|
|
SetIsUrgent(true);
|
|
}
|
|
|
|
if (!ContainsAllRequestedPlatforms(InRequestedPlatforms))
|
|
{
|
|
// Send back to the Request state (canceling any current operations) and then add the new platforms
|
|
if (GetState() != EPackageState::Request)
|
|
{
|
|
check(SendFlags == ESendFlags::QueueAddAndRemove);
|
|
SendToState(EPackageState::Request, ESendFlags::QueueAddAndRemove);
|
|
}
|
|
AddRequestedPlatforms(InRequestedPlatforms);
|
|
}
|
|
else if (bUrgencyChanged && SendFlags == ESendFlags::QueueAddAndRemove)
|
|
{
|
|
SendToState(GetState(), SendFlags);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetRequestData(InRequestedPlatforms, bInIsUrgent, MoveTemp(InCompletionCallback));
|
|
SendToState(EPackageState::Request, SendFlags);
|
|
}
|
|
}
|
|
|
|
void FPackageData::SetRequestData(const TArrayView<const ITargetPlatform* const>& InRequestedPlatforms, bool bInIsUrgent, FCompletionCallback&& InCompletionCallback)
|
|
{
|
|
check(!CompletionCallback);
|
|
check(RequestedPlatforms.Num() == 0);
|
|
check(!bIsUrgent);
|
|
SetRequestedPlatforms(InRequestedPlatforms);
|
|
SetIsUrgent(bInIsUrgent);
|
|
AddCompletionCallback(MoveTemp(InCompletionCallback));
|
|
}
|
|
|
|
void FPackageData::ClearInProgressData()
|
|
{
|
|
ClearRequestedPlatforms();
|
|
SetIsUrgent(false);
|
|
CompletionCallback = FCompletionCallback();
|
|
}
|
|
|
|
void FPackageData::AddCookedPlatforms(const TArrayView<const ITargetPlatform* const>& New, const TArrayView<const bool>& Succeeded)
|
|
{
|
|
check(New.Num() == Succeeded.Num());
|
|
int32 Num = New.Num();
|
|
if (Num == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const ITargetPlatform* const* NewData = New.GetData();
|
|
const bool* SucceededData = Succeeded.GetData();
|
|
for (int32 n = 0; n < Num; ++n)
|
|
{
|
|
const ITargetPlatform* TargetPlatform = NewData[n];
|
|
bool bSucceeded = SucceededData[n];
|
|
|
|
int32 ExistingIndex = CookedPlatforms.IndexOfByKey(TargetPlatform);
|
|
if (ExistingIndex != INDEX_NONE)
|
|
{
|
|
CookSucceeded[ExistingIndex] = bSucceeded;
|
|
}
|
|
else
|
|
{
|
|
CookedPlatforms.Add(TargetPlatform);
|
|
CookSucceeded.Add(bSucceeded);
|
|
}
|
|
}
|
|
|
|
PackageDatas.GetMonitor().OnCookedPlatformAdded(*this);
|
|
}
|
|
|
|
void FPackageData::AddCookedPlatforms(const TArrayView<const ITargetPlatform* const>& New, bool bSucceeded)
|
|
{
|
|
int32 Num = New.Num();
|
|
if (Num == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (const ITargetPlatform* TargetPlatform: New)
|
|
{
|
|
int32 ExistingIndex = CookedPlatforms.IndexOfByKey(TargetPlatform);
|
|
if (ExistingIndex != INDEX_NONE)
|
|
{
|
|
CookSucceeded[ExistingIndex] = bSucceeded;
|
|
}
|
|
else
|
|
{
|
|
CookedPlatforms.Add(TargetPlatform);
|
|
CookSucceeded.Add(bSucceeded);
|
|
}
|
|
}
|
|
|
|
PackageDatas.GetMonitor().OnCookedPlatformAdded(*this);
|
|
}
|
|
|
|
void FPackageData::RemoveCookedPlatform(const ITargetPlatform* Platform)
|
|
{
|
|
int32 Num = CookedPlatforms.Num();
|
|
for (int32 n = CookedPlatforms.Num() - 1; n >= 0; --n)
|
|
{
|
|
if (CookedPlatforms[n] == Platform)
|
|
{
|
|
CookedPlatforms.RemoveAtSwap(n);
|
|
CookSucceeded.RemoveAtSwap(n);
|
|
PackageDatas.GetMonitor().OnCookedPlatformRemoved(*this);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FPackageData::RemoveCookedPlatforms(const TArrayView<const ITargetPlatform* const>& Platforms)
|
|
{
|
|
for (const ITargetPlatform* Platform: Platforms)
|
|
{
|
|
RemoveCookedPlatform(Platform);
|
|
}
|
|
}
|
|
|
|
void FPackageData::ClearCookedPlatforms()
|
|
{
|
|
if (CookedPlatforms.Num() > 0)
|
|
{
|
|
CookedPlatforms.Empty();
|
|
CookSucceeded.Empty();
|
|
PackageDatas.GetMonitor().OnCookedPlatformRemoved(*this);
|
|
}
|
|
}
|
|
|
|
const TArray<const ITargetPlatform*>& FPackageData::GetCookedPlatforms() const
|
|
{
|
|
return CookedPlatforms;
|
|
}
|
|
|
|
int32 FPackageData::GetNumCookedPlatforms() const
|
|
{
|
|
return CookedPlatforms.Num();
|
|
}
|
|
|
|
bool FPackageData::HasAnyCookedPlatform() const
|
|
{
|
|
return CookedPlatforms.Num() > 0;
|
|
}
|
|
|
|
bool FPackageData::HasAnyCookedPlatforms(const TArrayView<const ITargetPlatform* const>& Platforms, bool bIncludeFailed) const
|
|
{
|
|
if (CookedPlatforms.Num() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (const ITargetPlatform* QueryPlatform: Platforms)
|
|
{
|
|
if (HasCookedPlatform(QueryPlatform, bIncludeFailed))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FPackageData::HasAllCookedPlatforms(const TArrayView<const ITargetPlatform* const>& Platforms, bool bIncludeFailed) const
|
|
{
|
|
if (Platforms.Num() == 0)
|
|
{
|
|
return true;
|
|
}
|
|
if (CookedPlatforms.Num() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (const ITargetPlatform* QueryPlatform: Platforms)
|
|
{
|
|
if (!HasCookedPlatform(QueryPlatform, bIncludeFailed))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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
|
|
{
|
|
int32 Num = CookedPlatforms.Num();
|
|
for (int n = 0; n < Num; ++n)
|
|
{
|
|
if (CookedPlatforms[n] == Platform)
|
|
{
|
|
return CookSucceeded[n] ? 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 of the multi-state properties and sets them based on the given state */
|
|
struct FStateProperties
|
|
{
|
|
EPackageStateProperty Properties;
|
|
explicit FStateProperties(EPackageState InState)
|
|
{
|
|
switch (InState)
|
|
{
|
|
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;
|
|
case EPackageState::WaitAssign:
|
|
Properties = EPackageStateProperty::InProgress | EPackageStateProperty::WaitAssignProperty;
|
|
break;
|
|
default:
|
|
check(false);
|
|
Properties = EPackageStateProperty::None;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
void FPackageData::SendToState(EPackageState NextState, ESendFlags SendFlags)
|
|
{
|
|
EPackageState OldState = GetState();
|
|
if (CookTrace::IsTargetPackage(PackageName))
|
|
{
|
|
UE_LOG(LogMPCookTrace, Display, TEXT("SendToState %s %d %d"), *PackageName.ToString(), int(OldState), int(NextState));
|
|
if (Package.IsValid())
|
|
{
|
|
for (FObjectIterator It; It; ++It)
|
|
{
|
|
if (It->GetOutermost() == Package.Get())
|
|
{
|
|
if (UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(*It))
|
|
{
|
|
if (CookTrace::IsTargetPackage(BPClass->GetFName()))
|
|
{
|
|
UE_LOG(LogMPCookTrace, Display, TEXT("Blueprint %s has ClassFlags: %u"), *BPClass->GetName(), BPClass->ClassFlags);
|
|
}
|
|
}
|
|
else if (UMaterialInstanceConstant* MI = Cast<UMaterialInstanceConstant>(*It))
|
|
{
|
|
if (CookTrace::IsTargetPackage(MI->GetFName()))
|
|
{
|
|
FString ParentName = MI->Parent ? MI->Parent->GetPathName() : TEXT("None");
|
|
UE_LOG(LogMPCookTrace, Display, TEXT("MaterialInstance %s has Parent: %s"), *MI->GetName(), *ParentName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
switch (OldState)
|
|
{
|
|
case EPackageState::Idle:
|
|
OnExitIdle();
|
|
break;
|
|
case EPackageState::Request:
|
|
if (!!(SendFlags & ESendFlags::QueueRemove))
|
|
{
|
|
ensure(PackageDatas.GetRequestQueue().Remove(this) == 1);
|
|
}
|
|
OnExitRequest();
|
|
break;
|
|
case EPackageState::LoadPrepare:
|
|
if (!!(SendFlags & ESendFlags::QueueRemove))
|
|
{
|
|
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;
|
|
case EPackageState::WaitAssign:
|
|
if (!!(SendFlags & ESendFlags::QueueRemove))
|
|
{
|
|
ensure(PackageDatas.GetWaitAssignSet().Remove(this) == 1);
|
|
}
|
|
OnExitWaitAssign();
|
|
break;
|
|
default:
|
|
check(false);
|
|
break;
|
|
}
|
|
|
|
FStateProperties OldProperties(OldState);
|
|
FStateProperties NewProperties(NextState);
|
|
// Exit state properties in order from highest to lowest, then enter state properties in order 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)
|
|
{
|
|
case EPackageStateProperty::InProgress:
|
|
OnExitInProgress();
|
|
break;
|
|
case EPackageStateProperty::Loading:
|
|
OnExitLoading();
|
|
break;
|
|
case EPackageStateProperty::HasPackage:
|
|
OnExitHasPackage();
|
|
break;
|
|
case EPackageStateProperty::WaitAssignProperty:
|
|
OnExitWaitAssignProperty();
|
|
break;
|
|
default:
|
|
check(false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (EPackageStateProperty Iterator = EPackageStateProperty::Min; Iterator <= EPackageStateProperty::Max; Iterator = static_cast<EPackageStateProperty>(static_cast<uint32>(Iterator) << 1))
|
|
{
|
|
if (((OldProperties.Properties & Iterator) == EPackageStateProperty::None) & ((NewProperties.Properties & Iterator) != EPackageStateProperty::None))
|
|
{
|
|
switch (Iterator)
|
|
{
|
|
case EPackageStateProperty::InProgress:
|
|
OnEnterInProgress();
|
|
break;
|
|
case EPackageStateProperty::Loading:
|
|
OnEnterLoading();
|
|
break;
|
|
case EPackageStateProperty::HasPackage:
|
|
OnEnterHasPackage();
|
|
break;
|
|
case EPackageStateProperty::WaitAssignProperty:
|
|
OnEnterWaitAssignProperty();
|
|
break;
|
|
default:
|
|
check(false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetState(NextState);
|
|
switch (NextState)
|
|
{
|
|
case EPackageState::Idle:
|
|
OnEnterIdle();
|
|
break;
|
|
case EPackageState::Request:
|
|
OnEnterRequest();
|
|
if (((SendFlags & ESendFlags::QueueAdd) != ESendFlags::QueueNone))
|
|
{
|
|
PackageDatas.GetRequestQueue().AddRequest(this);
|
|
}
|
|
break;
|
|
case EPackageState::LoadPrepare:
|
|
OnEnterLoadPrepare();
|
|
if ((SendFlags & ESendFlags::QueueAdd) != ESendFlags::QueueNone)
|
|
{
|
|
if (GetIsUrgent())
|
|
{
|
|
PackageDatas.GetLoadPrepareQueue().AddFront(this);
|
|
}
|
|
else
|
|
{
|
|
PackageDatas.GetLoadPrepareQueue().Add(this);
|
|
}
|
|
}
|
|
break;
|
|
case EPackageState::LoadReady:
|
|
OnEnterLoadReady();
|
|
if ((SendFlags & ESendFlags::QueueAdd) != ESendFlags::QueueNone)
|
|
{
|
|
if (GetIsUrgent())
|
|
{
|
|
PackageDatas.GetLoadReadyQueue().AddFront(this);
|
|
}
|
|
else
|
|
{
|
|
PackageDatas.GetLoadReadyQueue().Add(this);
|
|
}
|
|
}
|
|
break;
|
|
case EPackageState::Save:
|
|
OnEnterSave();
|
|
if (((SendFlags & ESendFlags::QueueAdd) != ESendFlags::QueueNone))
|
|
{
|
|
if (GetIsUrgent())
|
|
{
|
|
PackageDatas.GetSaveQueue().AddFront(this);
|
|
}
|
|
else
|
|
{
|
|
PackageDatas.GetSaveQueue().Add(this);
|
|
}
|
|
}
|
|
break;
|
|
case EPackageState::WaitAssign:
|
|
OnEnterWaitAssign();
|
|
if (((SendFlags & ESendFlags::QueueAdd) != ESendFlags::QueueNone))
|
|
{
|
|
PackageDatas.GetWaitAssignSet().Add(this);
|
|
}
|
|
break;
|
|
default:
|
|
check(false);
|
|
break;
|
|
}
|
|
|
|
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:
|
|
check(Algo::Find(PackageDatas.GetSaveQueue(), this) != nullptr);
|
|
break;
|
|
case EPackageState::WaitAssign:
|
|
check(PackageDatas.GetWaitAssignSet().Contains(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()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnEnterRequest()
|
|
{
|
|
check(RequestedPlatforms.Num() > 0); // 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
|
|
}
|
|
|
|
void FPackageData::OnExitRequest()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnEnterLoadPrepare()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnExitLoadPrepare()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnEnterLoadReady()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnExitLoadReady()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnEnterSave()
|
|
{
|
|
check(GetPackage() != nullptr && GetPackage()->IsFullyLoaded());
|
|
|
|
CheckObjectCacheEmpty();
|
|
CheckCookedPlatformDataEmpty();
|
|
}
|
|
|
|
void FPackageData::OnExitSave()
|
|
{
|
|
PackageDatas.GetCookOnTheFlyServer().ReleaseCookedPlatformData(*this);
|
|
ClearObjectCache();
|
|
}
|
|
|
|
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();
|
|
}
|
|
ClearInProgressData();
|
|
}
|
|
|
|
void FPackageData::OnEnterLoading()
|
|
{
|
|
CheckPreloadEmpty();
|
|
}
|
|
|
|
void FPackageData::OnExitLoading()
|
|
{
|
|
ClearPreload();
|
|
}
|
|
|
|
void FPackageData::OnEnterHasPackage()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnExitHasPackage()
|
|
{
|
|
SetPackage(nullptr);
|
|
}
|
|
|
|
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();
|
|
SetIsPreloadAttempted(true);
|
|
return true;
|
|
}
|
|
if (GAllowCookedDataInEditorBuilds)
|
|
{
|
|
// Use of preloaded files is not yet implemented when GAllowCookedDataInEditorBuilds is on, see FLinkerLoad::CreateLoader
|
|
SetIsPreloadAttempted(true);
|
|
return true;
|
|
}
|
|
if (!PreloadableFile.Get())
|
|
{
|
|
TStringBuilder<NAME_SIZE> FileNameString;
|
|
GetFileName().ToString(FileNameString);
|
|
PreloadableFile.Set(MakeShared<FPreloadableFile>(FileNameString.ToString()), *this);
|
|
PreloadableFile.Get()->InitializeAsync(FPreloadableFile::Flags::PreloadHandle | FPreloadableFile::Flags::Prime);
|
|
}
|
|
const TSharedPtr<FPreloadableFile>& 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());
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (FilePtr->TotalSize() < 0)
|
|
{
|
|
UE_LOG(LogCook, Warning, TEXT("Failed to find file when preloading %s."), *GetFileName().ToString());
|
|
SetIsPreloadAttempted(true);
|
|
PreloadableFile.Reset(*this);
|
|
return true;
|
|
}
|
|
|
|
if (!FPreloadableFile::TryRegister(FilePtr))
|
|
{
|
|
UE_LOG(LogCook, Warning, TEXT("Duplicate attempts to register %s for preload."), *GetFileName().ToString());
|
|
SetIsPreloadAttempted(true);
|
|
PreloadableFile.Reset(*this);
|
|
return true;
|
|
}
|
|
|
|
SetIsPreloaded(true);
|
|
SetIsPreloadAttempted(true);
|
|
return true;
|
|
}
|
|
|
|
void FPackageData::FTrackedPreloadableFilePtr::Set(TSharedPtr<FPreloadableFile>&& 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<FPreloadableFile>& FilePtr = PreloadableFile.Get();
|
|
if (GetIsPreloaded())
|
|
{
|
|
check(FilePtr);
|
|
if (FPreloadableFile::UnRegister(FilePtr))
|
|
{
|
|
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());
|
|
check(!FilePtr || !FPreloadableFile::UnRegister(FilePtr));
|
|
}
|
|
|
|
PreloadableFile.Reset(*this);
|
|
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);
|
|
if (!ObjectWeakPointer.Get()) // ignore pending kill objects; they will not be serialized out so we don't need to call BeginCacheForCookedPlatformData on them
|
|
{
|
|
continue;
|
|
}
|
|
CachedObjectsInOuter.Emplace(MoveTemp(ObjectWeakPointer));
|
|
}
|
|
SetHasSaveCache(true);
|
|
}
|
|
else
|
|
{
|
|
check(false);
|
|
}
|
|
}
|
|
|
|
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::OnRemoveSessionPlatform(const ITargetPlatform* Platform)
|
|
{
|
|
RequestedPlatforms.RemoveSwap(Platform);
|
|
}
|
|
|
|
bool FPackageData::HasReferencedObjects() const
|
|
{
|
|
return Package != nullptr || CachedObjectsInOuter.Num() > 0;
|
|
}
|
|
|
|
void FPackageData::RemapTargetPlatforms(const TMap<ITargetPlatform*, ITargetPlatform*>& Remap)
|
|
{
|
|
RemapArrayElements(RequestedPlatforms, Remap);
|
|
RemapArrayElements(CookedPlatforms, Remap);
|
|
}
|
|
|
|
bool FPackageData::IsSaveInvalidated() const
|
|
{
|
|
if (GetState() != EPackageState::Save)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return GetPackage() == nullptr || !GetPackage()->IsFullyLoaded() ||
|
|
Algo::AnyOf(CachedObjectsInOuter, [](const FWeakObjectPtr& WeakPtr)
|
|
{
|
|
// 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;
|
|
});
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 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 || LocalObject->IsCachedCookedPlatformDataLoaded(TargetPlatform))
|
|
{
|
|
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);
|
|
check(CurrentAsyncCache != nullptr); // bNeedsRelease should not have been set if the AsyncCache does not have an entry for the class
|
|
*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::OnCookedPlatformAdded(FPackageData& PackageData)
|
|
{
|
|
if (!PackageData.GetMonitorIsCooked())
|
|
{
|
|
++NumCooked;
|
|
PackageData.SetMonitorIsCooked(true);
|
|
}
|
|
}
|
|
|
|
void FPackageDataMonitor::OnCookedPlatformRemoved(FPackageData& PackageData)
|
|
{
|
|
if (PackageData.GetNumCookedPlatforms() == 0)
|
|
{
|
|
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
|
|
|
|
FPackageDatas::FPackageDatas(UCookOnTheFlyServer& InCookOnTheFlyServer)
|
|
: CookOnTheFlyServer(InCookOnTheFlyServer)
|
|
{
|
|
}
|
|
|
|
FPackageDatas::~FPackageDatas()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
FString FPackageDatas::GetReferencerName() const
|
|
{
|
|
return TEXT("FPackageDatas");
|
|
}
|
|
|
|
void FPackageDatas::AddReferencedObjects(FReferenceCollector& Collector)
|
|
{
|
|
return CookOnTheFlyServer.CookerAddReferencedObjects(Collector);
|
|
}
|
|
|
|
const FPackageNameCache& FPackageDatas::GetPackageNameCache() const
|
|
{
|
|
return PackageNameCache;
|
|
}
|
|
|
|
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)
|
|
{
|
|
FPackageData** PackageDataMapAddr = PackageNameToPackageData.Find(PackageName);
|
|
if (PackageDataMapAddr != nullptr)
|
|
{
|
|
FPackageData** FileNameMapAddr = FileNameToPackageData.Find(NormalizedFileName);
|
|
check(FileNameMapAddr && *FileNameMapAddr == *PackageDataMapAddr);
|
|
return **PackageDataMapAddr;
|
|
}
|
|
|
|
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());
|
|
return CreatePackageData(PackageName, NormalizedFileName);
|
|
}
|
|
|
|
FPackageData* FPackageDatas::FindPackageDataByPackageName(const FName& PackageName)
|
|
{
|
|
if (PackageName.IsNone())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FPackageData** PackageDataMapAddr = PackageNameToPackageData.Find(PackageName);
|
|
return PackageDataMapAddr ? *PackageDataMapAddr : nullptr;
|
|
}
|
|
|
|
FPackageData* FPackageDatas::TryAddPackageDataByPackageName(const FName& PackageName)
|
|
{
|
|
if (PackageName.IsNone())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FPackageData** PackageDataMapAddr = PackageNameToPackageData.Find(PackageName);
|
|
if (PackageDataMapAddr != nullptr)
|
|
{
|
|
return *PackageDataMapAddr;
|
|
}
|
|
|
|
FName FileName = PackageNameCache.GetCachedStandardFileName(PackageName);
|
|
if (FileName.IsNone())
|
|
{
|
|
// This can happen if PackageName is a script package
|
|
return nullptr;
|
|
}
|
|
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());
|
|
return &CreatePackageData(PackageName, FileName);
|
|
}
|
|
|
|
FPackageData& FPackageDatas::AddPackageDataByPackageNameChecked(const FName& PackageName)
|
|
{
|
|
FPackageData* PackageData = TryAddPackageDataByPackageName(PackageName);
|
|
check(PackageData);
|
|
return *PackageData;
|
|
}
|
|
|
|
FPackageData* FPackageDatas::FindPackageDataByFileName(const FName& InFileName)
|
|
{
|
|
FName FileName(FPackageNameCache::GetStandardFileName(InFileName));
|
|
if (FileName.IsNone())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FPackageData** PackageDataMapAddr = FileNameToPackageData.Find(FileName);
|
|
return PackageDataMapAddr ? *PackageDataMapAddr : nullptr;
|
|
}
|
|
|
|
FPackageData* FPackageDatas::TryAddPackageDataByFileName(const FName& InFileName)
|
|
{
|
|
FName FileName(FPackageNameCache::GetStandardFileName(InFileName));
|
|
if (FileName.IsNone())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FPackageData** PackageDataMapAddr = FileNameToPackageData.Find(FileName);
|
|
if (PackageDataMapAddr != nullptr)
|
|
{
|
|
return *PackageDataMapAddr;
|
|
}
|
|
|
|
const FName* PackageName = PackageNameCache.GetCachedPackageNameFromStandardFileName(FileName);
|
|
if (!PackageName)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return &CreatePackageData(*PackageName, FileName);
|
|
}
|
|
|
|
FPackageData& FPackageDatas::CreatePackageData(FName PackageName, FName FileName)
|
|
{
|
|
if (PackageName.IsNone())
|
|
{
|
|
check(!FileName.IsNone());
|
|
const FName* FoundPackageName = PackageNameCache.GetCachedPackageNameFromStandardFileName(FileName);
|
|
check(FoundPackageName);
|
|
PackageName = *FoundPackageName;
|
|
check(!PackageName.IsNone());
|
|
}
|
|
else if (FileName.IsNone())
|
|
{
|
|
FileName = PackageNameCache.GetCachedStandardFileName(PackageName);
|
|
check(!FileName.IsNone());
|
|
}
|
|
|
|
FPackageData* PackageData = new FPackageData(*this, PackageName, FileName);
|
|
PackageDatas.Add(PackageData);
|
|
PackageNameToPackageData.Add(PackageName, PackageData);
|
|
FileNameToPackageData.Add(FileName, PackageData);
|
|
return *PackageData;
|
|
}
|
|
|
|
FPackageData& FPackageDatas::AddPackageDataByFileNameChecked(const FName& FileName)
|
|
{
|
|
FPackageData* PackageData = TryAddPackageDataByFileName(FileName);
|
|
check(PackageData);
|
|
return *PackageData;
|
|
}
|
|
|
|
FPackageData* FPackageDatas::UpdateFileName(const FName& PackageName)
|
|
{
|
|
if (!PackageNameCache.HasCacheForPackageName(PackageName))
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FName OldFileName = PackageNameCache.GetCachedStandardFileName(PackageName);
|
|
PackageNameCache.ClearPackageFileNameCacheForPackage(PackageName);
|
|
FName NewFileName = PackageNameCache.GetCachedStandardFileName(PackageName);
|
|
|
|
FPackageData** PackageDataAddr = PackageNameToPackageData.Find(PackageName);
|
|
if (!PackageDataAddr)
|
|
{
|
|
check(OldFileName.IsNone() || !FileNameToPackageData.Find(OldFileName));
|
|
return nullptr;
|
|
}
|
|
FPackageData* PackageData = *PackageDataAddr;
|
|
|
|
if (OldFileName == NewFileName)
|
|
{
|
|
return PackageData;
|
|
}
|
|
|
|
if (!OldFileName.IsNone())
|
|
{
|
|
PackageDataAddr = FileNameToPackageData.Find(OldFileName);
|
|
check(PackageDataAddr == nullptr || *PackageDataAddr == PackageData);
|
|
FileNameToPackageData.Remove(OldFileName);
|
|
}
|
|
PackageData->SetFileName(NewFileName);
|
|
if (!NewFileName.IsNone())
|
|
{
|
|
check(FileNameToPackageData.Find(NewFileName) == nullptr);
|
|
FileNameToPackageData.Add(NewFileName, PackageData);
|
|
}
|
|
|
|
return PackageData;
|
|
}
|
|
|
|
void FPackageDatas::RegisterFileNameAlias(FPackageData& PackageData, FName FileName)
|
|
{
|
|
FileName = FPackageNameCache::GetStandardFileName(FileName);
|
|
if (FileName.IsNone())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FPackageData*& PackageDataMapAddr = FileNameToPackageData.FindOrAdd(FileName);
|
|
check(PackageDataMapAddr == nullptr || PackageDataMapAddr == &PackageData);
|
|
PackageDataMapAddr = &PackageData;
|
|
}
|
|
|
|
int32 FPackageDatas::GetNumCooked()
|
|
{
|
|
return Monitor.GetNumCooked();
|
|
}
|
|
|
|
void FPackageDatas::GetCookedFileNamesForPlatform(const ITargetPlatform* Platform, TArray<FName>& CookedFiles, bool bGetFailedCookedPackages, bool bGetSuccessfulCookedPackages)
|
|
{
|
|
for (const FPackageData* PackageData: PackageDatas)
|
|
{
|
|
ECookResult CookResults = PackageData->GetCookResults(Platform);
|
|
if (((CookResults == ECookResult::Succeeded) & (bGetSuccessfulCookedPackages != 0)) |
|
|
((CookResults == ECookResult::Failed) & (bGetFailedCookedPackages != 0)))
|
|
{
|
|
CookedFiles.Add(PackageData->GetFileName());
|
|
}
|
|
}
|
|
}
|
|
|
|
void FPackageDatas::Clear()
|
|
{
|
|
PendingCookedPlatformDatas.Empty(); // These destructors will dereference PackageDatas
|
|
RequestQueue.Empty();
|
|
SaveQueue.Empty();
|
|
PackageNameToPackageData.Empty();
|
|
FileNameToPackageData.Empty();
|
|
for (FPackageData* PackageData: PackageDatas)
|
|
{
|
|
delete PackageData;
|
|
}
|
|
PackageDatas.Empty();
|
|
}
|
|
|
|
void FPackageDatas::ClearCookedPlatforms()
|
|
{
|
|
for (FPackageData* PackageData: PackageDatas)
|
|
{
|
|
PackageData->ClearCookedPlatforms();
|
|
}
|
|
}
|
|
|
|
void FPackageDatas::OnRemoveSessionPlatform(const ITargetPlatform* TargetPlatform)
|
|
{
|
|
for (FPackageData* PackageData: PackageDatas)
|
|
{
|
|
PackageData->OnRemoveSessionPlatform(TargetPlatform);
|
|
}
|
|
}
|
|
|
|
TArray<FPendingCookedPlatformData>& FPackageDatas::GetPendingCookedPlatformDatas()
|
|
{
|
|
return PendingCookedPlatformDatas;
|
|
}
|
|
|
|
void FPackageDatas::PollPendingCookedPlatformDatas()
|
|
{
|
|
if (PendingCookedPlatformDatas.Num() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GShaderCompilingManager->ProcessAsyncResults(true /* bLimitExecutionTime */, false /* bBlockOnGlobalShaderCompletion */);
|
|
|
|
FPendingCookedPlatformData* Datas = PendingCookedPlatformDatas.GetData();
|
|
for (int Index = 0; Index < PendingCookedPlatformDatas.Num();)
|
|
{
|
|
if (Datas[Index].PollIsComplete())
|
|
{
|
|
PendingCookedPlatformDatas.RemoveAtSwap(Index, 1 /* Count */, false /* bAllowShrinking */);
|
|
}
|
|
else
|
|
{
|
|
++Index;
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
PackageData->RemapTargetPlatforms(Remap);
|
|
}
|
|
for (FPendingCookedPlatformData& CookedPlatformData: PendingCookedPlatformDatas)
|
|
{
|
|
CookedPlatformData.RemapTargetPlatforms(Remap);
|
|
}
|
|
}
|
|
|
|
TFastPointerSet<FPackageData*>& FPackageDatas::GetWaitAssignSet()
|
|
{
|
|
return WaitAssignSet;
|
|
}
|
|
|
|
void FPackageData::OnExitWaitAssign()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnEnterWaitAssign()
|
|
{
|
|
}
|
|
|
|
void FPackageData::OnExitWaitAssignProperty()
|
|
{
|
|
// SetWorkerAssignment(FWorkerId::Invalid());
|
|
}
|
|
|
|
void FPackageData::OnEnterWaitAssignProperty()
|
|
{
|
|
}
|
|
|
|
void FRequestQueue::Empty()
|
|
{
|
|
NormalRequests.Empty();
|
|
UrgentRequests.Empty();
|
|
}
|
|
|
|
bool FRequestQueue::IsEmpty() const
|
|
{
|
|
return Num() == 0;
|
|
}
|
|
|
|
uint32 FRequestQueue::Num() const
|
|
{
|
|
return NormalRequests.Num() + UrgentRequests.Num();
|
|
}
|
|
|
|
bool FRequestQueue::Contains(const FPackageData* InPackageData) const
|
|
{
|
|
FPackageData* PackageData = const_cast<FPackageData*>(InPackageData);
|
|
return NormalRequests.Contains(PackageData) || UrgentRequests.Contains(PackageData);
|
|
}
|
|
|
|
uint32 FRequestQueue::RemoveRequest(FPackageData* PackageData)
|
|
{
|
|
uint32 OriginalNum = NormalRequests.Num() + UrgentRequests.Num();
|
|
NormalRequests.Remove(PackageData);
|
|
UrgentRequests.Remove(PackageData);
|
|
uint32 Result = OriginalNum - (NormalRequests.Num() + UrgentRequests.Num());
|
|
check(Result == 0 || Result == 1);
|
|
return Result;
|
|
}
|
|
|
|
uint32 FRequestQueue::Remove(FPackageData* PackageData)
|
|
{
|
|
return RemoveRequest(PackageData);
|
|
}
|
|
|
|
FPackageData* FRequestQueue::PopRequest()
|
|
{
|
|
for (FPackageData* PackageData: UrgentRequests)
|
|
{
|
|
UrgentRequests.Remove(PackageData);
|
|
return PackageData;
|
|
}
|
|
for (FPackageData* PackageData: NormalRequests)
|
|
{
|
|
NormalRequests.Remove(PackageData);
|
|
return PackageData;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void FRequestQueue::AddRequest(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)
|
|
#if COOK_CHECKSLOW_PACKAGEDATA
|
|
: PackageData(InPackageData)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
#if COOK_CHECKSLOW_PACKAGEDATA
|
|
FPoppedPackageDataScope::~FPoppedPackageDataScope()
|
|
{
|
|
PackageData.CheckInContainer();
|
|
}
|
|
#endif
|
|
|
|
} // namespace Cook
|
|
} // namespace UE
|