2023-01-13 03:31:00 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "CommandletUtils.h"
|
|
|
|
|
|
2023-02-22 07:39:51 -05:00
|
|
|
#include "AssetRegistry/AssetData.h"
|
|
|
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
2023-01-13 03:31:00 -05:00
|
|
|
#include "Async/ParallelFor.h"
|
|
|
|
|
#include "Containers/Set.h"
|
|
|
|
|
#include "Misc/PackageName.h"
|
2023-02-22 07:39:51 -05:00
|
|
|
#include "Misc/Paths.h"
|
2023-01-13 03:31:00 -05:00
|
|
|
#include "UObject/PackageTrailer.h"
|
|
|
|
|
|
|
|
|
|
namespace UE::Virtualization
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
TArray<FString> FindAllPackages()
|
|
|
|
|
{
|
|
|
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FindAllPackages);
|
|
|
|
|
|
2023-02-22 07:39:51 -05:00
|
|
|
TArray<FString> PackagePaths;
|
2023-01-13 03:31:00 -05:00
|
|
|
|
2023-02-22 07:39:51 -05:00
|
|
|
FAssetRegistryModule& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
2023-01-13 03:31:00 -05:00
|
|
|
|
2023-02-22 07:39:51 -05:00
|
|
|
// Do an async search even though we immediately block on it. This will result in the asset registry cache
|
|
|
|
|
// being saved to disk on a background thread which is an operation we don't need to wait on. This can
|
|
|
|
|
// save a fair amount of time on larger projects.
|
|
|
|
|
const bool bSynchronousSearch = false;
|
|
|
|
|
AssetRegistry.Get().SearchAllAssets(bSynchronousSearch);
|
|
|
|
|
AssetRegistry.Get().WaitForCompletion();
|
2023-01-13 03:31:00 -05:00
|
|
|
|
2023-02-22 07:39:51 -05:00
|
|
|
const FString EnginePath = FPaths::EngineDir();
|
|
|
|
|
|
|
|
|
|
AssetRegistry.Get().EnumerateAllPackages([&PackagePaths, EnginePath](FName PackageName, const FAssetPackageData& PackageData)
|
|
|
|
|
{
|
|
|
|
|
FString RelFileName;
|
|
|
|
|
if (PackageData.Extension != EPackageExtension::Unspecified && PackageData.Extension != EPackageExtension::Custom)
|
|
|
|
|
{
|
|
|
|
|
const FString Extension = LexToString(PackageData.Extension);
|
|
|
|
|
if (FPackageName::TryConvertLongPackageNameToFilename(PackageName.ToString(), RelFileName, Extension))
|
|
|
|
|
{
|
|
|
|
|
FString StdFileName = FPaths::CreateStandardFilename(RelFileName);
|
|
|
|
|
|
|
|
|
|
// Now we have the absolute file path we can filter out engine packages
|
|
|
|
|
if (!StdFileName.StartsWith(EnginePath))
|
|
|
|
|
{
|
|
|
|
|
PackagePaths.Emplace(MoveTemp(StdFileName));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return PackagePaths;
|
2023-01-13 03:31:00 -05:00
|
|
|
}
|
|
|
|
|
|
2023-01-30 04:56:40 -05:00
|
|
|
TArray<FString> FindPackagesInDirectory(const FString& DirectoryToSearch)
|
|
|
|
|
{
|
|
|
|
|
TArray<FString> FilesInPackageFolder;
|
|
|
|
|
FPackageName::FindPackagesInDirectory(FilesInPackageFolder, DirectoryToSearch);
|
|
|
|
|
|
|
|
|
|
TArray<FString> PackageNames;
|
|
|
|
|
PackageNames.Reserve(FilesInPackageFolder.Num());
|
|
|
|
|
|
|
|
|
|
for (const FString& BasePath : FilesInPackageFolder)
|
|
|
|
|
{
|
|
|
|
|
PackageNames.Add(FPaths::CreateStandardFilename(BasePath));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PackageNames;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-13 03:31:00 -05:00
|
|
|
TArray<FString> DiscoverPackages(const FString& CmdlineParams)
|
|
|
|
|
{
|
|
|
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(DiscoverPackages);
|
|
|
|
|
|
|
|
|
|
FString PackageDir;
|
|
|
|
|
if (FParse::Value(*CmdlineParams, TEXT("PackageDir="), PackageDir) || FParse::Value(*CmdlineParams, TEXT("PackageFolder="), PackageDir))
|
|
|
|
|
{
|
2023-01-30 04:56:40 -05:00
|
|
|
return FindPackagesInDirectory(PackageDir);
|
2023-01-13 03:31:00 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return FindAllPackages();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<FIoHash> FindVirtualizedPayloads(const TArray<FString>& PackagePaths)
|
|
|
|
|
{
|
|
|
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FindVirtualizedPayloads);
|
|
|
|
|
|
|
|
|
|
// Each task will write out to its own TSet so we don't have to lock anything, we
|
|
|
|
|
// will combine the sets at the end.
|
|
|
|
|
TArray<TSet<FIoHash>> PayloadsPerTask;
|
|
|
|
|
|
|
|
|
|
ParallelForWithTaskContext(PayloadsPerTask, PackagePaths.Num(),
|
|
|
|
|
[&PackagePaths](TSet<FIoHash>& Context, int32 Index)
|
|
|
|
|
{
|
|
|
|
|
const FString& PackageName = PackagePaths[Index];
|
|
|
|
|
|
|
|
|
|
UE::FPackageTrailer Trailer;
|
|
|
|
|
if (UE::FPackageTrailer::TryLoadFromFile(PackageName, Trailer))
|
|
|
|
|
{
|
|
|
|
|
TArray<FIoHash> VirtualizedPayloads = Trailer.GetPayloads(UE::EPayloadStorageType::Virtualized);
|
|
|
|
|
Context.Append(VirtualizedPayloads);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Combine the results into a final set
|
|
|
|
|
TSet<FIoHash> AllPayloads;
|
|
|
|
|
for (const TSet<FIoHash>& Payloads : PayloadsPerTask)
|
|
|
|
|
{
|
|
|
|
|
AllPayloads.Append(Payloads);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AllPayloads.Array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} //namespace UE::Virtualization
|