// Copyright Epic Games, Inc. All Rights Reserved. #include "Commandlets/ChunkDependencyInfo.h" UChunkDependencyInfo::UChunkDependencyInfo(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { CachedHighestChunk = -1; } const FChunkDependencyTreeNode* UChunkDependencyInfo::GetOrBuildChunkDependencyGraph(int32 HighestChunk) { if (HighestChunk > CachedHighestChunk) { return BuildChunkDependencyGraph(HighestChunk); } return &RootTreeNode; } const FChunkDependencyTreeNode* UChunkDependencyInfo::BuildChunkDependencyGraph(int32 HighestChunk) { // Reset any current tree RootTreeNode.ChunkID = 0; RootTreeNode.ChildNodes.Reset(0); ChildToParentMap.Reset(); CachedHighestChunk = HighestChunk; // Ensure the DependencyArray is OK to work with. for (int32 DepIndex = DependencyArray.Num() - 1; DepIndex >= 0; DepIndex--) { const FChunkDependency& Dep = DependencyArray[DepIndex]; if (Dep.ChunkID > HighestChunk) { HighestChunk = Dep.ChunkID; } if (Dep.ParentChunkID > HighestChunk) { HighestChunk = Dep.ParentChunkID; } if (Dep.ChunkID == Dep.ParentChunkID) { // Remove cycles DependencyArray.RemoveAtSwap(DepIndex); } } // Add missing links (assumes they parent to chunk zero) for (int32 i = 1; i <= HighestChunk; ++i) { if (!DependencyArray.FindByPredicate([=](const FChunkDependency& RHS) { return i == RHS.ChunkID; })) { FChunkDependency Dep; Dep.ChunkID = i; Dep.ParentChunkID = 0; DependencyArray.Add(Dep); } } // Remove duplicates DependencyArray.StableSort([](const FChunkDependency& LHS, const FChunkDependency& RHS) { return LHS.ChunkID < RHS.ChunkID; }); for (int32 i = 0; i < DependencyArray.Num() - 1;) { if (DependencyArray[i] == DependencyArray[i + 1]) { DependencyArray.RemoveAt(i + 1); } else { ++i; } } AddChildrenRecursive(RootTreeNode, DependencyArray, TSet()); return &RootTreeNode; } void UChunkDependencyInfo::AddChildrenRecursive(FChunkDependencyTreeNode& Node, TArray& DepInfo, TSet Parents) { if (Parents.Num() > 0) { ChildToParentMap.FindOrAdd(Node.ChunkID).Append(Parents); } Parents.Add(Node.ChunkID); auto ChildNodeIndices = DepInfo.FilterByPredicate( [&](const FChunkDependency& RHS) { return Node.ChunkID == RHS.ParentChunkID; }); for (const auto& ChildIndex: ChildNodeIndices) { Node.ChildNodes.Add(FChunkDependencyTreeNode(ChildIndex.ChunkID)); } for (auto& Child: Node.ChildNodes) { AddChildrenRecursive(Child, DepInfo, Parents); } } void UChunkDependencyInfo::RemoveRedundantChunks(TArray& ChunkIDs) const { for (int32 ChunkIndex = ChunkIDs.Num() - 1; ChunkIndex >= 0; ChunkIndex--) { const TSet* FoundParents = ChildToParentMap.Find(ChunkIDs[ChunkIndex]); if (FoundParents) { for (int32 ParentChunk: *FoundParents) { if (ChunkIDs.Contains(ParentChunk)) { ChunkIDs.RemoveAt(ChunkIndex); break; } } } } }