Agrarsense
AssetLibrary.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
6#include "AssetLibrary.h"
7
17
21
22#include "Kismet/KismetSystemLibrary.h"
23#include "Engine/GameViewportClient.h"
24#include "GameFramework/Actor.h"
25#include "Engine/Engine.h"
26#include "UObject/Class.h"
27#include "Engine/World.h"
28
29// Paths to data assets
30static const FString VEHICLE_ASSET_PATH = "/Game/Agrarsense/Data/Vehicles/VehicleActorAssetMap";
31static const FString FOLIAGE_ASSET_PATH = "/Game/Agrarsense/Data/Foliage/FoliageActorAssetMap";
32static const FString WALKER_ASSET_PATH = "/Game/Agrarsense/Data/Walkers/WalkerActorAssetMap";
33static const FString PROP_ASSET_PATH = "/Game/Agrarsense/Data/Props/PropActorAssetMap";
34
35TWeakObjectPtr<UFoliageActorAssetMapDataAsset> UAssetLibrary::FoliageActorAssetMapDataAsset;
36TArray<FInstancedActorData> UAssetLibrary::AddedFoliageActors;
37TMap<EFoliageTypes, FString> UAssetLibrary::FoliageTypeMap;
38TArray<EFoliageTypes> UAssetLibrary::FoliageKeys;
39
40TWeakObjectPtr <UVehicleActorAssetMapDataAsset> UAssetLibrary::VehicleDataAsset;
41TArray<FVehicleData> UAssetLibrary::SpawnedVehicles;
42
43TWeakObjectPtr<UPropActorAssetMapDataAsset> UAssetLibrary::PropActorAssetMapDataAsset;
44TArray<FInstancedActorData> UAssetLibrary::SpawnedPropActors;
45TMap<EPropTypes, FString> UAssetLibrary::PropTypeMap;
46TArray<EPropTypes> UAssetLibrary::PropKeys;
47
48TWeakObjectPtr<UWalkerActorAssetMapDataAsset> UAssetLibrary::WalkerActorAssetMapDataAsset;
49TArray<TWeakObjectPtr<AWalker>> UAssetLibrary::SpawnedWalkers;
50
51AActor* UAssetLibrary::SpawnFoliage(EFoliageTypes FoliageType, FTransform Transform,
52 FString ActorName, FString ActorID,
53 bool RandomZRotation, bool SnapToGround)
54{
56
57 if (!FoliageActorAssetMapDataAsset.IsValid())
58 {
59 return nullptr;
60 }
61
62 UFoliageActorAssetDataAsset* ActorAssetData = FoliageActorAssetMapDataAsset->Foliages.FindRef(FoliageType);
63 TSubclassOf<AActor> ActorClass = ActorAssetData ? ActorAssetData->ActorAsset.Actor : nullptr;
64
65 AActor* SpawnedActor = TrySpawnActor(ActorClass, Transform, ActorName, ActorID, SnapToGround, RandomZRotation);
66
67 AInstancedActor* InstancedActor = Cast<AInstancedActor>(SpawnedActor);
68 if (InstancedActor)
69 {
70 if (FoliageTypeMap.Contains(FoliageType))
71 {
72 // Set InstactedActor type and model strings, this is used for JSON exporting.
73 FString Model = FoliageTypeMap[FoliageType];
74 InstancedActor->SetTypeAndModel("foliage", Model);
75 }
76
77 // Add to array
79 Data.Actor = InstancedActor;
80 AddedFoliageActors.Add(Data);
81 }
82
83 return SpawnedActor;
84}
85
87 FTransform SpawnTransform, const FString& ActorName,
88 const FString& ActorID, bool SnapAboveGround,
89 const float AboveOffset, const bool DestroyOverlappingActors)
90{
92
93 if (!VehicleDataAsset.IsValid())
94 {
95 return nullptr;
96 }
97
98 UVehicleActorAssetDataAsset* ActorAssetData = VehicleDataAsset->Vehicles.FindRef(VehicleType);
99 TSubclassOf<AActor> ActorClass = ActorAssetData ? ActorAssetData->ActorAsset.Actor : nullptr;
100
101 ESpawnActorCollisionHandlingMethod SpawnCollisionHandling = ESpawnActorCollisionHandlingMethod::Undefined;
102 if (VehicleType == EVehicleTypes::Drone)
103 {
104 // Workaround for drone
105 SpawnCollisionHandling = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
106 }
107
108 FString ID = ActorID;
109 if (ID.IsEmpty())
110 {
112 }
113
114 AActor* SpawnedActor = TrySpawnActor(ActorClass, SpawnTransform, ActorName, ID, false, false, SpawnCollisionHandling);
115
116 AVehicle* Vehicle = Cast<AVehicle>(SpawnedActor);
117 if (SpawnedActor && Vehicle)
118 {
119 if (SnapAboveGround)
120 {
122 SpawnTransform = SpawnedActor->GetTransform();
123 }
124
125 FVehicleData VehicleData;
126 VehicleData.Vehicle = Vehicle;
127 VehicleData.VehicleType = VehicleType;
128 SpawnedVehicles.Add(VehicleData);
129
130 Vehicle->TeleportTo(SpawnTransform.GetLocation(), SpawnTransform.GetRotation().Rotator());
131
132 if (DestroyOverlappingActors)
133 {
135 }
136
137 // Add to array
138 FVehicleData Data;
139 Data.Vehicle = Vehicle;
140 Data.VehicleType = Vehicle->GetVehicleType();
141 SpawnedVehicles.Add(Data);
142 }
143
144 return Vehicle;
145}
146
147AActor* UAssetLibrary::SpawnProp(EPropTypes PropType, FTransform Transform,
148 FString ActorName, FString ActorID,
149 bool RandomZRotation, bool SnapToGround)
150{
152
153 if (!PropActorAssetMapDataAsset.IsValid())
154 {
155 return nullptr;
156 }
157
158 UPropActorAssetDataAsset* ActorAssetData = PropActorAssetMapDataAsset->Props.FindRef(PropType);
159 TSubclassOf<AActor> ActorClass = ActorAssetData ? ActorAssetData->ActorAsset.Actor : nullptr;
160
161 AActor* SpawnedActor = TrySpawnActor(ActorClass, Transform, ActorName, ActorID, SnapToGround, RandomZRotation);
162
163 AInstancedActor* InstancedActor = Cast<AInstancedActor>(SpawnedActor);
164 if (InstancedActor)
165 {
166 FInstancedActorData InstancedActorData;
167 InstancedActorData.Actor = InstancedActor;
168 SpawnedPropActors.Add(InstancedActorData);
169
170 if (PropTypeMap.Contains(PropType))
171 {
172 // Set InstactedActor type and model strings, this is used for JSON exporting.
173 FString Model = PropTypeMap[PropType];
174 InstancedActor->SetTypeAndModel("prop", Model);
175 }
176
177
178 // Add to array
180 Data.Actor = InstancedActor;
181 SpawnedPropActors.Add(Data);
182 }
183
184 return SpawnedActor;
185}
186
187AWalker* UAssetLibrary::SpawnWalker(FWalkerParameters Parameters, const FString& ActorName,
188 const FString& ActorID, bool StartAutomatically)
189{
191
192 if (!WalkerActorAssetMapDataAsset.IsValid())
193 {
194 return nullptr;
195 }
196
197 UWalkerActorAssetDataAsset* ActorAssetData = WalkerActorAssetMapDataAsset->Walkers.FindRef(Parameters.WalkerType);
198 TSubclassOf<AActor> ActorClass = ActorAssetData ? ActorAssetData->ActorAsset.Actor : nullptr;
199
200 FTransform StartTransform;
201 auto& Transforms = Parameters.Points;
202
203 if (!Transforms.IsEmpty())
204 {
205 if (Parameters.WalkerAction == EWalkerAction::FollowPath && Transforms.Num() < 2)
206 {
207 SimulatorLog::Log("Failed to spawn FollowPath Walker due to insufficient path points.");
208 return nullptr;
209 }
210 StartTransform = Transforms[0];
211 }
212
213 FString ID = ActorID;
214 if (ID.IsEmpty())
215 {
217 }
218
219 AActor* SpawnedActor = TrySpawnActor(ActorClass, StartTransform, ActorName, ID, false, false);
220
221 AWalker* Walker = Cast<AWalker>(SpawnedActor);
222 if (Walker)
223 {
225 Walker->SetWalkerParameters(Parameters);
226 Walker->SetIgnoreInput(!StartAutomatically);
227
228 // Add to array
230 }
231
232 return Walker;
233}
234
235AActor* UAssetLibrary::TrySpawnActor(TSubclassOf<AActor> ActorClass, FTransform& Transform,
236 FString ActorName, FString ActorID,
237 bool SnapToGround, bool RandomZRotation, ESpawnActorCollisionHandlingMethod CollisionMethod)
238{
239 if (!IsInGameThread())
240 {
241#if WITH_EDITOR
242 UE_LOG(LogTemp, Warning, TEXT("AssetLibrary.cpp: Attempting to spawn actor from a background thread. This is not allowed."));
243#endif
244 return nullptr;
245 }
246
247 if (!ActorClass)
248 {
249#if WITH_EDITOR
250 UE_LOG(LogTemp, Warning, TEXT("AssetLibrary.cpp: ActorClass is nullptr! Cannot spawn actor."));
251#endif
252 return nullptr;
253 }
254
255 UWorld* World = nullptr;
256 if (GEngine && GEngine->GameViewport)
257 {
258 World = GEngine->GameViewport->GetWorld();
259 }
260
261 if (!World)
262 {
263 return nullptr;
264 }
265
266 // Spawn actor deferred
267 AActor* SpawnedActor = World->SpawnActorDeferred<AActor>(ActorClass, Transform, nullptr, nullptr, CollisionMethod);
268
269 if (SpawnedActor)
270 {
271 if (SnapToGround)
272 {
274 Transform = SpawnedActor->GetTransform();
275 }
276
277 if (RandomZRotation)
278 {
279 float RotationAngle = FMath::FRandRange(0.0f, 360.0f);
280 Transform.SetRotation(FQuat::MakeFromEuler(FVector(0.0f, 0.0f, RotationAngle)));
281 }
282
283 // Set ID and name through IActorInformation if the spawned actor implements it
284 if (SpawnedActor && SpawnedActor->GetClass()->ImplementsInterface(UActorInformation::StaticClass()))
285 {
286 IActorInformation::Execute_SetActorIDAndName(SpawnedActor, ActorName, ActorID);
287 }
288
289 // Finish Actor spawning (BeginPlay runs now)
290 SpawnedActor->FinishSpawning(Transform);
291 }
292
293 return SpawnedActor;
294}
295
297{
298 UWorld* World = nullptr;
299 if (GEngine && GEngine->GameViewport)
300 {
301 World = GEngine->GameViewport->GetWorld();
302 }
303
304 if (!World || !SpawnedActor)
305 {
306 return;
307 }
308
309 FVector Origin;
310 FVector BoxExtent;
311 SpawnedActor->GetActorBounds(true, Origin, BoxExtent);
312
313 float SphereRadius = BoxExtent.GetMax();
314
315 TArray<AActor*> OverlappingActors;
316 UKismetSystemLibrary::SphereOverlapActors(World, SpawnedActor->GetTransform().GetLocation(), SphereRadius, {}, nullptr, {}, OverlappingActors);
317
318 for (AActor* OverlappingActor : OverlappingActors)
319 {
320 if (OverlappingActor && OverlappingActor != SpawnedActor)
321 {
322 if (OverlappingActor->IsA(AWalker::StaticClass()) ||
323 OverlappingActor->IsA(AInstancedActor::StaticClass()) ||
324 OverlappingActor->IsA(AVehicle::StaticClass()))
325 {
326 OverlappingActor->Destroy();
327 }
328 }
329 }
330}
331
333{
334 SpawnedVehicles.RemoveAll([](const FVehicleData& VehicleData)
335 {
336 return !VehicleData.Vehicle.IsValid();
337 });
338
339 return SpawnedVehicles;
340}
341
343{
345
347}
348
350{
352
353 EFoliageTypes RandomFoliageType = EFoliageTypes::NONE;
354 if (FoliageKeys.Num())
355 {
356 int32 RandomIndex = FMath::RandRange(0, FoliageKeys.Num() - 1);
357 RandomFoliageType = FoliageKeys[RandomIndex];
358 }
359
360 return RandomFoliageType;
361}
362
364{
365 AddedFoliageActors.RemoveAll([](const FInstancedActorData& ActorData)
366 {
367 return !ActorData.Actor.IsValid();
368 });
369
370 TArray<AInstancedActor*> ValidActors;
371 ValidActors.Reserve(AddedFoliageActors.Num());
372
373 for (const FInstancedActorData& ActorData : AddedFoliageActors)
374 {
375 if (ActorData.Actor.IsValid())
376 {
377 ValidActors.Add(ActorData.Actor.Get());
378 }
379 }
380
381 return ValidActors;
382}
383
385{
387
388 return PropActorAssetMapDataAsset.Get();
389}
390
392{
394
395 EPropTypes RandomPropType = EPropTypes::NONE;
396 if (PropKeys.Num())
397 {
398 int32 RandomIndex = FMath::RandRange(0, PropKeys.Num() - 1);
399 RandomPropType = PropKeys[RandomIndex];
400 }
401
402 return RandomPropType;
403}
404
405TArray<AInstancedActor*> UAssetLibrary::GetAllAddedPropActors()
406{
407 SpawnedPropActors.RemoveAll([](const FInstancedActorData& ActorData)
408 {
409 return !ActorData.Actor.IsValid();
410 });
411
412 TArray<AInstancedActor*> ValidActors;
413 ValidActors.Reserve(SpawnedPropActors.Num());
414
415 for (const FInstancedActorData& ActorData : SpawnedPropActors)
416 {
417 if (ActorData.Actor.IsValid())
418 {
419 ValidActors.Add(ActorData.Actor.Get());
420 }
421 }
422
423 return ValidActors;
424}
425
427{
429
430 return WalkerActorAssetMapDataAsset.Get();
431}
432
434{
435 SpawnedWalkers.RemoveAll([](const TWeakObjectPtr<AWalker>& ActorData)
436 {
437 return !ActorData.IsValid();
438 });
439
440 TArray<AWalker*> ValidWalkers;
441 ValidWalkers.Reserve(SpawnedWalkers.Num());
442
443 for (const TWeakObjectPtr<AWalker>& ActorData : SpawnedWalkers)
444 {
445 AWalker* WalkerPtr = ActorData.Get();
446 if (WalkerPtr)
447 {
448 ValidWalkers.Add(WalkerPtr);
449 }
450 }
451
452 return ValidWalkers;
453}
454
456{
457 TArray<AWalker*> WalkersActors = GetAllWalkers();
458
459 if (WalkersActors.IsEmpty())
460 {
461 return;
462 }
463
464 for (AWalker* Walker : WalkersActors)
465 {
466 if (Walker)
467 {
468 Walker->Destroy();
469 }
470 }
471
472 WalkersActors.Empty();
473
474 FString Message = FString::Printf(TEXT("Destroyed all %d Walkers."), WalkersActors.Num());
475 SimulatorLog::Log(Message);
476}
477
479{
480 if (!VehicleDataAsset.IsValid())
481 {
482 VehicleDataAsset.Reset();
483 FSoftObjectPath VehicleActorAssetMap(VEHICLE_ASSET_PATH);
484 VehicleDataAsset = Cast<UVehicleActorAssetMapDataAsset>(VehicleActorAssetMap.TryLoad());
485 }
486}
487
489{
490 if (FoliageActorAssetMapDataAsset.IsValid())
491 {
492 return;
493 }
494
496 FSoftObjectPath FoliageActorAssetMapDataAssetPath(FOLIAGE_ASSET_PATH);
497 FoliageActorAssetMapDataAsset = Cast<UFoliageActorAssetMapDataAsset>(FoliageActorAssetMapDataAssetPath.TryLoad());
498
499 if (FoliageActorAssetMapDataAsset.IsValid())
500 {
502 FoliageTypeMap.Empty();
503 FoliageTypeMap = UEnumUtilities::CreateEnumStringMap<EFoliageTypes>("/Script/Agrarsense.EFoliageTypes");
504 }
505}
506
508{
509 if (PropActorAssetMapDataAsset.IsValid())
510 {
511 return;
512 }
513
514 FSoftObjectPath PropActorAssetMapDataAssetPath(PROP_ASSET_PATH);
515 PropActorAssetMapDataAsset = Cast<UPropActorAssetMapDataAsset>(PropActorAssetMapDataAssetPath.TryLoad());
516
517 if (PropActorAssetMapDataAsset.IsValid())
518 {
519 PropActorAssetMapDataAsset->Props.GetKeys(PropKeys);
520 SpawnedPropActors.Empty();
521
522 PropTypeMap.Empty();
523 PropTypeMap = UEnumUtilities::CreateEnumStringMap<EPropTypes>("/Script/Agrarsense.EPropTypes");
524 }
525}
526
528{
529 if (!WalkerActorAssetMapDataAsset.IsValid())
530 {
531 FSoftObjectPath WalkerActorAssetMapDataAssetPath(WALKER_ASSET_PATH);
532 WalkerActorAssetMapDataAsset = Cast<UWalkerActorAssetMapDataAsset>(WalkerActorAssetMapDataAssetPath.TryLoad());
533 }
534}
static const FString PROP_ASSET_PATH
static const FString VEHICLE_ASSET_PATH
static const FString FOLIAGE_ASSET_PATH
static const FString WALKER_ASSET_PATH
EFoliageTypes
Definition: FoliageTypes.h:15
EPropTypes
Definition: PropTypes.h:15
EVehicleTypes
Definition: VehicleTypes.h:15
void SetTypeAndModel(const FString &Type, const FString &Model)
Definition: Walker.h:28
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static TWeakObjectPtr< UFoliageActorAssetMapDataAsset > FoliageActorAssetMapDataAsset
Definition: AssetLibrary.h:174
static UWalkerActorAssetMapDataAsset * GetWalkerActorAssetMapDataAsset()
static TArray< AInstancedActor * > GetAllAddedPropActors()
static void SetupWalkerDataAsset()
static TArray< FInstancedActorData > SpawnedPropActors
Definition: AssetLibrary.h:181
static TMap< EFoliageTypes, FString > FoliageTypeMap
Definition: AssetLibrary.h:175
static AVehicle * SpawnVehicle(EVehicleTypes VehicleType, FTransform SpawnTransform, const FString &ActorName, const FString &ActorID, bool SnapAboveGround=false, float AboveOffset=150.0f, bool DestroyOverlappingActors=false)
static void DestroyAllWalkers()
static TWeakObjectPtr< UVehicleActorAssetMapDataAsset > VehicleDataAsset
Definition: AssetLibrary.h:170
static void SetupVehicleDataAsset()
static EFoliageTypes GetRandomFoliageType()
static void DestroyOverlappingActorsSphere(AActor *SpawnedActor)
static TArray< FVehicleData > GetSpawnedVehicles()
static TArray< EPropTypes > PropKeys
Definition: AssetLibrary.h:183
static TArray< EFoliageTypes > FoliageKeys
Definition: AssetLibrary.h:177
static TMap< EPropTypes, FString > PropTypeMap
Definition: AssetLibrary.h:182
static TArray< AInstancedActor * > GetAllAddedFoliageActors()
static TArray< AWalker * > GetAllWalkers()
static void SetupPropDataAsset()
static TWeakObjectPtr< UPropActorAssetMapDataAsset > PropActorAssetMapDataAsset
Definition: AssetLibrary.h:180
static AActor * SpawnProp(EPropTypes PropType, FTransform Transform, FString ActorName="", FString ActorID="", bool RandomZRotation=false, bool SnapToGround=false)
static void SetupFoliageDataAsset()
static TWeakObjectPtr< UWalkerActorAssetMapDataAsset > WalkerActorAssetMapDataAsset
Definition: AssetLibrary.h:186
static AActor * TrySpawnActor(TSubclassOf< AActor > ActorClass, FTransform &Transform, FString ActorName, FString ActorID, bool SnapToGround, bool RandomZRotation, ESpawnActorCollisionHandlingMethod CollisionMethod=ESpawnActorCollisionHandlingMethod::Undefined)
static AWalker * SpawnWalker(FWalkerParameters Parameters, const FString &ActorName="", const FString &ActorID="", bool StartAutomatically=true)
static EPropTypes GetRandomPropType()
static TArray< FVehicleData > SpawnedVehicles
Definition: AssetLibrary.h:171
static TArray< TWeakObjectPtr< AWalker > > SpawnedWalkers
Definition: AssetLibrary.h:187
static UPropActorAssetMapDataAsset * GetPropActorAssetMapDataAsset()
static UFoliageActorAssetMapDataAsset * GetFoliageActorAssetMapDataAsset()
static AActor * SpawnFoliage(EFoliageTypes FoliageType, FTransform Transform, FString ActorName="", FString ActorID="", bool RandomZRotation=true, bool SnapToGround=true)
static TArray< FInstancedActorData > AddedFoliageActors
Definition: AssetLibrary.h:176
static FString ConvertVehicleTypeToString(EVehicleTypes VehicleType)
static FString ConvertWalkerTypeToString(EWalkerType WalkerType)
static bool SnapActorAboveGround(AActor *Actor, float AboveOffset=50.0f)
static bool SnapActorToGround(AActor *Actor, float StartZOffset=600.0f, float EndZOffset=600.0f)
TSubclassOf< AActor > Actor
Definition: ActorAsset.h:37
TWeakObjectPtr< AInstancedActor > Actor
EVehicleTypes VehicleType
Definition: AssetLibrary.h:46
TWeakObjectPtr< AVehicle > Vehicle
Definition: AssetLibrary.h:40
EWalkerAction WalkerAction
TArray< FTransform > Points
EWalkerType WalkerType