// Portage UE 5.5 - voir LPFixSceneCaptureCommandlet.h #include "LPFixSceneCaptureCommandlet.h" #include "Components/SceneCaptureComponent2D.h" #include "Engine/Level.h" #include "Engine/SceneCapture2D.h" #include "Engine/World.h" #include "Misc/PackageName.h" #include "UObject/Package.h" #include "UObject/SavePackage.h" DEFINE_LOG_CATEGORY_STATIC(LogLPFixSceneCapture, Log, All); namespace { AActor* FindActorByLabelOrName(ULevel* Level, const FString& Name) { for (AActor* Actor : Level->Actors) { if (Actor && (Actor->GetActorLabel() == Name || Actor->GetName() == Name)) { return Actor; } } return nullptr; } } ULPFixSceneCaptureCommandlet::ULPFixSceneCaptureCommandlet() { IsClient = false; IsServer = false; IsEditor = true; LogToConsole = true; } int32 ULPFixSceneCaptureCommandlet::Main(const FString& Params) { TArray Tokens, Switches; TMap ParamsMap; ParseCommandLine(*Params, Tokens, Switches, ParamsMap); const bool bDryRun = Switches.Contains(TEXT("DryRun")); const FString MapPath = ParamsMap.FindRef(TEXT("Map")); const FString ActorName = ParamsMap.FindRef(TEXT("Actor")); const FString FromName = ParamsMap.FindRef(TEXT("From")); FVector Offset = FVector::ZeroVector; { TArray Parts; ParamsMap.FindRef(TEXT("Offset")).ParseIntoArray(Parts, TEXT(","), true); if (Parts.Num() == 3) { Offset = FVector(FCString::Atod(*Parts[0]), FCString::Atod(*Parts[1]), FCString::Atod(*Parts[2])); } } if (MapPath.IsEmpty() || ActorName.IsEmpty() || FromName.IsEmpty()) { UE_LOG(LogLPFixSceneCapture, Error, TEXT("Usage : -Map=/Game/Scenes/X -Actor= -From= [-Offset=x,y,z] [-DryRun]")); return 1; } const FString WorldPath = MapPath + TEXT(".") + FPackageName::GetShortName(MapPath); UWorld* World = LoadObject(nullptr, *WorldPath); if (!World || !World->PersistentLevel) { UE_LOG(LogLPFixSceneCapture, Error, TEXT("Carte introuvable : %s"), *WorldPath); return 1; } World->AddToRoot(); ASceneCapture2D* Capture = Cast(FindActorByLabelOrName(World->PersistentLevel, ActorName)); AActor* From = FindActorByLabelOrName(World->PersistentLevel, FromName); if (!Capture || !From || !From->GetRootComponent()) { UE_LOG(LogLPFixSceneCapture, Error, TEXT("Acteur introuvable : %s (capture) ou %s (reference, avec racine)"), *ActorName, *FromName); World->RemoveFromRoot(); return 1; } USceneCaptureComponent2D* CaptureComp = Capture->GetCaptureComponent2D(); USceneComponent* NewRoot = nullptr; for (UActorComponent* Comp : Capture->GetComponents()) { USceneComponent* SceneComp = Cast(Comp); if (SceneComp && SceneComp != CaptureComp && SceneComp->GetClass() == USceneComponent::StaticClass()) { NewRoot = SceneComp; break; } } if (!NewRoot) { NewRoot = CaptureComp; } const FTransform FromTransform = From->GetRootComponent()->GetRelativeTransform(); const FTransform Target(FromTransform.GetRotation(), FromTransform.GetLocation() + Offset, FVector::OneVector); UE_LOG(LogLPFixSceneCapture, Warning, TEXT("=== %s : racine %s -> %s, cible %s (= %s + %s)%s ==="), *Capture->GetActorLabel(), *GetNameSafe(Capture->GetRootComponent()), *GetNameSafe(NewRoot), *Target.ToString(), *FromName, *Offset.ToString(), bDryRun ? TEXT(" [DRY RUN]") : TEXT("")); if (bDryRun) { World->RemoveFromRoot(); return 0; } Capture->Modify(); Capture->SetRootComponent(NewRoot); if (CaptureComp && CaptureComp != NewRoot) { CaptureComp->AttachToComponent(NewRoot, FAttachmentTransformRules::KeepRelativeTransform); CaptureComp->SetRelativeTransform(FTransform::Identity); } NewRoot->SetRelativeTransform(Target); NewRoot->UpdateComponentToWorld(); if (CaptureComp && CaptureComp != NewRoot) { CaptureComp->UpdateComponentToWorld(); } // Verification : racine, rattachement, position monde de la capture. int32 Errors = 0; if (Capture->GetRootComponent() != NewRoot) { ++Errors; UE_LOG(LogLPFixSceneCapture, Error, TEXT(" racine non affectee")); } if (CaptureComp && CaptureComp != NewRoot && CaptureComp->GetAttachParent() != NewRoot) { ++Errors; UE_LOG(LogLPFixSceneCapture, Error, TEXT(" capture non rattachee")); } const FTransform Final = CaptureComp ? CaptureComp->GetComponentTransform() : NewRoot->GetComponentTransform(); if (!Final.Equals(Target, 0.01)) { ++Errors; UE_LOG(LogLPFixSceneCapture, Error, TEXT(" position finale %s differente de la cible %s"), *Final.ToString(), *Target.ToString()); } UE_LOG(LogLPFixSceneCapture, Warning, TEXT(" capture : position monde %s"), *Final.ToString()); int32 Result = 0; if (Errors == 0) { UPackage* Package = World->GetOutermost(); const FString Filename = FPackageName::LongPackageNameToFilename(Package->GetName(), FPackageName::GetMapPackageExtension()); FSavePackageArgs SaveArgs; SaveArgs.TopLevelFlags = RF_Standalone; SaveArgs.Error = GWarn; if (UPackage::SavePackage(Package, World, *Filename, SaveArgs)) { UE_LOG(LogLPFixSceneCapture, Warning, TEXT(" -> carte sauvegardee")); } else { UE_LOG(LogLPFixSceneCapture, Error, TEXT(" ECHEC de sauvegarde")); Result = 1; } } else { UE_LOG(LogLPFixSceneCapture, Error, TEXT(" %d ecart(s) : carte NON sauvegardee"), Errors); Result = 1; } World->RemoveFromRoot(); return Result; }