| 704 | } // namespace |
| 705 | |
| 706 | bool ListActorsSync( |
| 707 | TArray<TSharedPtr<FJsonValue>>& OutActors, |
| 708 | FString& OutError) |
| 709 | { |
| 710 | OutActors.Reset(); |
| 711 | OutError.Empty(); |
| 712 | if (!GEditor) |
| 713 | { |
| 714 | OutError = TEXT("GEditor null"); |
| 715 | return false; |
| 716 | } |
| 717 | UWorld* World = GEditor->GetEditorWorldContext().World(); |
| 718 | if (!World) |
| 719 | { |
| 720 | OutError = TEXT("editor world unavailable"); |
| 721 | return false; |
| 722 | } |
| 723 | |
| 724 | for (TActorIterator<AActor> It(World); It; ++It) |
| 725 | { |
| 726 | AActor* A = *It; |
| 727 | if (!ShouldListActor(A)) |
| 728 | continue; |
| 729 | |
| 730 | TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>(); |
| 731 | Obj->SetStringField(TEXT("name"), A->GetName()); |
| 732 | // The user-visible label from UE's own outliner (set via the |
| 733 | // Details > "Actor Label" field). Falls back to GetName if |
| 734 | // empty so the bridge UI never shows a blank row. |
| 735 | #if WITH_EDITOR |
| 736 | FString Label = A->GetActorLabel(); |
| 737 | #else |
| 738 | FString Label = A->GetName(); |
| 739 | #endif |
| 740 | if (Label.IsEmpty()) |
| 741 | Label = A->GetName(); |
| 742 | Obj->SetStringField(TEXT("label"), Label); |
| 743 | Obj->SetStringField(TEXT("class"), A->GetClass()->GetName()); |
| 744 | |
| 745 | const FString Aid = ExtractActorId(A); |
| 746 | Obj->SetStringField(TEXT("actor_id"), Aid); |
| 747 | Obj->SetBoolField(TEXT("is_articulation"), |
| 748 | A->IsA(AMjArticulation::StaticClass())); |
| 749 | Obj->SetBoolField(TEXT("is_static_mesh_actor"), |
| 750 | A->IsA(AStaticMeshActor::StaticClass())); |
| 751 | Obj->SetBoolField(TEXT("is_light"), |
| 752 | A->IsA(ALight::StaticClass())); |
| 753 | |
| 754 | // MJ-native pose: convert UE cm -> metres, UE rotation -> MJ quat. |
| 755 | const FVector UELoc = A->GetActorLocation(); |
| 756 | const FQuat UEQ = A->GetActorQuat(); |
| 757 | double MjPos[3], MjQuat[4]; |
| 758 | MjUtils::UEToMjPosition(UELoc, MjPos); |
| 759 | MjUtils::UEToMjRotation(UEQ, MjQuat); |
| 760 | TArray<TSharedPtr<FJsonValue>> LocOut; |
| 761 | for (int i = 0; i < 3; ++i) |
| 762 | LocOut.Add(MakeShared<FJsonValueNumber>(MjPos[i])); |
| 763 | Obj->SetArrayField(TEXT("location"), LocOut); |
no test coverage detected