UE::AssetUtils::SaveGeneratedTexture2DAsset crashes on some texture types, such as trying to use it to save, then overwrite the minimap texture that comes from the AWorldPartitionMiniMap actor.
Steps to Reproduce
void FGameRuntimeMapMinimap::UpdateMinimapCache(UWorld* World)
{
if(IsValid(World))
{
MinimapTexture = nullptr;
MinimapBounds.Init();
MinimapUVOffset.Init();
if(AWorldPartitionMiniMap* Minimap = FWorldPartitionMiniMapHelper::GetWorldPartitionMiniMap(World, false))
{
if(IsValid(Minimap->MiniMapTexture))
{
if (UTexture2D* DupeMinimap = DuplicateObject(Minimap->MiniMapTexture, GetTransientPackage()))
{
UE::AssetUtils::FTexture2DAssetOptions SaveTextureOptions;
SaveTextureOptions.NewAssetPath = FString::Printf(TEXT("%s_Minimap"), *World->GetPackage()->GetPathName());
SaveTextureOptions.bOverwriteIfExists = true;
UE::AssetUtils::FTexture2DAssetResults SaveTextureResult;
if (UE::AssetUtils::ECreateTexture2DResult::Ok == UE::AssetUtils::SaveGeneratedTexture2DAsset(DupeMinimap, SaveTextureOptions, SaveTextureResult))
{
MinimapTexture = SaveTextureResult.Texture;
MinimapBounds = Minimap->MiniMapWorldBounds;
MinimapUVOffset = Minimap->UVOffset;
}
}
}
}
}
}
- Run the above code once will work properly
- Run the above code a 2nd time, where it attempts to perform the bOverwriteIfExists logic, and it will fail a series of ensure checks, and then crashes.
The reason seems to be that this utility function tries to do invalid stuff with a DTX1 virtual texture that is built by the minimap system.
Hi there,
Thanks for this, I’ve reproduced the issue and reported it as a bug. Currently, in the case where an asset already exists, the SaveGeneratedTexture2DAsset function tries to copy the texture data between the two existing textures. Unfortunately, there are many edge cases that this code does not handled. One of which is copy texture data for a texture with any type of compression. In the new asset case, this function is simply moving the transient object to a non-transient package that can be saved, so no texture data manipulation is required in this case. I would recommend that, until this is fixed, you simply handle the existing asset case yourself. This can be done using the following code snippet:
FString MinimapAssetPath = FString::Printf(TEXT("%s_Minimap"), *World->GetPackage()->GetPathName());
if (UTexture2D* ExistingTexture = LoadObject<UTexture2D>(nullptr, *MinimapAssetPath, nullptr, LOAD_NoWarn | LOAD_Quiet))
{
if (UTexture2D* DupeMinimap = DuplicateObject(Minimap->MiniMapTexture, ExistingTexture->GetOuter(), ExistingTexture->GetFName()))
{
DupeMinimap->ClearFlags(RF_Transient);
DupeMinimap->SetFlags(RF_Public | RF_Standalone | RF_Transactional);
DupeMinimap->MarkPackageDirty();
DupeMinimap->Modify();
UE_LOG(LogTemp, Log, TEXT("SaveWorldPartitionMinimapFromWorld: Successfully duplicated minimap texture into existing asset: %s"), *MinimapAssetPath);
return true;
}
UE_LOG(LogTemp, Error, TEXT("SaveWorldPartitionMinimapFromWorld: Failed to duplicate minimap texture into existing asset"));
return false;
}
This code duplicates the source texture over top of (and replaces) whatever texture exists at the specified asset path.
Once the bug report has been processed by epic it should become publicly visible here.
Regards,
Lance Chaney
Thanks!
No problem. Since the the bug report has now gone public, I will be closing off this case.
Regards,
Lance Chaney