Hi, I’m trying to save a static mesh (generated from PCG) into my unreal assets. Once the asset has been generated, I call OnPCGGenerated which then calls the following functions. The idea here is that I will delete the original actor and replace it within the scene with a new actor with a static mesh component instead of the PCG component. This is to improve overall performance. The files generate in the expected location with the expected filenames, however they are not appearing in the Content Drawer within the Unreal Engine Editor…
What am I doing wrong that’s resulting in these .uasset files not being discovered by unreal engine? I’ve tried copying pre-existing assets into the folder and those get detected instantly whilst my generated ones do not get detected at all whilst existing in the filespace…
void APCGToStaticMeshComponent::OnPCGGenerated(const FPCGDataCollection& DataCollection)
{
MountAssetDir();
AActor* NewActor = ClearPCGLink();
if (NewActor)
{
ClearSplinePoints(NewActor);
ConvertToStaticMesh(NewActor);
}
// Destroy the original PCG actor after merging
if (!Destroy(true))
{
UE_LOG(LogTemp, Error, TEXT("Unable to destroy PCG actor."));
}
}
void APCGToStaticMeshComponent::MountAssetDir()
{
const FString MountPoint = "/Game/PCG/StaticMeshes/";
const FString AbsolutePath = FPaths::ProjectContentDir() + "PCG/StaticMeshes/";
if (!IFileManager::Get().DirectoryExists(*AbsolutePath))
{
IFileManager::Get().MakeDirectory(*AbsolutePath);
}
if (FPackageName::MountPointExists(MountPoint))
{
FPackageName::UnRegisterMountPoint(MountPoint, AbsolutePath);
}
FPackageName::RegisterMountPoint(MountPoint, AbsolutePath);
UE_LOG(LogTemp, Log, TEXT("Registered mount point '%s' to '%s'"), *MountPoint, *AbsolutePath);
}
AActor* APCGToStaticMeshComponent::ClearPCGLink()
{
UPCGComponent* PCGComponent = GetComponentByClass<UPCGComponent>();
if (!PCGComponent)
{
UE_LOG(LogTemp, Error, TEXT("Unable to find PCG Component in Actor."));
return nullptr;
}
AActor* NewActor = PCGComponent->ClearPCGLink();
if (!NewActor)
{
UE_LOG(LogTemp, Error, TEXT("Unable to clear PCG Link"));
return nullptr;
}
NewActor->SetActorLabel(GetActorLabel());
return NewActor;
}
void APCGToStaticMeshComponent::ClearSplinePoints(AActor* Actor)
{
TArray<USplineComponent*> SplineComponents;
Actor->GetComponents(SplineComponents);
for (USplineComponent* SplineComponent : SplineComponents)
{
if (SplineComponent)
{
SplineComponent->DestroyComponent();
}
}
}
void APCGToStaticMeshComponent::ConvertToStaticMesh(AActor* Actor)
{
// Get all instanced static mesh components in the actor
TArray<UInstancedStaticMeshComponent*> InstancedMeshComponents;
Actor->GetComponents(InstancedMeshComponents);
// Convert to TArray<UPrimitiveComponent*> for MergeComponentsToStaticMesh function
TArray<UPrimitiveComponent*> ComponentsToMerge;
for (UInstancedStaticMeshComponent* InstancedMesh : InstancedMeshComponents)
{
ComponentsToMerge.Add(Cast<UPrimitiveComponent>(InstancedMesh));
}
// Ensure there's at least one component to convert
if (ComponentsToMerge.Num() > 0)
{
// Calculate the center of all components for positioning
FVector ComponentGroupCenter = FVector::ZeroVector;
for (UPrimitiveComponent* Component : ComponentsToMerge)
{
ComponentGroupCenter += Component->GetComponentLocation();
}
ComponentGroupCenter /= ComponentsToMerge.Num();
// Offset components by the calculated center to align with the world origin
for (UPrimitiveComponent* Component : ComponentsToMerge)
{
Component->SetWorldLocation(Component->GetComponentLocation() - ComponentGroupCenter);
}
// Set up the merging utility and settings
const IMeshMergeUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshMergeModule>("MeshMergeUtilities").GetUtilities();
FMeshMergingSettings MergeSettings;
MergeSettings.bMergeEquivalentMaterials = true;
MergeSettings.bBakeVertexDataToMesh = true;
MergeSettings.bMergePhysicsData = true;
MergeSettings.bSupportRayTracing = true;
MergeSettings.bGenerateLightMapUV = true;
// Prepare the asset path and package
FString AssetName = Actor->GetActorLabel();
FString RelativePath = TEXT("/Game/PCG/StaticMeshes/");
FString PackageName = RelativePath + "SM_" + AssetName;
UPackage* NewPackage = CreatePackage(*PackageName);
NewPackage->SetFlags(RF_Public | RF_Standalone);
// Merge components into a single static mesh
TArray<UObject*> OutAssetsToSync;
FVector OutMergedActorLocation;
MeshUtilities.MergeComponentsToStaticMesh(ComponentsToMerge, Actor->GetWorld(), MergeSettings, nullptr,
NewPackage, PackageName, OutAssetsToSync,
OutMergedActorLocation, 0.0f, false);
// Save the merged static mesh if successfully created
if (OutAssetsToSync.Num() > 0)
{
UStaticMesh* MergedStaticMesh = Cast<UStaticMesh>(OutAssetsToSync[0]);
if (MergedStaticMesh)
{
MergedStaticMesh->SetFlags(RF_Public | RF_Standalone);
FAssetRegistryModule::AssetCreated(MergedStaticMesh);
bool dirty = MergedStaticMesh->MarkPackageDirty();
NewPackage->SetDirtyFlag(true);
// Specify save path
FSavePackageArgs SaveArgs;
SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
SaveArgs.Error = GLog;
FString PackagePath = FPackageName::LongPackageNameToFilename("/Game/PCG/StaticMeshes/SM_" + AssetName, FPackageName::GetAssetPackageExtension());
if (UPackage::SavePackage(NewPackage, MergedStaticMesh, *PackagePath, SaveArgs))
{
UE_LOG(LogTemp, Log, TEXT("Successfully saved static mesh package: %s"), *PackagePath);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to save static mesh package: %s"), *PackagePath);
}
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to cast the merged asset to UStaticMesh."));
}
}
else
{
UE_LOG(LogTemp, Error, TEXT("No assets created during merge process."));
}
}
}