| 1297 | } |
| 1298 | |
| 1299 | bool ActorHierarchySync( |
| 1300 | const FString& ActorKey, |
| 1301 | TSharedPtr<FJsonObject>& OutRoot, |
| 1302 | FString& OutError) |
| 1303 | { |
| 1304 | OutError.Empty(); |
| 1305 | if (!GEditor) |
| 1306 | { |
| 1307 | OutError = TEXT("GEditor null"); |
| 1308 | return false; |
| 1309 | } |
| 1310 | UWorld* PieWorld = GEditor->PlayWorld; |
| 1311 | UWorld* World = PieWorld ? PieWorld : GEditor->GetEditorWorldContext().World(); |
| 1312 | if (!World) |
| 1313 | { |
| 1314 | OutError = TEXT("no world available"); |
| 1315 | return false; |
| 1316 | } |
| 1317 | AActor* A = FindByActorIdOrName(World, ActorKey); |
| 1318 | if (!A) |
| 1319 | { |
| 1320 | OutError = FString::Printf(TEXT("no actor matching '%s'"), *ActorKey); |
| 1321 | return false; |
| 1322 | } |
| 1323 | |
| 1324 | // Walk via Actor->GetAttachedActors recursively. UE allows actor |
| 1325 | // attachment trees independent of component trees. |
| 1326 | TFunction<TSharedPtr<FJsonObject>(AActor*)> BuildNode; |
| 1327 | BuildNode = [&BuildNode](AActor* N) -> TSharedPtr<FJsonObject> { |
| 1328 | TSharedPtr<FJsonObject> Node = MakeShared<FJsonObject>(); |
| 1329 | Node->SetStringField(TEXT("name"), N->GetName()); |
| 1330 | Node->SetStringField(TEXT("class"), N->GetClass()->GetName()); |
| 1331 | |
| 1332 | double MjPos[3]; |
| 1333 | MjUtils::UEToMjPosition(N->GetActorLocation(), MjPos); |
| 1334 | TArray<TSharedPtr<FJsonValue>> LocOut; |
| 1335 | for (int i = 0; i < 3; ++i) |
| 1336 | LocOut.Add(MakeShared<FJsonValueNumber>(MjPos[i])); |
| 1337 | Node->SetArrayField(TEXT("location"), LocOut); |
| 1338 | |
| 1339 | TArray<AActor*> Attached; |
| 1340 | N->GetAttachedActors(Attached, /*bResetArray=*/true, /*bRecurse=*/false); |
| 1341 | TArray<TSharedPtr<FJsonValue>> Children; |
| 1342 | for (AActor* C : Attached) |
| 1343 | if (C) |
| 1344 | Children.Add(MakeShared<FJsonValueObject>(BuildNode(C))); |
| 1345 | Node->SetArrayField(TEXT("children"), Children); |
| 1346 | return Node; |
| 1347 | }; |
| 1348 | OutRoot = BuildNode(A); |
| 1349 | return true; |
| 1350 | } |
| 1351 | } // namespace URLabLevelOps |