// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Algo/BinarySearch.h" #include "AssetRegistry/AssetData.h" #include "AssetRegistry/IAssetRegistry.h" #include "Containers/BitArray.h" #include "Misc/AssetRegistryInterface.h" #include "PropertyCombinationSet.h" struct FDependsNodeReservations; /** Implementation of IDependsNode */ class FDependsNode { public: typedef TArray FDependsNodeList; static constexpr uint32 PackageFlagWidth = 3; static constexpr uint32 SearchableNameFlagWidth = 0; static constexpr uint32 ManageFlagWidth = 1; typedef TPropertyCombinationSet FPackageFlagSet; static constexpr uint32 PackageFlagSetWidth = FPackageFlagSet::StorageBitCount; static constexpr uint32 SearchableNameFlagSetWidth = 0; static constexpr uint32 ManageFlagSetWidth = TPropertyCombinationSet::StorageBitCount; public: FDependsNode(); FDependsNode(const FAssetIdentifier& InIdentifier); /** Prints the dependencies and referencers for this node to the log */ void PrintNode() const; /** Prints the dependencies for this node to the log */ void PrintDependencies() const; /** Prints the referencers to this node to the log */ void PrintReferencers() const; /** Gets the list of dependencies for this node */ void GetDependencies(TArray& OutDependencies, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; /** Gets the list of dependency names for this node */ void GetDependencies(TArray& OutDependencies, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; void GetDependencies(TArray& OutDependencies, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; /** Gets the list of referencers to this node */ void GetReferencers(TArray& OutReferencers, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; void GetReferencers(TArray& OutReferencers, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; /** Helper function to return GetIdentifier.PackageName. */ FName GetPackageName() const; /** Returns the entire identifier */ const FAssetIdentifier& GetIdentifier() const; bool IsScriptPath() const; /** Sets the entire identifier */ void SetIdentifier(const FAssetIdentifier& InIdentifier); /** Add a dependency to this node */ void AddDependency(FDependsNode* InDependency, UE::AssetRegistry::EDependencyCategory InDependencyType, UE::AssetRegistry::EDependencyProperty InProperties); void GetPackageReferencers(TArray>& OutReferencers); void AddPackageDependencySet(FDependsNode* InDependency, const FPackageFlagSet& PropertyCombinationSet); /** Add a referencer to this node */ void AddReferencer(FDependsNode* InReferencer); /** Remove a dependency from this node */ void RemoveDependency(FDependsNode* InDependency, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All); /** Remove a referencer from this node */ void RemoveReferencer(FDependsNode* InReferencer); /** Removes any referencers that no longer have this node as a dependency */ void RefreshReferencers(); bool ContainsDependency(const FDependsNode* InDependency, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; /** Clear all dependency records from this node */ void ClearDependencies(UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All); void ClearReferencers(); /** * Removes Manage dependencies on this node and clean up referencers array. * Manage references are the only ones safe to remove at runtime. */ void RemoveManageReferencesToNode(); /** Remove all nodes from referencers and dependencies for which ShouldRemove returns true */ void RemoveLinks(const TUniqueFunction& ShouldRemove); /** Returns number of connections this node has, both references and dependencies */ int32 GetConnectionCount() const; /** Returns amount of memory used by the arrays */ SIZE_T GetAllocatedSize(void) const; typedef TUniqueFunction FIterateDependenciesCallback; /** * Iterate over all the dependencies of this node, optionally filtered by the target node, category and query, * and call the supplied lambda parameter on the record. */ void IterateOverDependencies(const FIterateDependenciesCallback& InCallback, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; void IterateOverDependencies(const FIterateDependenciesCallback& InCallback, const FDependsNode* DependsNode, UE::AssetRegistry::EDependencyCategory Category = UE::AssetRegistry::EDependencyCategory::All, const UE::AssetRegistry::FDependencyQuery& Flags = UE::AssetRegistry::FDependencyQuery()) const; /** Iterate over all the referencers of this node and call the supplied lambda parameter on the referencer */ template void IterateOverReferencers(const T& InCallback) const; void Reserve(int32 InNumPackageDependencies, int32 InNumNameDependencies, int32 InNumManageDependencies, int32 InNumReferencers); void Reserve(const FDependsNodeReservations& InReservations); void Reserve(const FDependsNode* Other); bool GetAllowShrinking() const; void SetAllowShrinking(bool bAllowShrinking); static uint8 PackagePropertiesToByte(UE::AssetRegistry::EDependencyProperty Properties); static UE::AssetRegistry::EDependencyProperty ByteToPackageProperties(uint8 Bits); static uint8 ManagePropertiesToByte(UE::AssetRegistry::EDependencyProperty Properties); static UE::AssetRegistry::EDependencyProperty ByteToManageProperties(uint8 Bits); struct FSaveScratch { struct FSortInfo { int32 SerializeIndex; int32 ListIndex; }; TArray SortInfos; TArray OutDependencies; TBitArray<> OutFlagBits; }; void SerializeSave(FArchive& Ar, const TUniqueFunction& GetSerializeIndexFromNode, FSaveScratch& Scratch, const FAssetRegistrySerializationOptions& Options) const; struct FLoadScratch { TArray InDependencies; TArray InFlagBits; TArray PointerDependencies; TArray SortIndexes; }; void SerializeLoad(FArchive& Ar, const TUniqueFunction& GetNodeFromSerializeIndex, FLoadScratch& Scratch); void SerializeLoad_BeforeFlags(FArchive& Ar, FAssetRegistryVersion::Type Version, FDependsNode* PreallocatedDependsNodeDataBuffer, int32 NumDependsNodes, bool bSerializeDependencies, uint32 HardBits, uint32 SoftBits, uint32 HardManageBits, uint32 SoftManageBits); static void GetPropertySetBits_BeforeFlags(uint32& HardBits, uint32& SoftBits, uint32& HardManageBits, uint32& SoftManageBits); bool IsDependencyListSorted(UE::AssetRegistry::EDependencyCategory Category) const; void SetIsDependencyListSorted(UE::AssetRegistry::EDependencyCategory Category, bool bValue); bool IsReferencersSorted() const; void SetIsReferencersSorted(bool bValue); bool IsDependenciesInitialized() const; void SetIsDependenciesInitialized(bool bValue); private: /** * Recursively prints dependencies of the node starting with the specified indent. * VisitedNodes should be an empty set at first which is populated recursively. */ void PrintDependenciesRecursive(const FString& Indent, TSet& VisitedNodes) const; /** * Recursively prints referencers to the node starting with the specified indent. * VisitedNodes should be an empty set at first which is populated recursively. */ void PrintReferencersRecursive(const FString& Indent, TSet& VisitedNodes) const; void ConstructFlags(); /** The name of the package/object this node represents */ FAssetIdentifier Identifier; FDependsNodeList PackageDependencies; FDependsNodeList NameDependencies; FDependsNodeList ManageDependencies; FDependsNodeList Referencers; TBitArray<> PackageFlags; TBitArray<> ManageFlags; // Transient flags that are not serialized uint32 PackageIsSorted : 1; uint32 SearchableNameIsSorted : 1; uint32 ManageIsSorted : 1; uint32 ReferencersIsSorted : 1; uint32 DependenciesInitialized : 1; uint32 bScriptPath : 1; /** Used to control FDependsNodeList shrinking behaviour */ uint32 bAllowShrinking : 1; friend FDependsNodeReservations; }; struct FDependsNodeReservations { int32 PackageDependenciesSize = 0; int32 NameDependenciesSize = 0; int32 ManageDependenciesSize = 0; int32 ReferencersSize = 0; FDependsNodeReservations() = default; FDependsNodeReservations(const FDependsNode& Node) { PackageDependenciesSize = Node.PackageDependencies.Num(); NameDependenciesSize = Node.NameDependencies.Num(); ManageDependenciesSize = Node.ManageDependencies.Num(); ReferencersSize = Node.Referencers.Num(); } friend FArchive& operator<<(FArchive& Ar, FDependsNodeReservations& Reservations) { Ar << Reservations.PackageDependenciesSize << Reservations.NameDependenciesSize << Reservations.ManageDependenciesSize << Reservations.ReferencersSize; return Ar; } }; /////////////////////////////////////////////////////// // Inline implementations /////////////////////////////////////////////////////// inline FDependsNode::FDependsNode() { ConstructFlags(); } inline FDependsNode::FDependsNode(const FAssetIdentifier& InIdentifier) { ConstructFlags(); SetIdentifier(InIdentifier); } inline FName FDependsNode::GetPackageName() const { return Identifier.PackageName; } inline const FAssetIdentifier& FDependsNode::GetIdentifier() const { return Identifier; } inline bool FDependsNode::IsScriptPath() const { return bScriptPath != 0; } inline SIZE_T FDependsNode::GetAllocatedSize(void) const { return PackageDependencies.GetAllocatedSize() + PackageFlags.GetAllocatedSize() + NameDependencies.GetAllocatedSize() + ManageDependencies.GetAllocatedSize() + ManageFlags.GetAllocatedSize() + Referencers.GetAllocatedSize(); } template inline void FDependsNode::IterateOverReferencers(const T& InCallback) const { for (FDependsNode* Referencer : Referencers) { InCallback(Referencer); } } inline void FDependsNode::Reserve(int32 InNumPackageDependencies, int32 InNumNameDependencies, int32 InNumManageDependencies, int32 InNumReferencers) { PackageDependencies.Reserve(InNumPackageDependencies); PackageFlags.Reserve(InNumPackageDependencies * PackageFlagSetWidth); NameDependencies.Reserve(InNumNameDependencies); ManageDependencies.Reserve(InNumManageDependencies); ManageFlags.Reserve(InNumManageDependencies * ManageFlagSetWidth); Referencers.Reserve(InNumReferencers); } inline void FDependsNode::Reserve(const FDependsNodeReservations& InReservations) { Reserve(InReservations.PackageDependenciesSize, InReservations.NameDependenciesSize, InReservations.ManageDependenciesSize, InReservations.ReferencersSize); } inline void FDependsNode::Reserve(const FDependsNode* Other) { Reserve(Other->PackageDependencies.Num(), Other->NameDependencies.Num(), Other->ManageDependencies.Num(), Other->Referencers.Num()); } inline bool FDependsNode::GetAllowShrinking() const { return bAllowShrinking; } inline void FDependsNode::SetAllowShrinking(bool InAllowShrinking) { bAllowShrinking = InAllowShrinking; } inline uint8 FDependsNode::PackagePropertiesToByte(UE::AssetRegistry::EDependencyProperty Properties) { return (0x01 * (static_cast(Properties & UE::AssetRegistry::EDependencyProperty::Hard) != 0)) | (0x02 * (static_cast(Properties & UE::AssetRegistry::EDependencyProperty::Game) != 0)) | (0x04 * (static_cast(Properties & UE::AssetRegistry::EDependencyProperty::Build) != 0)); } inline UE::AssetRegistry::EDependencyProperty FDependsNode::ByteToPackageProperties(uint8 Bits) { return static_cast( (static_cast(UE::AssetRegistry::EDependencyProperty::Hard) * ((Bits & 0x01) != 0)) | (static_cast(UE::AssetRegistry::EDependencyProperty::Game) * ((Bits & 0x02) != 0)) | (static_cast(UE::AssetRegistry::EDependencyProperty::Build) * ((Bits & 0x04) != 0)) ); } inline uint8 FDependsNode::ManagePropertiesToByte(UE::AssetRegistry::EDependencyProperty Properties) { return (0x01 * (static_cast(Properties & UE::AssetRegistry::EDependencyProperty::Direct) != 0)); } inline UE::AssetRegistry::EDependencyProperty FDependsNode::ByteToManageProperties(uint8 Bits) { return static_cast( (static_cast(UE::AssetRegistry::EDependencyProperty::Direct) * ((Bits & 0x01) != 0)) ); } inline void FDependsNode::ConstructFlags() { PackageIsSorted = 1; SearchableNameIsSorted = 1; ManageIsSorted = 1; ReferencersIsSorted = 1; DependenciesInitialized = 0; bScriptPath = 0; }