void FChunkManifestGenerator::GenerateChunkManifestForPackage(const FName& PackageFName, const FString& PackagePathName, const FString& SandboxFilename, const FString& LastLoadedMapName, FSandboxPlatformFile* InSandboxFile) { TArray<int32> TargetChunks; TArray<int32> ExistingChunkIDs; if (!bGenerateChunks) { TargetChunks.AddUnique(0); ExistingChunkIDs.AddUnique(0); } if (bGenerateChunks) { // Collect all chunk IDs associated with this package from the asset registry TArray<int32> RegistryChunkIDs = GetAssetRegistryChunkAssignments(PackageFName); ExistingChunkIDs = GetExistingPackageChunkAssignments(PackageFName); // Try to call game-specific delegate to determine the target chunk ID // FString Name = Package->GetPathName(); if (FGameDelegates::Get().GetAssignStreamingChunkDelegate().IsBound()) { FGameDelegates::Get().GetAssignStreamingChunkDelegate().ExecuteIfBound(PackagePathName, LastLoadedMapName, RegistryChunkIDs, ExistingChunkIDs, TargetChunks); } else { //Take asset registry assignments and existing assignments TargetChunks.Append(RegistryChunkIDs); TargetChunks.Append(ExistingChunkIDs); } } bool bAssignedToChunk = false; // if the delegate requested a specific chunk assignment, add them package to it now. for (const auto& PackageChunk : TargetChunks) { AddPackageToManifest(SandboxFilename, PackageFName, PackageChunk); bAssignedToChunk = true; } // If the delegate requested to remove the package from any chunk, remove it now for (const auto& PackageChunk : ExistingChunkIDs) { if (!TargetChunks.Contains(PackageChunk)) { RemovePackageFromManifest(PackageFName, PackageChunk); } } }
void FChunkManifestGenerator::AddPackageToChunkManifest(UPackage* Package, const FString& SandboxFilename, const FString& LastLoadedMapName, FSandboxPlatformFile* InSandboxFile) { TArray<int32> TargetChunks; TArray<int32> ExistingChunkIDs; if (!bGenerateChunks) { TargetChunks.AddUnique(0); ExistingChunkIDs.AddUnique(0); } auto PackageFName = Package->GetFName(); if (bGenerateChunks) { // Try to determine if this package has been loaded as a result of loading a map package. FString MapThisAssetWasLoadedWith; if (!LastLoadedMapName.IsEmpty()) { if (AssetsLoadedWithLastPackage.Contains(PackageFName)) { MapThisAssetWasLoadedWith = LastLoadedMapName; } } // Collect all chunk IDs associated with this package from the asset registry TArray<int32> RegistryChunkIDs = GetAssetRegistryChunkAssignments(Package); ExistingChunkIDs = GetExistingPackageChunkAssignments(PackageFName); // Try to call game-specific delegate to determine the target chunk ID FString Name = Package->GetPathName(); if (FGameDelegates::Get().GetAssignStreamingChunkDelegate().IsBound()) { FGameDelegates::Get().GetAssignStreamingChunkDelegate().ExecuteIfBound(Name, MapThisAssetWasLoadedWith, RegistryChunkIDs, ExistingChunkIDs, TargetChunks); } else { //Take asset registry assignments and existing assignments TargetChunks.Append(RegistryChunkIDs); TargetChunks.Append(ExistingChunkIDs); } } NotifyPackageWasCooked(SandboxFilename, PackageFName); bool bAssignedToChunk = false; // if the delegate requested a specific chunk assignment, add them package to it now. for (const auto& PackageChunk : TargetChunks) { AddPackageToManifest(SandboxFilename, PackageFName, PackageChunk); bAssignedToChunk = true; } // If the delegate requested to remove the package from any chunk, remove it now for (const auto& PackageChunk : ExistingChunkIDs) { if (!TargetChunks.Contains(PackageChunk)) { RemovePackageFromManifest(PackageFName, PackageChunk); } } if (!bAssignedToChunk) { NotifyPackageWasNotAssigned(SandboxFilename, PackageFName); } }
void FChunkManifestGenerator::BuildChunkManifest(const TArray<FName>& CookedPackages, FSandboxPlatformFile* InSandboxFile, bool bGenerateStreamingInstallManifest) { bGenerateChunks = bGenerateStreamingInstallManifest; // initialize LargestChunkId, FoundIDList, PackageChunkIDMap, AssetRegistryData // Calculate the largest chunk id used by the registry to get the indices for the default chunks AssetRegistry.GetAllAssets(AssetRegistryData); int32 LargestChunkID = -1; for (int32 Index = 0; Index < AssetRegistryData.Num(); ++Index) { auto& AssetData = AssetRegistryData[Index]; auto& RegistryChunkIDs = RegistryChunkIDsMap.FindOrAdd(AssetData.PackageName); for (auto ChunkIt = AssetData.ChunkIDs.CreateConstIterator(); ChunkIt; ++ChunkIt) { int32 ChunkID = *ChunkIt; if (ChunkID < 0) { UE_LOG(LogChunkManifestGenerator, Warning, TEXT("Out of range ChunkID: %d"), ChunkID); ChunkID = 0; } else if (ChunkID > LargestChunkID) { LargestChunkID = ChunkID; } if (!RegistryChunkIDs.Contains(ChunkID)) { RegistryChunkIDs.Add(ChunkID); } auto* FoundIDList = PackageChunkIDMap.Find(AssetData.PackageName); if (!FoundIDList) { FoundIDList = &PackageChunkIDMap.Add(AssetData.PackageName); } FoundIDList->AddUnique(ChunkID); } // Now clear the original chunk id list. We will fill it with real IDs when cooking. AssetData.ChunkIDs.Empty(); // Map asset data to its package (there can be more than one asset data per package). auto& PackageData = PackageToRegistryDataMap.FindOrAdd(AssetData.PackageName); PackageData.Add(Index); } // add all the packages to the unassigned package list for (const auto& CookedPackage : CookedPackages) { const FString SandboxPath = InSandboxFile->ConvertToAbsolutePathForExternalAppForWrite(*FPackageName::LongPackageNameToFilename(CookedPackage.ToString())); AllCookedPackages.Add(CookedPackage, SandboxPath); UnassignedPackageSet.Add(CookedPackage, SandboxPath); } for (const auto& CookedPackage : StartupPackages) { const FString SandboxPath = InSandboxFile->ConvertToAbsolutePathForExternalAppForWrite(*FPackageName::LongPackageNameToFilename(CookedPackage.ToString())); AllCookedPackages.Add(CookedPackage, SandboxPath); AddPackageToManifest(SandboxPath, CookedPackage, 0); } // assign chunks for all the map packages for (const auto& CookedPackage : UnassignedPackageSet) { // ignore non map packages for now const FName MapFName = CookedPackage.Key; // this package could be missing from the map because it didn't get cooked. // the reason for this might be that it's a redirector therefore we cooked the package which actually contains the asset if (PackageToRegistryDataMap.Find(MapFName) == nullptr) continue; if (ContainsMap(MapFName) == false) continue; // get all the dependencies for this map TArray<FName> MapDependencies; ensure(GatherAllPackageDependencies(MapFName, MapDependencies)); for (const auto& RawPackageFName : MapDependencies) { const FName PackageFName = GetPackageNameFromDependencyPackageName(RawPackageFName); if (PackageFName == NAME_None) { continue; } const FString PackagePathName = PackageFName.ToString(); const FString MapName = MapFName.ToString(); const FString* SandboxFilenamePtr = AllCookedPackages.Find(PackageFName); if (!SandboxFilenamePtr) { const FString SandboxPath = InSandboxFile->ConvertToAbsolutePathForExternalAppForWrite(*FPackageName::LongPackageNameToFilename(PackagePathName)); AllCookedPackages.Add(PackageFName, SandboxPath); SandboxFilenamePtr = AllCookedPackages.Find(PackageFName); check(SandboxFilenamePtr); } const FString& SandboxFilename = *SandboxFilenamePtr; GenerateChunkManifestForPackage(PackageFName, PackagePathName, SandboxFilename, MapName, InSandboxFile); } } // process the remaining unassigned packages, they don't have a map associated with them // probably a good reason for it but maybe not for (const auto& CookedPackage : UnassignedPackageSet) { const FName& PackageFName = CookedPackage.Key; const FString& SandboxFilename = AllCookedPackages.FindChecked(PackageFName); const FString PackagePathName = PackageFName.ToString(); GenerateChunkManifestForPackage(PackageFName, PackagePathName, SandboxFilename, FString(), InSandboxFile); } // anything that remains in the UnAssignedPackageSet will be put in chunk0 when we save the asset registry }