// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "BuildPatchManifest.h" #include "IBuildManifestSet.h" namespace BuildPatchServices { /** * An interface for tracking references to chunks used throughout an installation. It is used to share across systems the * chunks that are still required and when. */ class IChunkReferenceTracker { public: enum class ESortDirection : uint8 { Ascending = 0, Descending }; public: virtual ~IChunkReferenceTracker() {} /** * Gets a set of all chunks referenced by the installation this tracker refers to. * This returns the _remaining_ referenced chunks! * @return set of GUID containing every chunk used. */ virtual TSet GetReferencedChunks() const = 0; /** * Gets the number of times a specific chunk is still referenced for the associated installation. * @param ChunkId The id for the chunk in question. * @return the number of references remaining. */ virtual int32 GetReferenceCount(const FGuid& ChunkId) const = 0; /** * Sorts a given array of chunk ids by the order in which they are required for the installation. * @param ChunkList The array to be sorted. * @param Direction The direction of sort. Ascending places soonest required chunk first. */ virtual void SortByUseOrder(TArray& ChunkList, ESortDirection Direction) const = 0; /** * Find the next X chunk references that match the provided predicate. * @param Count The number of chunk entries that are desired. * @param SelectPredicate The predicate used to select each chunk. * @return an array of unique chunk id entries, in the order in which they are required. */ virtual TArray GetNextReferences(int32 Count, const TFunction& SelectPredicate) const = 0; /** * Select from the next X chunk references, entries that match the provided predicate. * @param Count The number of chunk entries to search through. * @param SelectPredicate The predicate used to select each chunk. * @return an array of unique chunk id entries, in the order in which they are required. */ virtual TArray SelectFromNextReferences(int32 Count, const TFunction& SelectPredicate) const = 0; /** * Poorly named - Should be named "DoneWithChunk". The expectation is that we finish with chunks in the expected * use order. * * Pop the top reference from the tracker, indicating that operation has been performed. * It is not valid to pop anything but the top guid, so it must be provided for verification of behavior. * @param ChunkId The id of the top chunk, this is used to verify behavior. * @return true if the correct guid was provided and the reference was popped, false if the wrong guid * was provided and thus no change was made. */ virtual bool PopReference(const FGuid& ChunkId) = 0; // Return how many chunks are left to process. virtual int32 GetRemainingChunkCount() const = 0; // Return the ordered list we are consuming. // copies the _remaining_ items! virtual void CopyOutOrderedUseList(TArray& OutUseList) const = 0; // Returns the next usage index in _advancing order_ for the chunkid, or -1 if it won't // be used again. virtual int32 GetNextUsageForChunk(const FGuid& ChunkId, int32& OutLastUsageIndex) const = 0; virtual int32 GetCurrentUsageIndex() const = 0; }; /** * A factory for creating an IChunkReferenceTracker instance. */ class FChunkReferenceTrackerFactory { public: /** * This implementation takes the install manifest and generates the internal data and chunk reference tracking based * off of a set of files that will be constructed. * @param InstallManifest The install manifest to enumerate references from. * @param FilesToConstruct The set of files to be installed, other files will not be considered. * @return the new IChunkReferenceTracker instance created. */ static IChunkReferenceTracker* Create(const IBuildManifestSet* Manifest, const TSet& FilesToConstruct); /** * This implementation takes custom chunk references to track. The array should be every chunk reference, including duplicates, in order of use. * See namespace CustomChunkReferencesHelpers for common setup examples to use. * @param CustomChunkReferences The custom chunk references to track. * @return the new IChunkReferenceTracker instance created. */ static IChunkReferenceTracker* Create(TArray CustomChunkReferences); }; /** * Helpers for creating a CustomChunkReferences array for use with the equivalent FChunkReferenceTrackerFactory. */ namespace CustomChunkReferencesHelpers { /** * This implementation takes the install manifest and generates the CustomChunkReferences needed for a chunk reference tracker based * on caching data and so using each chunk once in the order that would be required to install the build. * @param InstallManifest The install manifest to enumerate references from. * @return the chunk use references for FChunkReferenceTrackerFactory::Create. */ FORCEINLINE TArray OrderedUniqueReferences(const FBuildPatchAppManifestRef& InstallManifest) { TArray ChunkReferences; // Create our full list of chunks, no dupes, just one reference per chunk in the correct order. TArray AllFiles; TSet AllChunks; InstallManifest->GetFileList(AllFiles); for (const FString& File : AllFiles) { const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File); if (NewFileManifest != nullptr) { for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts) { bool bWasAlreadyInSet = false; AllChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet); if (!bWasAlreadyInSet) { ChunkReferences.Add(ChunkPart.Guid); } } } } return ChunkReferences; } /** * This implementation takes a new install manifest and a current manifest. It generates the CustomChunkReferences needed for a chunk reference tracker based * on caching data for a patch only, and so using the chunks in InstallManifest, which are not in CurrentManifest, once each in the order that they * would be required to patch the build. * @param InstallManifest The install manifest to enumerate chunk references from. * @param CurrentManifest The current manifest to exclude chunk references from. * @return the chunk use references for FChunkReferenceTrackerFactory::Create. */ FORCEINLINE TArray OrderedUniquePatchReferences(const FBuildPatchAppManifestRef& InstallManifest, const FBuildPatchAppManifestRef& CurrentManifest) { TArray ChunkReferences; // Create our list of chunks, no dupes, just one reference per chunk which appears only in InstallManifest, and in the correct order of use. TArray AllFiles; TSet OldChunks; TSet NewChunks; CurrentManifest->GetDataList(OldChunks); InstallManifest->GetFileList(AllFiles); for (const FString& File : AllFiles) { const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File); if (NewFileManifest != nullptr) { for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts) { const bool bIsNewChunk = !OldChunks.Contains(ChunkPart.Guid); if (bIsNewChunk) { bool bWasAlreadyInSet = false; NewChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet); if (!bWasAlreadyInSet) { ChunkReferences.Add(ChunkPart.Guid); } } } } } return ChunkReferences; } /** * This implementation takes the install manifest and a tagset. It generates the CustomChunkReferences needed for a chunk reference tracker based * on caching data and so using each chunk once in the order that would be required to install the build when using the same tagset provided. * @param InstallManifest The install manifest to enumerate references from. * @param InstallTagSet The tagset that would be used with install manifest, this will filter down required file list and thus required chunk list. * @return the chunk use references for FChunkReferenceTrackerFactory::Create. */ FORCEINLINE TArray OrderedUniqueReferencesTagged(const FBuildPatchAppManifestRef& InstallManifest, const TSet& InstallTagSet) { TArray ChunkReferences; // Create our full list of chunks, no dupes, just one reference per chunk in the correct order. TArray TaggedFiles; TSet TaggedChunks; InstallManifest->GetTaggedFileList(InstallTagSet, TaggedFiles); for (const FString& File : TaggedFiles) { const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File); if (NewFileManifest != nullptr) { for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts) { bool bWasAlreadyInSet = false; TaggedChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet); if (!bWasAlreadyInSet) { ChunkReferences.Add(ChunkPart.Guid); } } } } return ChunkReferences; } /** * This implementation takes a new install manifest, a current manifest, and a tagset for each. It generates the CustomChunkReferences needed for a chunk reference tracker based * on caching data for a patch only, and so using the chunks in InstallManifest, which are not in CurrentManifest, once each in the order that would be required * to patch the build when using the tagsets provided. * @param InstallManifest The install manifest to enumerate chunk references from. * @param InstallTagSet The tagset that would be used with install manifest, this will filter down required file list and thus required chunk list. * @param CurrentManifest The current manifest if considering an update, which reduces the number of chunks required. * @param CurrentTagSet The tagset filtering files from CurrentManifest, so that chunks would not be ignored for files not present on disk. This would often be the same as InstallTagSet unless * InstallManifest changed the file tag names, or you are calling for purpose of adding/removing tags. * @return the chunk use references for FChunkReferenceTrackerFactory::Create. */ FORCEINLINE TArray OrderedUniquePatchReferencesTagged(const FBuildPatchAppManifestRef& InstallManifest, const TSet& InstallTagSet, const FBuildPatchAppManifestRef& CurrentManifest, const TSet& CurrentTagSet) { // Enumerate what is available in the current build. TSet FilesInstalled; TSet ChunksRequired; TSet ChunksInstalled; CurrentManifest->GetTaggedFileList(CurrentTagSet, FilesInstalled); CurrentManifest->GetChunksRequiredForFiles(FilesInstalled, ChunksRequired); CurrentManifest->EnumerateProducibleChunks(CurrentTagSet, ChunksRequired, ChunksInstalled); TArray ChunkReferences; // Create our list of chunks, no dupes, just one reference per chunk which appears only in InstallManifest, and in the correct order of use. TArray TaggedFiles; TSet TaggedNewChunks; InstallManifest->GetTaggedFileList(InstallTagSet, TaggedFiles); for (const FString& File : TaggedFiles) { const FFileManifest* NewFileManifest = InstallManifest->GetFileManifest(File); if (NewFileManifest != nullptr) { for (const FChunkPart& ChunkPart : NewFileManifest->ChunkParts) { const bool bIsNewChunk = !ChunksInstalled.Contains(ChunkPart.Guid); if (bIsNewChunk) { bool bWasAlreadyInSet = false; TaggedNewChunks.Add(ChunkPart.Guid, &bWasAlreadyInSet); if (!bWasAlreadyInSet) { ChunkReferences.Add(ChunkPart.Guid); } } } } } return ChunkReferences; } } }