Files
UnrealEngine/Engine/Plugins/Mutable/Source/MutableValidation/Private/MuV/COIBulkUpdateTestCommandlet.cpp
2025-05-18 13:04:45 +08:00

180 lines
8.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MuV/COIBulkUpdateTestCommandlet.h"
#include "CustomizableObjectCompilationUtility.h"
#include "CustomizableObjectInstanceUpdateUtility.h"
#include "ValidationUtils.h"
#include "AssetRegistry/AssetData.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "MuCO/CustomizableObject.h"
#include "MuCO/CustomizableObjectInstance.h"
#include "Interfaces/ITargetPlatformManagerModule.h"
#include "MuCO/CustomizableObjectPrivate.h"
#include "MuCO/CustomizableObjectSystem.h"
#include "MuCO/CustomizableObjectSystemPrivate.h"
#include "MuCO/LoadUtils.h"
#include "MuCOE/CustomizableObjectBenchmarkingUtils.h"
int32 UCOIBulkUpdateTestCommandlet::Main(const FString& Params)
{
// Ensure we have set the mutable system to the benchmarking mode and that we are reporting benchmarking data
FLogBenchmarkUtil::SetBenchmarkReportingStateOverride(true);
UCustomizableObjectSystemPrivate::SetUsageOfBenchmarkingSettings(true);
// Ensure we do not show any OK dialog since we are not an user that can interact with them
GIsRunningUnattendedScript = true;
// Get the path where to look for the Customizable Object Instances we want to validate
FName InstancesPackagePath;
{
if (!FParse::Value(*Params, TEXT("InstancesPackagePath="), InstancesPackagePath))
{
UE_LOG(LogMutable,Error,TEXT("Failed to parse path where to find the Customizable Object Instances to update : %s"),*Params)
return 1;
}
if (InstancesPackagePath.IsNone())
{
UE_LOG(LogMutable,Error,TEXT("The path to scan can not be empty"))
return 1;
}
}
UE_LOG(LogMutable, Log, TEXT("(string) instance_search_path : %s "), *InstancesPackagePath.ToString());
// Load the asset registry system so we can proceed without issues
PrepareAssetRegistry();
LogGlobalSettings();
// Cache all UAssets (find a way to not have them in memory yet, not until we need them)
const TArray<FAssetData> FoundAssetData = FindAllAssetsAtPath(InstancesPackagePath, UCustomizableObjectInstance::StaticClass());
// Early exit if no instances could be found for testing.
if (FoundAssetData.IsEmpty())
{
UE_LOG(LogMutable,Error,TEXT("Aborting Bulk Instance Update Test: No assets could be found at the provided package path"));
return 1;
}
// Get all the CO's that need compilation before proceeding
TMap<UCustomizableObject*, TArray<TStrongObjectPtr<UCustomizableObjectInstance>>> MutableResources;
for (const FAssetData& Data : FoundAssetData)
{
UObject* LoadedAsset = MutablePrivate::LoadObject(Data);
check (LoadedAsset);
UCustomizableObjectInstance* LoadedInstance = Cast<UCustomizableObjectInstance>(LoadedAsset);
check (LoadedInstance)
// Get the COI CO and cache it for later compilation
UCustomizableObject* InstanceCO = LoadedInstance->GetCustomizableObject();
if (!InstanceCO)
{
UE_LOG(LogMutable,Error,TEXT("The instance %s does not have a CO. This instance will not get tested."), *LoadedInstance->GetName());
continue;
}
// Add/update an entry with the new instance for a given CO.
TArray<TStrongObjectPtr<UCustomizableObjectInstance>>& Entry = MutableResources.FindOrAdd(InstanceCO);
Entry.Emplace(LoadedInstance);
}
// At this point it is safe to assume that all keys are valid COs and all instances are also valid.
// Report the objects found (COs and COIs) -------------------------------
const uint32 TotalAmountOfCustomizableObjects = MutableResources.Num();
UE_LOG(LogMutable,Display,TEXT("Customizable Objects to compile : %u"), TotalAmountOfCustomizableObjects);
UE_LOG(LogMutable, Log, TEXT("(int) customizable_objects_count : %u "), TotalAmountOfCustomizableObjects);
const uint32 TotalAmountOfInstances = FoundAssetData.Num();
UE_LOG(LogMutable,Display,TEXT("Customizable Object Instances to update : %u"), TotalAmountOfInstances);
UE_LOG(LogMutable, Log, TEXT("(int) customizable_object_instances_count : %u "), TotalAmountOfInstances);
// Report the amount of instances for each of the COs found as parents of the instances in the target path
for (TTuple<UCustomizableObject*, TArray<TStrongObjectPtr<UCustomizableObjectInstance>>>& MutableResourceTuple : MutableResources)
{
const UCustomizableObject* CustomizableObjectToCompile = MutableResourceTuple.Key;
check (CustomizableObjectToCompile);
const FString CustomizableObjectName = CustomizableObjectToCompile->GetName();
const uint32 COInstancesCount = MutableResourceTuple.Value.Num();
UE_LOG(LogMutable,Display,TEXT("The CO \"%s\" has in total \"%u\" instances."), *CustomizableObjectName, COInstancesCount );
UE_LOG(LogMutable, Log, TEXT("(int) %s_instance_count : %u "), *CustomizableObjectName, COInstancesCount);
// print the name of the instances+
uint32 InstanceIndex = 0;
for (const TStrongObjectPtr<UCustomizableObjectInstance>& Instance : MutableResourceTuple.Value)
{
check(Instance);
const FString CustomizableObjectInstanceName = Instance->GetName();
UE_LOG(LogMutable, Log, TEXT("%u : \"%s\""), InstanceIndex++, *CustomizableObjectInstanceName);
}
}
// ------ Execution of the actual mutable operations ------
// Make sure there is nothing else that the engine needs to do before starting our test
Wait(60);
// Cache the target compilation platform so we can override the compilation configs of the target COs
ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef();
const ITargetPlatform* TargetCompilationPlatform = TPM.GetRunningTargetPlatform();
TSharedRef<FCustomizableObjectCompilationUtility> CompilationUtility = MakeShared<FCustomizableObjectCompilationUtility>();
TSharedRef<FCustomizableObjectInstanceUpdateUtility> InstanceUpdatingUtility = MakeShared<FCustomizableObjectInstanceUpdateUtility>();
// Compile all found COs one by one
uint32 CurrentInstanceIndex = 1;
for ( TMap<UCustomizableObject*, TArray<TStrongObjectPtr<UCustomizableObjectInstance>>>::TIterator ResourcesIterator = MutableResources.CreateIterator(); ResourcesIterator; ++ResourcesIterator)
{
UCustomizableObject*& CustomizableObject = ResourcesIterator->Key;
check (CustomizableObject);
const FString CustomizableObjectName = CustomizableObject->GetName();
// Set the compilation platform based on what the system is currently running on
FCompilationOptions CompilationOptions = GetCompilationOptionsForBenchmarking(*CustomizableObject);
CompilationOptions.TargetPlatform = TargetCompilationPlatform;
// Compile the current CO object
if (!CompilationUtility->CompileCustomizableObject(*CustomizableObject, false, &CompilationOptions)) // Do not log mutable data since mongoDB will not be able to handle it correctly
{
UE_LOG(LogMutable, Error,TEXT("The CO %s could not be compiled successfully. Skipping the update of all COIs that use it."), *CustomizableObjectName )
continue;
}
// Now that CO has been compiled proceed with the update of the instances that use it
const uint32 CustomizableObjectInstanceCount = ResourcesIterator->Value.Num();
UE_LOG(LogMutable, Display, TEXT("Starting update of the \"%u\" instances with CO : \"%s\"."), CustomizableObjectInstanceCount, *CustomizableObjectName);
// Iterate over all the COIs of the CO and update them
TArray<TStrongObjectPtr<UCustomizableObjectInstance>>& Instances = ResourcesIterator->Value;
while (!Instances.IsEmpty())
{
TStrongObjectPtr<UCustomizableObjectInstance> Instance = Instances[0];
check(Instance);
Instances.RemoveAt(0);
UE_LOG(LogMutable, Display, TEXT("\t( %u / %u ) Processing instance : \"%s\" ."),CurrentInstanceIndex++, TotalAmountOfInstances ,*Instance->GetName());
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
// Update each one of the instances and notify if the update failed in any manner
InstanceUpdatingUtility->UpdateInstance(*Instance);
// Remove standalone flag from the instance so we can GC it while keeping other standalone objects
Instance->ClearFlags(EObjectFlags::RF_Standalone);
}
ResourcesIterator.RemoveCurrent();
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
}
UE_LOG(LogMutable,Display,TEXT("Mutable commandlet finished."));
return 0;
}