EM_Task/UnrealEd/Private/Cooker/PackageTracker.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

215 lines
5.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/Array.h"
#include "Containers/RingBuffer.h"
#include "Containers/Set.h"
#include "CookRequests.h"
#include "CookTypes.h"
#include "HAL/CriticalSection.h"
#include "INetworkFileSystemModule.h"
#include "Misc/ScopeLock.h"
#include "Templates/UnrealTemplate.h"
#include "UObject/NameTypes.h"
#include "UObject/UObjectArray.h"
class ITargetPlatform;
class UPackage;
namespace UE
{
namespace Cook
{
struct FPackageDatas;
struct FRecompileRequest;
/** Helper to pass a recompile request to game thread */
struct FRecompileRequest
{
struct FShaderRecompileData RecompileData;
volatile bool bComplete = false;
};
template <typename Type>
struct FThreadSafeQueue
{
private:
mutable FCriticalSection SynchronizationObject; // made this mutable so this class can have const functions and still be thread safe
TRingBuffer<Type> Items;
public:
void Enqueue(const Type& Item)
{
FScopeLock ScopeLock(&SynchronizationObject);
Items.Add(Item);
}
void EnqueueUnique(const Type& Item)
{
FScopeLock ScopeLock(&SynchronizationObject);
for (const Type& Existing: Items)
{
if (Existing == Item)
{
return;
}
}
Items.PushBack(Item);
}
bool Dequeue(Type* Result)
{
FScopeLock ScopeLock(&SynchronizationObject);
if (Items.Num())
{
*Result = Items.PopFrontValue();
return true;
}
return false;
}
void DequeueAll(TArray<Type>& Results)
{
FScopeLock ScopeLock(&SynchronizationObject);
Results.Reserve(Results.Num() + Items.Num());
while (!Items.IsEmpty())
{
Results.Add(Items.PopFrontValue());
}
}
bool HasItems() const
{
FScopeLock ScopeLock(&SynchronizationObject);
return Items.Num() > 0;
}
void Remove(const Type& Item)
{
FScopeLock ScopeLock(&SynchronizationObject);
Items.Remove(Item);
}
void CopyItems(const TArray<Type>& InItems) const
{
FScopeLock ScopeLock(&SynchronizationObject);
Items.Empty(InItems.Num());
for (const Type& Item: InItems)
{
Items.PushBack(Item);
}
}
int Num() const
{
FScopeLock ScopeLock(&SynchronizationObject);
return Items.Num();
}
void Empty()
{
FScopeLock ScopeLock(&SynchronizationObject);
Items.Empty();
}
};
/** Simple thread safe proxy for TSet<FName> */
template <typename T>
class FThreadSafeSet
{
TSet<T> InnerSet;
FCriticalSection SetCritical;
public:
void Add(T InValue)
{
FScopeLock SetLock(&SetCritical);
InnerSet.Add(InValue);
}
bool AddUnique(T InValue)
{
FScopeLock SetLock(&SetCritical);
if (!InnerSet.Contains(InValue))
{
InnerSet.Add(InValue);
return true;
}
return false;
}
bool Contains(T InValue)
{
FScopeLock SetLock(&SetCritical);
return InnerSet.Contains(InValue);
}
void Remove(T InValue)
{
FScopeLock SetLock(&SetCritical);
InnerSet.Remove(InValue);
}
void Empty()
{
FScopeLock SetLock(&SetCritical);
InnerSet.Empty();
}
void GetValues(TSet<T>& OutSet)
{
FScopeLock SetLock(&SetCritical);
OutSet.Append(InnerSet);
}
};
struct FThreadSafeUnsolicitedPackagesList
{
void AddCookedPackage(const FFilePlatformRequest& PlatformRequest);
void GetPackagesForPlatformAndRemove(const ITargetPlatform* Platform, TArray<FName>& PackageNames);
void Empty();
private:
FCriticalSection SyncObject;
TArray<FFilePlatformRequest> CookedPackages;
};
struct FPackageTracker: public FUObjectArray::FUObjectCreateListener
, public FUObjectArray::FUObjectDeleteListener
{
public:
FPackageTracker(FPackageDatas& InPackageDatas);
~FPackageTracker();
/* Returns all packages that have been loaded since the last time GetNewPackages was called */
TArray<UPackage*> GetNewPackages();
virtual void NotifyUObjectCreated(const class UObjectBase* Object, int32 Index) override;
virtual void NotifyUObjectDeleted(const class UObjectBase* Object, int32 Index) override;
virtual void OnUObjectArrayShutdown() override;
/** Swap all ITargetPlatform* stored on this instance according to the mapping in @param Remap. */
void RemapTargetPlatforms(const TMap<ITargetPlatform*, ITargetPlatform*>& Remap);
// This is the set of packages which have already had PostLoadFixup called
TSet<UPackage*> PostLoadFixupPackages;
// This is a complete list of currently loaded UPackages
TFastPointerSet<UPackage*> LoadedPackages;
// This list contains the UPackages loaded since last call to GetNewPackages
TArray<UPackage*> NewPackages;
/** The package currently being loaded at CookOnTheFlyServer's direct request. Used to determine which load dependencies were not preloaded. */
FPackageData* LoadingPackageData = nullptr;
FPackageDatas& PackageDatas;
FThreadSafeUnsolicitedPackagesList UnsolicitedCookedPackages;
FThreadSafeQueue<FRecompileRequest*> RecompileRequests;
FThreadSafeSet<FName> NeverCookPackageList;
FThreadSafeSet<FName> UncookedEditorOnlyPackages; // set of packages that have been rejected due to being referenced by editor-only properties
TFastPointerMap<const ITargetPlatform*, TSet<FName>> PlatformSpecificNeverCookPackages;
};
} // namespace Cook
} // namespace UE