Files
UnrealEngine/Engine/Source/Editor/VirtualizationEditor/Private/CheckForVirtualizedContentCommandlet.cpp
2025-05-18 13:04:45 +08:00

222 lines
6.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CheckForVirtualizedContentCommandlet.h"
#include "CommandletUtils.h"
#include "HAL/FileManager.h"
#include "Logging/StructuredLog.h"
#include "Misc/PackageName.h"
#include "Misc/Paths.h"
#include "UObject/PackageTrailer.h"
UCheckForVirtualizedContentCommandlet::UCheckForVirtualizedContentCommandlet(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
int32 UCheckForVirtualizedContentCommandlet::Main(const FString& Params)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UCheckForVirtualizedContentCommandlet);
TArray<FString> Tokens;
TArray<FString> Switches;
ParseCommandLine(*Params, Tokens, Switches);
bool bNoVAContentInEngine = false;
bool bNoVAContentInProject = false;
TArray<FString> DirectoriesToCheck;
int32 UnknownSwitch = 0;
for (const FString& Switch : Switches)
{
FString InputPath;
if (Switch == TEXT("CheckEngine"))
{
bNoVAContentInEngine = true;
}
else if (Switch == TEXT("CheckProject"))
{
bNoVAContentInProject = true;
}
else if (FParse::Value(*Switch, TEXT("CheckDir="), InputPath))
{
InputPath.ParseIntoArray(DirectoriesToCheck, TEXT("+"), true);
}
else
{
UnknownSwitch++;
}
}
if (UnknownSwitch == Switches.Num())
{
UE_LOG(LogVirtualization, Error, TEXT("No input was provided for the commandlet. Use '-CheckEngine', '-CheckProject' or '-CheckDir=...'"));
return 2;
}
TArray<FString> EnginePackages;
TArray<FString> ProjectPackages;
if (bNoVAContentInEngine || bNoVAContentInProject)
{
TRACE_CPUPROFILER_EVENT_SCOPE(SortAllPackages);
TArray<FString> AllPackages = UE::Virtualization::FindPackages(UE::Virtualization::EFindPackageFlags::None);
const FString EngineDir = FPaths::EngineDir();
for (const FString& Path : AllPackages)
{
const bool bIsEngineContent = Path.StartsWith(EngineDir);
if (bNoVAContentInEngine && bIsEngineContent)
{
EnginePackages.Add(Path);
}
else if (bNoVAContentInProject && !bIsEngineContent)
{
ProjectPackages.Add(Path);
}
}
}
bool bAllContentValid = true;
if (bNoVAContentInEngine)
{
if (!TryValidateContent(TEXT("Engine"), EnginePackages))
{
bAllContentValid = false;
}
}
if (bNoVAContentInProject)
{
if (!TryValidateContent(TEXT("Project"), ProjectPackages))
{
bAllContentValid = false;
}
}
if (!DirectoriesToCheck.IsEmpty())
{
for (const FString& Directory : DirectoriesToCheck)
{
if (!TryValidateDirectory(Directory))
{
bAllContentValid = false;
}
}
}
UE_LOG(LogVirtualization, Display, TEXT("********************************************************************************"));
return bAllContentValid ? 0 : 1;
}
TArray<FString> UCheckForVirtualizedContentCommandlet::FindVirtualizedPackages(const TArray<FString>& PackagePaths)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ParsePackageTrailers);
TArray<FString> VirtualizedPackages;
for (const FString& Path : PackagePaths)
{
UE::FPackageTrailer Trailer;
if (UE::FPackageTrailer::TryLoadFromFile(Path, Trailer))
{
const int32 NumVirtualizedPayloads = Trailer.GetNumPayloads(UE::EPayloadStorageType::Virtualized);
if (NumVirtualizedPayloads > 0)
{
FString PackageName;
if (FPackageName::TryConvertFilenameToLongPackageName(Path, PackageName))
{
VirtualizedPackages.Emplace(MoveTemp(PackageName));
}
else
{
VirtualizedPackages.Add(Path);
}
}
}
}
return VirtualizedPackages;
}
bool UCheckForVirtualizedContentCommandlet::TryValidateContent(const TCHAR* DebugName, const TArray<FString>& Packages)
{
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*WriteToString<128>("TryValidateContent - ", DebugName));
check(DebugName != nullptr);
UE_LOG(LogVirtualization, Display, TEXT("********************************************************************************"));
UE_LOG(LogVirtualization, Display, TEXT("Looking for virtualized payloads in %s content..."), DebugName);
UE_LOG(LogVirtualization, Display, TEXT("Found %d %s package(s)"), Packages.Num(), DebugName);
TArray<FString> VirtualizedPackages = FindVirtualizedPackages(Packages);
if (VirtualizedPackages.IsEmpty())
{
UE_LOG(LogVirtualization, Display, TEXT("No virtualized packages were found in %s content"), DebugName);
return true;
}
else
{
for (FString& Path : VirtualizedPackages)
{
UE_LOGFMT(LogVirtualization, Error, "Package {PackagePath} contains virtualized payloads", Path);
}
UE_LOG(LogVirtualization, Error, TEXT("Found %d virtualized package(s) in %s content"), VirtualizedPackages.Num(), DebugName);
return false;
}
}
bool UCheckForVirtualizedContentCommandlet::TryValidateDirectory(const FString& Directory)
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryValidateDirectory);
UE_LOG(LogVirtualization, Display, TEXT("********************************************************************************"));
UE_LOG(LogVirtualization, Display, TEXT("Searching directory '%s' for virtualized packages..."), *Directory);
if (!IFileManager::Get().DirectoryExists(*Directory))
{
UE_LOG(LogVirtualization, Error, TEXT("Directory '%s' could not be found!"), *Directory);
return false;
}
TArray<FString> DirectoryPackages;
DirectoryPackages = UE::Virtualization::FindPackagesInDirectory(Directory);
if (DirectoryPackages.IsEmpty())
{
UE_LOG(LogVirtualization, Display, TEXT("Found no packages under '%s'"), *Directory);
return true;
}
UE_LOG(LogVirtualization, Display, TEXT("Found %d package(s) under '%s'"), DirectoryPackages.Num(), *Directory);
UE_LOG(LogVirtualization, Display, TEXT("Looking for virtualized payloads under directory..."));
TArray<FString> VirtualizedPackages = FindVirtualizedPackages(DirectoryPackages);
if (VirtualizedPackages.IsEmpty())
{
UE_LOG(LogVirtualization, Display, TEXT("No virtualized packages were found under '%s'"), *Directory);
}
else
{
for (FString& Path : VirtualizedPackages)
{
UE_LOGFMT(LogVirtualization, Error, "Package {PackagePath} contains virtualized payloads", Path);
}
UE_LOG(LogVirtualization, Error, TEXT("Found %d virtualized package(s) under '%s'"), VirtualizedPackages.Num(), *Directory);
}
return true;
}