FReply UConfigImportExport::OnExportGltf()

in Ambit/Source/Ambit/Mode/ConfigImportExport.cpp [493:606]


FReply UConfigImportExport::OnExportGltf()
{
    FAmbitMode* AmbitMode = FAmbitMode::GetEditorMode();
    check(AmbitMode);

    const TArray<FString> TargetPlatforms = AmbitMode->UISettings->ExportPlatforms.GetSelectedPlatforms();

    FString AwsRegion;
    FString BucketName;
    const bool bFoundBucket = GetAwsSettings(AwsRegion, BucketName, true);
    if (!bFoundBucket)
    {
        return FReply::Handled();
    }

    // Find World and compare to CurrentWorldContext to make sure we're not accidentally referring to valid static
    // object from another world context.
    UWorld* CurrentWorldContext = GEngine->GetWorldContexts()[0].World();
    bool bFoundWorld = false;
    for (TObjectIterator<UStaticMeshComponent> Itr; Itr; ++Itr)
    {
        AActor* Parent = (*Itr)->GetOwner();
        if (Parent == nullptr)
        {
            continue;
        }

        // Two steps to determine validity of actor as a static mesh actor:
        // 1. It should be of type AStaticMeshActor or AHoudiniAssetActor.
        // 2. It should not be marked for deletion in the editor.
        const bool bIsStaticMeshActor = Parent->IsA(AStaticMeshActor::StaticClass());
        const bool bIsHoudiniAssetActor = UHoudiniPublicAPIAssetWrapper::CanWrapHoudiniObject(Parent);
        const bool bIsValidActor = bIsStaticMeshActor || bIsHoudiniAssetActor;
        const bool bIsActorBeingDeleted = Parent->IsActorBeingDestroyed();
        if (!bIsValidActor || bIsActorBeingDeleted)
        {
            continue;
        }

        // Important to check if ParentWorld == nullptr because it is possible for an Actor to be of type
        // AStaticMeshActor or AHoudiniAssetActor but not be associated with a World object,
        // (e.g) AInteractiveFoliageActor, which derives from AStaticMeshActor but doesn't point to a World object.
        UWorld* ParentWorld = Parent->GetWorld();
        if (ParentWorld != nullptr && ParentWorld == CurrentWorldContext)
        {
            bFoundWorld = true;
            break;
        }
    }

    FString ErrorMessage;
    if (!bFoundWorld)
    {
        ErrorMessage = "Cannot find a static mesh to export.";
        FMenuHelpers::LogErrorAndPopup(ErrorMessage);

        return FReply::Handled();
    }

    const FString GltfExtension = AmbitMode->UISettings->GltfType.ToLower();

    const FString MapName = CurrentWorldContext->GetName();
    const FString FolderName = MapName + TEXT("_") + GltfExtension;
    const FString Filename = MapName + TEXT(".") + GltfExtension;

    const FString OutputDir = FPaths::Combine(*FPaths::ProjectDir(), TEXT("Saved"), TEXT("Cooked"), FolderName);
    const FString FilePath = FPaths::Combine(OutputDir, Filename);

    // Perform the export to glTF.
    const UGltfExport::GltfExportReturnCode ReturnCode = LambdaExportGltf(CurrentWorldContext, FilePath);
    if (ReturnCode == UGltfExport::ExporterNotInitialized)
    {
        ErrorMessage = "glTF Exporter not initialized.";
        FMenuHelpers::LogErrorAndPopup(ErrorMessage);

        return FReply::Handled();
    }
    if(ReturnCode == UGltfExport::ExporterNotFound)
    {
        ErrorMessage = "glTF Export: glTF Exporter plugin is not installed. \
        Follow the instructions in the User Guide to install the glTF Exporter plugin from the marketplace.";
        FMenuHelpers::LogErrorAndPopup(ErrorMessage);

        return FReply::Handled();
    }
    if (ReturnCode == UGltfExport::WriteToFileError)
    {
        ErrorMessage = "glTF Export: Error writing to file " + FilePath;
        FMenuHelpers::LogErrorAndPopup(ErrorMessage);

        return FReply::Handled();
    }
    if (ReturnCode == UGltfExport::Failed)
    {
        ErrorMessage = "glTF Export: Error completing export to " + FilePath;
        FMenuHelpers::LogErrorAndPopup(ErrorMessage);

        return FReply::Handled();
    }

    for (const FString& TargetPlatform : TargetPlatforms)
    {
        const FString& CompressedFile = AmbitFileHelpers::CompressFile(OutputDir, FPaths::ProjectIntermediateDir(),
                                                                       FolderName, TargetPlatform);

        LambdaS3FileUpload(AwsRegion, BucketName, CompressedFile,
                           FPaths::Combine(*FPaths::ProjectIntermediateDir(), *CompressedFile));
    }

    const FText NotificationText = NSLOCTEXT("Ambit", "MapUploadComplete", "Successfully uploaded to S3.");
    FAmbitModule::CreateAmbitNotification(NotificationText);

    return FReply::Handled();
}