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