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