Agrarsense
SimulatorJsonParser.cpp
Go to the documentation of this file.
1// Copyright (c) 2023 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
7
12
20
23
25
39
40
41#include "Kismet/GameplayStatics.h"
42#include "Camera/PlayerCameraManager.h"
43#include "GenericPlatform/GenericPlatformFile.h"
44#include "Serialization/JsonSerializer.h"
45#include "Serialization/JsonWriter.h"
46#include "Misc/DefaultValueHelper.h"
47#include "HAL/PlatformFileManager.h"
48#include "GameFramework/Pawn.h"
49#include "Misc/FileHelper.h"
50#include "Dom/JsonObject.h"
51#include "GameFramework/PlayerController.h"
52#include "CollisionQueryParams.h"
53#include "Engine/GameViewportClient.h"
54#include "Engine/EngineTypes.h"
55#include "Engine/Engine.h"
56#include "Engine/World.h"
57
59{
61 {
62 SimulatorLog::Log("SimulatorJsonParser: Spawning objects in main menu is disabled.");
63 return;
64 }
65
66 if (!FPaths::FileExists(Path))
67 {
68 SimulatorLog::Log("SimulatorJsonParser: Path doesn't exist.");
69 return;
70 }
71
72 if (!FPaths::GetExtension(Path).Equals(TEXT("json"), ESearchCase::IgnoreCase))
73 {
74 SimulatorLog::Log("SimulatorJsonParser: Invalid file extension. Only .json files are supported.");
75 return;
76 }
77
78 FString JsonString;
79 if (!FFileHelper::LoadFileToString(JsonString, *Path))
80 {
81 SimulatorLog::Log("SimulatorJsonParser: Failed to read the json file.");
82 return;
83 }
84
85 TSharedPtr<FJsonObject> RootJsonObject = MakeShareable(new FJsonObject);
86 TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(JsonString);
87 if (!FJsonSerializer::Deserialize(Reader, RootJsonObject))
88 {
89 SimulatorLog::Log("SimulatorJsonParser: Failed to deserialize json file.");
90 return;
91 }
92
93 const TArray<TSharedPtr<FJsonValue>>* JsonObjects;
94 if (!RootJsonObject->TryGetArrayField("objects", JsonObjects))
95 {
96 SimulatorLog::Log("json content doesn't contain 'objects' field. Make sure your json structure is correct.");
97 return;
98 }
99
100 // Finally start to go through the types defined in the json file.
101 for (const TSharedPtr<FJsonValue>& JsonObjectValue : *JsonObjects)
102 {
103 if (JsonObjectValue->Type != EJson::Object)
104 {
105 continue;
106 }
107
108 TSharedPtr<FJsonObject> JsonObject = JsonObjectValue->AsObject();
109 FString ObjectType;
110 if (!JsonObject->TryGetStringField("type", ObjectType))
111 {
112 continue;
113 }
114
115 // Parse types
116 if (ObjectType.Equals("vehicle", ESearchCase::IgnoreCase))
117 {
118 ParseVehicle(JsonObject);
119 }
120 if (ObjectType.Equals("spectator", ESearchCase::IgnoreCase))
121 {
122 ParseVehicle(JsonObject);
123 }
124 else if (ObjectType.Equals("weather", ESearchCase::IgnoreCase))
125 {
126 ChangeWeather(JsonObject);
127 }
128 else if (ObjectType.Equals("walker", ESearchCase::IgnoreCase))
129 {
130 SpawnWalker(JsonObject);
131 }
132 else if (ObjectType.Equals("sensor", ESearchCase::IgnoreCase))
133 {
134 SpawnSensorWorld(JsonObject);
135 }
136 else if (ObjectType.Equals("prop", ESearchCase::IgnoreCase) || ObjectType.Equals("Foliage", ESearchCase::IgnoreCase))
137 {
138 ParsePropOrFoliage(JsonObject, ObjectType);
139 }
140 else if (ObjectType.Equals("semanticColors", ESearchCase::IgnoreCase))
141 {
142 ParseAndSetSemanticColors(JsonObject);
143 }
144 else if (ObjectType.Equals("commands", ESearchCase::IgnoreCase))
145 {
146 ParseCommands(JsonObject);
147 }
148 else if (ObjectType.Equals("volumeDeletion", ESearchCase::IgnoreCase))
149 {
150 ParseVolumeDeletion(JsonObject);
151 }
152 }
153}
154
155void USimulatorJsonParser::ParseVehicle(const TSharedPtr<FJsonObject>& JsonObject)
156{
157 FString Model;
158 if (!JsonObject->TryGetStringField("model", Model))
159 {
160 // If json doesn't specifiy model, return
161 return;
162 }
163
164 FString Name, ID;
165 JsonObject->TryGetStringField("name", Name);
166 JsonObject->TryGetStringField("id", ID);
167 if (ID.IsEmpty())
168 {
169 ID = Model;
170 }
171
172 FTransform SpawnTransform = ParseTransform("spawnPoint", JsonObject);
173
174 bool DestroyCollidedObjectsOnSpawn = false;
175 JsonObject->TryGetBoolField("destroyOverlappingObjects", DestroyCollidedObjectsOnSpawn);
176
178 AVehicle* VehiclePtr = UAssetLibrary::SpawnVehicle(VehicleType, SpawnTransform, Name, ID, false, 150.0f, DestroyCollidedObjectsOnSpawn);
179
180 if (VehiclePtr)
181 {
182 if (VehicleType == EVehicleTypes::Drone)
183 {
184 ParseAndSetDroneParameters(Cast<APIDDrone>(VehiclePtr), JsonObject);
185 }
186
187 TeleportSpectatorOrFollowActorIfField(JsonObject, Cast<AActor>(VehiclePtr), SpawnTransform);
188 }
189 else
190 {
191 // If Vehicle is nullptr, return
192 return;
193 }
194
195 // Parse possible sensors which will be attached to spawned vehicle
196 const TArray<TSharedPtr<FJsonValue>>* SensorJsonObjects;
197 if (JsonObject->TryGetArrayField("sensors", SensorJsonObjects))
198 {
199 for (const TSharedPtr<FJsonValue>& SensorValue : *SensorJsonObjects)
200 {
201 if (SensorValue->Type == EJson::Object)
202 {
203 TSharedPtr<FJsonObject> SensorJsonObject = SensorValue->AsObject();
204 SpawnSensorToVehicle(VehiclePtr, SensorJsonObject);
205 }
206 }
207 }
208}
209
210void USimulatorJsonParser::ParsePropOrFoliage(const TSharedPtr<FJsonObject>& JsonObject, const FString& ObjectType)
211{
212 FString Model;
213 if (!JsonObject->TryGetStringField("model", Model))
214 {
215 // If json doesn't specifiy model, return
216 return;
217 }
218
219 bool RandomZRotation = false;
220 bool SnapToGround = false;
221 JsonObject->TryGetBoolField("snap_to_ground", SnapToGround);
222 JsonObject->TryGetBoolField("random_z_rotation", RandomZRotation);
223
224 FString Name, ID;
225 JsonObject->TryGetStringField("name", Name);
226 JsonObject->TryGetStringField("id", ID);
227
228 FTransform SpawnTransform = ParseTransform("spawnPoint", JsonObject);
229
230 if (ObjectType.Equals("prop", ESearchCase::IgnoreCase))
231 {
233 UAssetLibrary::SpawnProp(Type, SpawnTransform, Name, ID, RandomZRotation, SnapToGround);
234 }
235 else if (ObjectType.Equals("foliage", ESearchCase::IgnoreCase))
236 {
238 UAssetLibrary::SpawnFoliage(Type, SpawnTransform, Name, ID, RandomZRotation, SnapToGround);
239 }
240}
241
242void USimulatorJsonParser::SpawnSensorToVehicle(AVehicle* Vehicle, const TSharedPtr<FJsonObject>& SensorObject)
243{
244 if (!Vehicle || !SensorObject.IsValid())
245 {
246 return;
247 }
248
249 USensorsManagerComponent* VehicleSensorManager = Vehicle->GetSensorsManager();
250 if (!VehicleSensorManager)
251 {
252 return;
253 }
254
255 TSharedPtr<FJsonObject> ParametersObject = SensorObject->GetObjectField("parameters");
256 if (!ParametersObject.IsValid())
257 {
258 return;
259 }
260
261 // Sensor spawn point (relative)
262 FTransform RelativeTransform = ParseTransform("spawnPoint", SensorObject);
263
264 // Parse ESensorTypes from string
265 FString SensorTypeString;
266 SensorObject->TryGetStringField("model", SensorTypeString);
267 ESensorTypes SensorType = UEnumUtilities::ConvertStringToSensorType(SensorTypeString);
268
269 // It's fine if these are empty,
270 // USensorsManagerComponent will just generate random name and identifier
271 FString SensorIdentifier, Name;
272 SensorObject->TryGetStringField("name", Name);
273 SensorObject->TryGetStringField("id", SensorIdentifier);
274
275 FString AttachedToComponent;
276 SensorObject->TryGetStringField("attachedToComponent", AttachedToComponent);
277
278 FString AttachedToBoneString;
279 FName AttachedToBone;
280 if (SensorObject->TryGetStringField("attachedToBone", AttachedToBoneString))
281 {
282 AttachedToBone = FName(*AttachedToBoneString);
283 }
284
285 ASensorModel* TempActor = nullptr;
286 ASensor* SensorPtr = nullptr;
287 USceneComponent* AttachToComponent = VehicleSensorManager->GetComponentByHierarchyName(AttachedToComponent);
288
289 // Here sensors are spawned through VehicleSensorManager Actor so it can keep track of the spawned sensors.
290 switch (SensorType)
291 {
293 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnLidar(RelativeTransform, true, SensorIdentifier, Name, ParseParameters<FLidarParameters>(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
294 break;
295
297 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnCamera(RelativeTransform, true, SensorIdentifier, Name, ParseParameters<FCameraBaseParameters>(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
298 break;
299
301 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnThermalCamera(RelativeTransform, true, SensorIdentifier, Name, ParseParameters<FThermalCameraParameters>(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
302 break;
303
305 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnDepthCamera(RelativeTransform, true, SensorIdentifier, Name, ParseDepthCameraParameters(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
306 break;
307
309 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnRadar(RelativeTransform, true, SensorIdentifier, Name, ParseParameters<FRadarParameters>(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
310 break;
311
313 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnSegmentationCamera(RelativeTransform, true, SensorIdentifier, Name, ParseParameters<FCameraBaseParameters>(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
314 break;
315
317 SensorPtr = Cast<ASensor>(VehicleSensorManager->SpawnDVSCamera(RelativeTransform, true, SensorIdentifier, Name, ParseDVSCameraParameters(ParametersObject), true, TempActor, AttachToComponent, AttachedToBone));
318 break;
319
320 default:
321 break;
322 }
323}
324
325void USimulatorJsonParser::SpawnSensorWorld(const TSharedPtr<FJsonObject>& SensorObject)
326{
327 if (!SensorObject.IsValid())
328 {
329 return;
330 }
331
332 if (!SensorObject->HasField("parameters") || !SensorObject->HasField("model"))
333 {
334 return;
335 }
336
337 TSharedPtr<FJsonObject> ParametersObject = SensorObject->GetObjectField("parameters");
338 if (!ParametersObject.IsValid())
339 {
340 return;
341 }
342
343 FString SensorTypeString, SensorName, SensorIdentifier;
344 SensorObject->TryGetStringField("model", SensorTypeString);
345 SensorObject->TryGetStringField("name", SensorName);
346 SensorObject->TryGetStringField("id", SensorIdentifier);
347
348 FTransform SpawnTransform = ParseTransform("spawnPoint", SensorObject);
349
350 AActor* ActorPtr = nullptr;
351 ESensorTypes SensorType = UEnumUtilities::ConvertStringToSensorType(SensorTypeString);
352
353 UWorld* World = nullptr;
354
355 if (GEngine && GEngine->GameViewport)
356 {
357 World = GEngine->GameViewport->GetWorld();
358 }
359
361 if (!SimulationLevelManager)
362 {
363 SimulatorLog::Log("Failed to spawn Sensor. Reason: Coulnd't to find SimulationLevelManager Actor!");
364 return;
365 }
366
367 USensorsManagerComponent* WorldSensorManager = SimulationLevelManager->GetSensorsManager();
368 if (!WorldSensorManager)
369 {
370 SimulatorLog::Log("Failed to spawn Sensor. Reason: Coulnd't to find USensorsManagerComponent Component!");
371 return;
372 }
373
374 ASensorModel* TempActor = nullptr;
375
376 // Here sensors are spawned through WorldSensorManager Actor so it can keep track of the spawned sensors.
377 switch (SensorType)
378 {
380 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnLidar(SpawnTransform, false, SensorIdentifier, SensorName, ParseParameters<FLidarParameters>(ParametersObject), true, TempActor, nullptr, NAME_None));
381 break;
382
384 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnRadar(SpawnTransform, false, SensorIdentifier, SensorName, ParseParameters<FRadarParameters>(ParametersObject), true, TempActor, nullptr, NAME_None));
385 break;
386
388 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnCamera(SpawnTransform, false, SensorIdentifier, SensorName, ParseParameters<FCameraBaseParameters>(ParametersObject), true, TempActor, nullptr, NAME_None));
389 break;
390
392 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnThermalCamera(SpawnTransform, false, SensorIdentifier, SensorName, ParseThermalCameraParameters(ParametersObject), true, TempActor, nullptr, NAME_None));
393 break;
394
396 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnDepthCamera(SpawnTransform, false, SensorIdentifier, SensorName, ParseDepthCameraParameters(ParametersObject), true, TempActor, nullptr, NAME_None));
397 break;
398
400 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnSegmentationCamera(SpawnTransform, false, SensorIdentifier, SensorName, ParseParameters<FCameraBaseParameters>(ParametersObject), true, TempActor, nullptr, NAME_None));
401 break;
402
404 ActorPtr = Cast<AActor>(WorldSensorManager->SpawnDVSCamera(SpawnTransform, false, SensorIdentifier, SensorName, ParseDVSCameraParameters(ParametersObject), true, TempActor, nullptr, NAME_None));
405 break;
406
407 default:
408 break;
409 }
410
411 bool AttachToSpectator = false;
412 SensorObject->TryGetBoolField("attachToSpectator", AttachToSpectator);
413
414 if (AttachToSpectator)
415 {
417 }
418 else
419 {
420 TeleportSpectatorOrFollowActorIfField(SensorObject, ActorPtr, SpawnTransform);
421 }
422}
423
424void USimulatorJsonParser::SpawnWalker(const TSharedPtr<FJsonObject>& JsonObject)
425{
426 if (!JsonObject.IsValid())
427 {
428 SimulatorLog::Log("SimulatorJsonParser failed to parse Walker json: Invalid JsonObject");
429 return;
430 }
431
432 FString WalkerTypeString;
433 if (!JsonObject->TryGetStringField("model", WalkerTypeString))
434 {
435 SimulatorLog::Log("SimulatorJsonParser failed to parse Walker json: Model field is missing");
436 return;
437 }
438
439 EWalkerType WalkerType = UEnumUtilities::ConvertStringToWalkerType(WalkerTypeString);
440 if (WalkerType == EWalkerType::NONE)
441 {
442 SimulatorLog::Log("SimulatorJsonParser failed to parse Walker json: Walker is None");
443 return;
444 }
445
446 TSharedPtr<FJsonObject> ParametersObject = JsonObject->GetObjectField("parameters");
447 if (!ParametersObject.IsValid())
448 {
449 SimulatorLog::Log("SimulatorJsonParser failed to parse Walker json: ParametersObject is invalid or missing");
450 return;
451 }
452
453 FString WalkerActionString;
454 if (!ParametersObject->TryGetStringField("walkerAction", WalkerActionString))
455 {
456 SimulatorLog::Log("SimulatorJsonParser failed to parse Walker json: walkerAction field is missing");
457 return;
458 }
459
460 EWalkerAction WalkerAction = UEnumUtilities::ConvertStringToWalkerActionType(WalkerActionString);
461 if (WalkerAction == EWalkerAction::Roaming && !ParametersObject->HasField("spawnPoint"))
462 {
463 SimulatorLog::Log("SimulatorJsonParser failed to parse Walker json: Roaming Walker requires spawnPoint");
464 return;
465 }
466
467 // Retrieve the WalkerEndAction
468 FString WalkerEndActionString;
469 ParametersObject->TryGetStringField("walkerEndAction", WalkerEndActionString);
470 EWalkerEndAction WalkerEndAction = UEnumUtilities::ConvertStringToWalkerEndActionType(WalkerEndActionString);
471
472 // Create and populate WalkerParameters
473 FWalkerParameters WalkerParams;
474 WalkerParams.WalkerType = WalkerType;
475 WalkerParams.WalkerAction = WalkerAction;
476 WalkerParams.WalkerEndAction = WalkerEndAction;
477 WalkerParams.WalkerSpeed = GetIntValueOrDefault(ParametersObject, "walkerSpeed", 50);
478
479 // Parse points or spawnPoint into WalkerParams.Points
480 ParseWalkerSpawnPoints(ParametersObject, WalkerParams);
481
482 // Retrieve optional name and id fields
483 FString Name, ID;
484 ParametersObject->TryGetStringField("name", Name);
485 ParametersObject->TryGetStringField("id", ID);
486
487 // Retrieve the startAutomatically field
488 bool StartAutomatically = true;
489 if (ParametersObject->HasField("startAutomatically"))
490 {
491 ParametersObject->TryGetBoolField("startAutomatically", StartAutomatically);
492 }
493
494 // Finally spawn the Walker
495 AWalker* Walker = UAssetLibrary::SpawnWalker(WalkerParams, Name, ID, StartAutomatically);
496 if (Walker)
497 {
498 TeleportSpectatorOrFollowActorIfField(JsonObject, Cast<AActor>(Walker), WalkerParams.Points[0]);
499 }
500}
501
502void USimulatorJsonParser::ParseWalkerSpawnPoints(const TSharedPtr<FJsonObject>& ParametersObject, FWalkerParameters& WalkerParams)
503{
504 if (ParametersObject->HasField("points"))
505 {
506 // If the JSON has "points" field, parse those points into WalkerParams.Points
507 TSharedPtr<FJsonObject> PointsObject = ParametersObject->GetObjectField("points");
508 if (PointsObject.IsValid())
509 {
510 int PointIndex = 0;
511 while (true)
512 {
513 FString PointName = FString::Printf(TEXT("point%d"), PointIndex);
514 if (!PointsObject->HasField(PointName))
515 {
516 break;
517 }
518
519 TSharedPtr<FJsonObject> PointObject = PointsObject->GetObjectField(PointName);
520 if (PointObject.IsValid())
521 {
522 FTransform PointTransform = ParseTransform(PointName, PointsObject);
523 WalkerParams.Points.Add(PointTransform);
524 }
525
526 PointIndex++;
527 }
528 }
529 }
530 else if (ParametersObject->HasField("spawnPoint"))
531 {
532 // If the JSON doesn't have "points" field but has "spawnPoint", parse that into WalkerParams.Points
533 FTransform PointTransform = ParseTransform("spawnPoint", ParametersObject);
534 WalkerParams.Points.Add(PointTransform);
535 }
536}
537
538void USimulatorJsonParser::ChangeWeather(const TSharedPtr<FJsonObject>& JsonObject)
539{
540 if (!JsonObject.IsValid())
541 {
542 return;
543 }
544
545 TSharedPtr<FJsonObject> Parameters = JsonObject->GetObjectField("parameters");
546 if (Parameters.IsValid() && GEngine && GEngine->GameViewport)
547 {
548 UWorld* World = GEngine->GameViewport->GetWorld();
549 AWeather* WeatherActor = UAgrarsenseStatics::GetWeatherActor(World);
550 if (WeatherActor)
551 {
552 FWeatherParameters Params = WeatherActor->GetCurrentWeather();
553 FJsonObjectConverter::JsonObjectToUStruct(Parameters.ToSharedRef(), FWeatherParameters::StaticStruct(), &Params);
554 WeatherActor->UpdateWeather(Params, true);
555 }
556 }
557}
558
559void USimulatorJsonParser::ParseAndSetDroneParameters(APIDDrone* DronePtr, const TSharedPtr<FJsonObject>& JsonObject)
560{
561 if (!DronePtr || !JsonObject.IsValid())
562 {
563 return;
564 }
565
566 TSharedPtr<FJsonObject> ParametersObject = JsonObject->GetObjectField("parameters");
567
568 if (ParametersObject.IsValid())
569 {
570 FDroneParameters DroneParameters;
571 FJsonObjectConverter::JsonObjectToUStruct(ParametersObject.ToSharedRef(), FDroneParameters::StaticStruct(), &DroneParameters);
572
573 TSharedPtr<FJsonObject> PointsObject = ParametersObject->GetObjectField("points");
574 if (PointsObject.IsValid())
575 {
576 int PointIndex = 0;
577 while (true)
578 {
579 FString PointName = FString::Printf(TEXT("point%d"), PointIndex);
580 if (!PointsObject->HasField(PointName))
581 {
582 break;
583 }
584
585 TSharedPtr<FJsonObject> PointObject = PointsObject->GetObjectField(PointName);
586 if (PointObject.IsValid())
587 {
588 FTransform PointTransform = ParseTransform(PointName, PointObject);
589 DroneParameters.Points.Add(PointTransform);
590 }
591
592 PointIndex++;
593 }
594 }
595
596 DronePtr->ChangeDroneParameters(DroneParameters);
597 }
598}
599
600void USimulatorJsonParser::TeleportSpectatorOrFollowActorIfField(const TSharedPtr<FJsonObject>& JsonObject, AActor* Actor, const FTransform& Transform)
601{
602 if (!JsonObject.IsValid() || !Actor)
603 {
604 return;
605 }
606
607 bool follow = false;
608 bool teleport = false;
609 JsonObject->TryGetBoolField("followObject", follow);
610 JsonObject->TryGetBoolField("teleportSpectator", teleport);
611
612 if (!follow && !teleport)
613 {
614 // If neither is set, return
615 return;
616 }
617
618 if (GEngine && GEngine->GameViewport)
619 {
620 UWorld* World = GEngine->GameViewport->GetWorld();
622 if (Spectator)
623 {
624 if (follow)
625 {
626 AVehicle* VehiclePtr = Cast<AVehicle>(Actor);
627 if (VehiclePtr)
628 {
630 if (SimulationLevelManager)
631 {
632 SimulationLevelManager->TakeManualControlOfVehicle(VehiclePtr);
633 }
634 }
635 /*else
636 {
637 Spectator->FollowActor(Actor, false, 150.0f, 50.0f);
638 }*/
639 }
640 else if (teleport)
641 {
642 Spectator->TeleportSpectator(Transform);
643 }
644 }
645 }
646}
647
649{
650 if (!ActorPtr || !GEngine || !GEngine->GameViewport)
651 {
652 return;
653 }
654
655 UWorld* World = GEngine->GameViewport->GetWorld();
656 if (!World)
657 {
658 return;
659 }
660
662 APlayerController* PlayerController = UGameplayStatics::GetPlayerController(World, 0);
663 if (PlayerController && Spectator)
664 {
665 APlayerCameraManager* CameraManager = PlayerController->PlayerCameraManager;
666 if (CameraManager)
667 {
668 USceneComponent* CameraRootComponent = CameraManager->GetRootComponent();
669 if (CameraRootComponent)
670 {
671 // Set initial location and rotation to Spectator location
672 ActorPtr->SetActorLocation(Spectator->GetActorLocation());
673 ActorPtr->SetActorRotation(Spectator->GetActorRotation());
674
675 // Now attach ActorPtr to PlayerCameraManager CameraRootComponent so it follows the camera movement
676 ActorPtr->AttachToComponent(CameraRootComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
677
678 // Delete sensor model from the sensor after attaching to Spectator.
679 ASensor* SensorPtr = Cast<ASensor>(ActorPtr);
680 if (SensorPtr)
681 {
682 auto* SensorModelPtr = SensorPtr->GetSensorModel();
683 if (SensorModelPtr)
684 {
685 SensorModelPtr->Destroy();
686 }
687 }
688 }
689 }
690 }
691}
692
693void USimulatorJsonParser::ParseAndSetSemanticColors(const TSharedPtr<FJsonObject>& JsonObject)
694{
695 UWorld* World = nullptr;
696 if (GEngine && GEngine->GameViewport)
697 {
698 World = GEngine->GameViewport->GetWorld();
699 }
700
701 if (!World)
702 {
703 return;
704 }
705
706 UMaterialParameterCollectionInstance* CollectionInstance = UMaterialParameterCollectionUtilities::LoadMaterialParameterCollectionInstance(World, "/Game/Agrarsense/Data/Semantic/MPC_SemanticCameraColors");
707 if (!CollectionInstance)
708 {
709 SimulatorLog::Log("ROSJsonParser.cpp: Failed to load MaterialParameterCollectionInstance!");
710 return;
711 }
712
713 // Access the "colors" object
714 const TSharedPtr<FJsonObject>* ColorsObjectPtr = nullptr;
715 if (JsonObject->TryGetObjectField(TEXT("colors"), ColorsObjectPtr) && ColorsObjectPtr != nullptr)
716 {
717 const TSharedPtr<FJsonObject>& ColorsObject = *ColorsObjectPtr;
718 for (const auto& Elem : ColorsObject->Values)
719 {
720 FName Type = FName(*Elem.Key);
721 FString VectorString = Elem.Value->AsString();
722
723 // Parse the FVector4 value from the string
724 FVector4 ParsedVector;
725 TArray<FString> ParsedValues;
726 VectorString.ParseIntoArray(ParsedValues, TEXT(","), true);
727 if (ParsedValues.Num() == 4)
728 {
729 ParsedVector.X = FCString::Atof(*ParsedValues[0]);
730 ParsedVector.Y = FCString::Atof(*ParsedValues[1]);
731 ParsedVector.Z = FCString::Atof(*ParsedValues[2]);
732 ParsedVector.W = FCString::Atof(*ParsedValues[3]);
733
734 // try to update the material collection vector value
735 bool success = UMaterialParameterCollectionUtilities::UpdateMaterialCollectionVectorValue(CollectionInstance, Type, ParsedVector);
736 }
737 }
738 }
739}
740
741void USimulatorJsonParser::ParseCommands(const TSharedPtr<FJsonObject>& JsonObject)
742{
743 // Parse json that contains "commands" array of Unreal console commands to execute
744
745 if (!GEngine || !GEngine->GameViewport)
746 {
747 return;
748 }
749
750 UWorld* World = GEngine->GameViewport->GetWorld();
751 if (World)
752 {
753 const TArray<TSharedPtr<FJsonValue>>* CommandsArray;
754 if (JsonObject->TryGetArrayField(TEXT("commands"), CommandsArray))
755 {
756 for (const TSharedPtr<FJsonValue>& CommandValue : *CommandsArray)
757 {
758 FString Command;
759 if (CommandValue->TryGetString(Command))
760 {
761 GEngine->Exec(World, *Command);
762 }
763 }
764 }
765 }
766}
767
768void USimulatorJsonParser::ParseVolumeDeletion(const TSharedPtr<FJsonObject>& JsonObject)
769{
770 if (!GEngine || !GEngine->GameViewport || !JsonObject.IsValid())
771 {
772 return;
773 }
774
775 // Parse spawn location for this volume
776 FTransform SpawnTransform = ParseTransform("spawnPoint", JsonObject);
777
778 // We can use ParseTransform function to parse bounds as the json structure is similar.
779 FTransform TransformBounds = ParseTransform("bounds", JsonObject);
780 FVector Bounds = TransformBounds.GetLocation();
781
782 bool OnlyDestroyTrees = true; // default to only destroy trees
783 JsonObject->TryGetBoolField(TEXT("onlyDestroyTrees"), OnlyDestroyTrees);
784
785 UWorld* World = GEngine->GameViewport->GetWorld();
786
787 if (World)
788 {
789 ADeletionVolume* Volume = World->SpawnActor<ADeletionVolume>(ADeletionVolume::StaticClass(), SpawnTransform);
790 if (Volume)
791 {
792 // Change volume bounds
793 Volume->ChangeOverlapBounds(Bounds);
794
795 // Destroy all overlapping trees, Actor gets automatically destroyed after calling this
796 Volume->DestroyOverlappingActors(OnlyDestroyTrees);
797 }
798 }
799}
800
801FTransform USimulatorJsonParser::ParseTransform(const FString& FieldName, const TSharedPtr<FJsonObject>& Object)
802{
803 FTransform SpawnTransform;
804
805 const TSharedPtr<FJsonObject>* SpawnPointObject = nullptr;
806 if (Object->TryGetObjectField(FieldName, SpawnPointObject))
807 {
808 double LocationX = 0.0, LocationY = 0.0, LocationZ = 0.0;
809 double Yaw = 0.0, Pitch = 0.0, Roll = 0.0;
810
811 auto& SPO = *SpawnPointObject->Get();
812
813 // Attempt to extract location and rotation directly
814 bool HasLocation = SPO.TryGetNumberField(TEXT("x"), LocationX) && SPO.TryGetNumberField(TEXT("y"), LocationY) && SPO.TryGetNumberField(TEXT("z"), LocationZ);
815
816 // Attempt to get rotation information
817 SPO.TryGetNumberField(TEXT("yaw"), Yaw);
818 SPO.TryGetNumberField(TEXT("pitch"), Pitch);
819 SPO.TryGetNumberField(TEXT("roll"), Roll);
820
821 // Attempt to get scale information
822 FVector Scale;
823 bool ChangeScale = false;
824 if (SPO.HasField("scaleX") && SPO.HasField("scaleY") && SPO.HasField("scaleZ"))
825 {
826 ChangeScale = true;
827 SPO.TryGetNumberField(TEXT("scaleX"), Scale.X);
828 SPO.TryGetNumberField(TEXT("scaleY"), Scale.Y);
829 SPO.TryGetNumberField(TEXT("scaleZ"), Scale.Z);
830 }
831
832 if (HasLocation)
833 {
834 FVector Location(LocationX, LocationY, LocationZ);
835 FRotator Rotation(Pitch, Yaw, Roll);
836
837 SpawnTransform.SetLocation(Location);
838 SpawnTransform.SetRotation(Rotation.Quaternion());
839
840 if (ChangeScale)
841 {
842 SpawnTransform.SetScale3D(Scale);
843 }
844 }
845 }
846
847 return SpawnTransform;
848}
849
850FVector4 USimulatorJsonParser::ParseVector4(const FString& FieldName, const TSharedPtr<FJsonObject>& Object)
851{
852 FVector4 Vector;
853 const TSharedPtr<FJsonObject>* VectorObject;
854
855 if (Object->TryGetObjectField(FieldName, VectorObject))
856 {
857 double X, Y, Z, W;
858 (*VectorObject)->TryGetNumberField(TEXT("x"), X);
859 (*VectorObject)->TryGetNumberField(TEXT("y"), Y);
860 (*VectorObject)->TryGetNumberField(TEXT("z"), Z);
861 (*VectorObject)->TryGetNumberField(TEXT("w"), W);
862 Vector = FVector4(X, Y, Z, W);
863 }
864
865 return Vector;
866}
867
868FDepthCameraParameters USimulatorJsonParser::ParseDepthCameraParameters(const TSharedPtr<FJsonObject>& ParametersObject)
869{
870 FDepthCameraParameters DepthCameraParams;
871
872 if (ParametersObject.IsValid())
873 {
874 FJsonObjectConverter::JsonObjectToUStruct(ParametersObject.ToSharedRef(), FDepthCameraParameters::StaticStruct(), &DepthCameraParams);
875 }
876
877 return DepthCameraParams;
878}
879
881{
882 FThermalCameraParameters ThermalCameraParams;
883
884 if (ParametersObject.IsValid())
885 {
886 // Parse fields manually because FJsonObjectConverter::JsonObjectToUStruct couldn't parse these properly.
887 ThermalCameraParams.WarmColor = ParseVector4(TEXT("warmColor"), ParametersObject);
888 ThermalCameraParams.ColdColor = ParseVector4(TEXT("coldColor"), ParametersObject);
889 ParametersObject->TryGetBoolField(TEXT("allowCustomNoiseResolution"), ThermalCameraParams.AllowCustomNoiseResolution);
890 ParametersObject->TryGetNumberField(TEXT("widthResolutionNoise"), ThermalCameraParams.WidthResolutionNoise);
891 ParametersObject->TryGetNumberField(TEXT("heightResolutionNoise"), ThermalCameraParams.HeightResolutionNoise);
892
893 // Parse FCameraBaseParameters
894 TSharedPtr<FJsonObject> CameraParametersObject = ParametersObject->GetObjectField("cameraParameters");
895 if (CameraParametersObject.IsValid())
896 {
897 ThermalCameraParams.CameraParameters = ParseParameters<FCameraBaseParameters>(CameraParametersObject);
898 }
899 }
900
901 return ThermalCameraParams;
902}
903
904FDVSCameraParameters USimulatorJsonParser::ParseDVSCameraParameters(const TSharedPtr<FJsonObject>& ParametersObject)
905{
906 FDVSCameraParameters DVSCameraParams;
907
908 if (ParametersObject.IsValid())
909 {
910 FJsonObjectConverter::JsonObjectToUStruct(ParametersObject.ToSharedRef(), FDVSCameraParameters::StaticStruct(), &DVSCameraParams);
911 }
912
913 return DVSCameraParams;
914}
915
916int USimulatorJsonParser::GetIntValueOrDefault(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName, int Default)
917{
918 int Value = Default;
919
920 if (JsonObject.IsValid() && JsonObject->HasField(FieldName))
921 {
922 JsonObject->TryGetNumberField(FieldName, Value);
923 }
924
925 return Value;
926}
EFoliageTypes
Definition: FoliageTypes.h:15
EPropTypes
Definition: PropTypes.h:15
ESensorTypes
Definition: SensorTypes.h:15
@ SemanticSegmentationCamera
EVehicleTypes
Definition: VehicleTypes.h:15
EWalkerAction
Definition: WalkerAction.h:15
EWalkerEndAction
EWalkerType
Definition: WalkerType.h:16
void DestroyOverlappingActors(bool OnlyTrees)
void ChangeOverlapBounds(FVector Bounds)
void ChangeDroneParameters(const FDroneParameters &newParameters)
Definition: PIDDrone.h:71
Definition: Sensor.h:44
ASensorModel * GetSensorModel() const
Definition: Sensor.h:172
bool TakeManualControlOfVehicle(AVehicle *Vehicle)
USensorsManagerComponent * GetSensorsManager() const
void TeleportSpectator(const FTransform &Transform)
Definition: Spectator.cpp:48
Definition: Walker.h:28
void UpdateWeather(const FWeatherParameters &WeatherParameters, bool updateToROS)
Definition: Weather.cpp:97
const FWeatherParameters & GetCurrentWeather() const
Definition: Weather.h:76
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static bool IsPlayingInMainMenu()
static ASpectator * GetSpectator(const UObject *WorldContextObject)
static AWeather * GetWeatherActor(const UObject *WorldContextObject)
static ASimulationLevelManager * GetSimulationLevelManager(const UObject *WorldContextObject)
static AVehicle * SpawnVehicle(EVehicleTypes VehicleType, FTransform SpawnTransform, const FString &ActorName, const FString &ActorID, bool SnapAboveGround=false, float AboveOffset=150.0f, bool DestroyOverlappingActors=false)
static AActor * SpawnProp(EPropTypes PropType, FTransform Transform, FString ActorName="", FString ActorID="", bool RandomZRotation=false, bool SnapToGround=false)
static AWalker * SpawnWalker(FWalkerParameters Parameters, const FString &ActorName="", const FString &ActorID="", bool StartAutomatically=true)
static AActor * SpawnFoliage(EFoliageTypes FoliageType, FTransform Transform, FString ActorName="", FString ActorID="", bool RandomZRotation=true, bool SnapToGround=true)
static EWalkerEndAction ConvertStringToWalkerEndActionType(const FString &String)
static ESensorTypes ConvertStringToSensorType(const FString &String)
static EWalkerAction ConvertStringToWalkerActionType(const FString &String)
static EVehicleTypes ConvertStringToVehicleType(const FString &String)
static EWalkerType ConvertStringToWalkerType(const FString &String)
static EPropTypes ConvertStringToPropType(const FString &String)
static EFoliageTypes ConvertStringToFoliageType(const FString &String)
static bool UpdateMaterialCollectionVectorValue(UMaterialParameterCollectionInstance *MPCInstance, const FName ParameterName, const FVector4 Value)
static UMaterialParameterCollectionInstance * LoadMaterialParameterCollectionInstance(const UObject *WorldContextObject, const FString &Path)
static void TeleportSpectatorOrFollowActorIfField(const TSharedPtr< FJsonObject > &JsonObject, AActor *Actor, const FTransform &Transform)
static FTransform ParseTransform(const FString &FieldName, const TSharedPtr< FJsonObject > &Object)
static int GetIntValueOrDefault(const TSharedPtr< FJsonObject > &JsonObject, const FString &FieldName, int Default)
static FVector4 ParseVector4(const FString &FieldName, const TSharedPtr< FJsonObject > &Object)
static FDVSCameraParameters ParseDVSCameraParameters(const TSharedPtr< FJsonObject > &ParametersObject)
static void ParseAndSetDroneParameters(APIDDrone *DronePtr, const TSharedPtr< FJsonObject > &JsonObject)
static void ParseAndOperateJSONFile(const FString &Path)
static FThermalCameraParameters ParseThermalCameraParameters(const TSharedPtr< FJsonObject > &ParametersObject)
static void AttachActorToSpectatorCamera(AActor *ActorPtr)
static void ParsePropOrFoliage(const TSharedPtr< FJsonObject > &JsonObject, const FString &ObjectType)
static void ParseVehicle(const TSharedPtr< FJsonObject > &JsonObject)
static void ParseVolumeDeletion(const TSharedPtr< FJsonObject > &JsonObject)
static void ParseWalkerSpawnPoints(const TSharedPtr< FJsonObject > &ParametersObject, FWalkerParameters &WalkerParams)
static void ParseCommands(const TSharedPtr< FJsonObject > &JsonObject)
static FDepthCameraParameters ParseDepthCameraParameters(const TSharedPtr< FJsonObject > &ParametersObject)
static void ParseAndSetSemanticColors(const TSharedPtr< FJsonObject > &JsonObject)
static void ChangeWeather(const TSharedPtr< FJsonObject > &JsonObject)
static void SpawnWalker(const TSharedPtr< FJsonObject > &JsonObject)
static void SpawnSensorWorld(const TSharedPtr< FJsonObject > &SensorObject)
static void SpawnSensorToVehicle(AVehicle *Vehicle, const TSharedPtr< FJsonObject > &SensorObject)
TArray< FTransform > Points
FCameraBaseParameters CameraParameters
EWalkerAction WalkerAction
TArray< FTransform > Points
EWalkerType WalkerType
EWalkerEndAction WalkerEndAction