Refactoring Carla Actor Factories to be Programmable (#8761)
* Initial push for programmable Prop Factory This extends the design of Vehicle Factories to the Prop Factory. Final JSON generation still needs to be implemented Mesh loading needs to be implemented Planning to templatize functions at the FActorFactory class level to avoid code repetition and easier implementation of future factories * Walker, Prop and Blueprint Factories refactored to be programmable * Cleanup and visibility changes for programmable factories
This commit is contained in:
parent
0bfb05bfdd
commit
ac66720586
|
@ -1416,6 +1416,31 @@ void UActorBlueprintFunctionLibrary::MakePropDefinitions(
|
|||
FillActorDefinitionArray(ParameterArray, Definitions, &MakePropDefinition);
|
||||
}
|
||||
|
||||
void UActorBlueprintFunctionLibrary::MakeBlueprintDefinition(
|
||||
const FBlueprintParameters &Parameters,
|
||||
bool &Success,
|
||||
FActorDefinition &Definition)
|
||||
{
|
||||
FillIdAndTags(Definition, TEXT("blueprint"), Parameters.Name);
|
||||
AddRecommendedValuesForActorRoleName(Definition, {TEXT("blueprint")});
|
||||
|
||||
// Definition.Attributes.Emplace(FActorAttribute{
|
||||
// EActorAttributeType::String,
|
||||
// Parameters.ObjectType});
|
||||
|
||||
|
||||
Success = CheckActorDefinition(Definition);
|
||||
|
||||
}
|
||||
|
||||
void UActorBlueprintFunctionLibrary::MakeBlueprintDefinitions(
|
||||
const TArray<FBlueprintParameters> &ParameterArray,
|
||||
TArray<FActorDefinition> &Definitions)
|
||||
{
|
||||
FillActorDefinitionArray(ParameterArray, Definitions, &MakeBlueprintDefinition);
|
||||
}
|
||||
|
||||
|
||||
void UActorBlueprintFunctionLibrary::MakeObstacleDetectorDefinitions(
|
||||
const FString &Type,
|
||||
const FString &Id,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Carla/Actor/PedestrianParameters.h"
|
||||
#include "Carla/Actor/PropParameters.h"
|
||||
#include "Carla/Actor/VehicleParameters.h"
|
||||
#include "Carla/Actor/BlueprintParameters.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
|
@ -154,6 +155,17 @@ public:
|
|||
const TArray<FPropParameters> &ParameterArray,
|
||||
TArray<FActorDefinition> &Definitions);
|
||||
|
||||
UFUNCTION(Category = "Carla Actor", BlueprintCallable)
|
||||
static void MakeBlueprintDefinition(
|
||||
const FBlueprintParameters &Parameters,
|
||||
bool &Success,
|
||||
FActorDefinition &Definition);
|
||||
|
||||
UFUNCTION(Category = "Carla Actor", BlueprintCallable)
|
||||
static void MakeBlueprintDefinitions(
|
||||
const TArray<FBlueprintParameters> &ParameterArray,
|
||||
TArray<FActorDefinition> &Definitions);
|
||||
|
||||
UFUNCTION()
|
||||
static void MakeObstacleDetectorDefinitions(
|
||||
const FString &Type,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlueprintParameters.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct CARLA_API FBlueprintParameters
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
FString Name;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
FString Path;
|
||||
|
||||
};
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
|
||||
#include "Carla/Actor/Factory/BlueprintActorFactory.h"
|
||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||
#include "Carla/Actor/ActorDefinition.h"
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include <util/ue-header-guard-end.h>
|
||||
|
||||
TArray<FActorDefinition> ABlueprintActorFactory::GetDefinitions()
|
||||
{
|
||||
LoadBlueprintParametersArrayFromFile("BlueprintParameters.json", BlueprintsParams);
|
||||
|
||||
UActorBlueprintFunctionLibrary::MakeBlueprintDefinitions(BlueprintsParams, Definitions);
|
||||
return Definitions;
|
||||
}
|
||||
|
||||
FActorSpawnResult ABlueprintActorFactory::SpawnActor(
|
||||
const FTransform &SpawnAtTransform,
|
||||
const FActorDescription &ActorDescription)
|
||||
{
|
||||
FActorSpawnResult SpawnResult;
|
||||
if(!IsValid(ActorDescription.Class))
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Actor Description Class is null."));
|
||||
SpawnResult.Status = EActorSpawnResultStatus::InvalidDescription;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(ActorDescription.Class, SpawnAtTransform);
|
||||
SpawnResult.Actor = SpawnedActor;
|
||||
|
||||
if(SpawnedActor == nullptr)
|
||||
{
|
||||
SpawnResult.Status = EActorSpawnResultStatus::Collision;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
if(PostProcessBlueprint(SpawnedActor, ActorDescription))
|
||||
{
|
||||
SpawnResult.Status = EActorSpawnResultStatus::Success;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
SpawnResult.Status = EActorSpawnResultStatus::UnknownError;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
TSharedPtr<FJsonObject> ABlueprintActorFactory::FBlueprintParametersToJsonObject(const FBlueprintParameters& BlueprintParams)
|
||||
{
|
||||
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||
JsonObject->SetStringField(TEXT("Name"), BlueprintParams.Name);
|
||||
JsonObject->SetStringField(TEXT("Path"), BlueprintParams.Path);
|
||||
|
||||
return JsonObject;
|
||||
}
|
||||
|
||||
FString ABlueprintActorFactory::FBlueprintParametersArrayToJson(const TArray<FBlueprintParameters>& BlueprintParamsArray)
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> JsonArray;
|
||||
|
||||
for (const FBlueprintParameters& BlueprintParams : BlueprintParamsArray)
|
||||
{
|
||||
// Convert each FBlueprintParameters to a JSON object
|
||||
TSharedPtr<FJsonObject> JsonObject = FBlueprintParametersToJsonObject(BlueprintParams);
|
||||
JsonArray.Add(MakeShareable(new FJsonValueObject(JsonObject)));
|
||||
}
|
||||
|
||||
// Convert the array of JSON objects into a single JSON object
|
||||
TSharedRef<FJsonObject> RootObject = MakeShareable(new FJsonObject);
|
||||
RootObject->SetArrayField(TEXT("Blueprints"), JsonArray);
|
||||
|
||||
// Serialize the JSON object into an FString
|
||||
FString OutputString;
|
||||
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
|
||||
FJsonSerializer::Serialize(RootObject, Writer);
|
||||
|
||||
return OutputString;
|
||||
}
|
||||
|
||||
void ABlueprintActorFactory::SaveBlueprintParametersArrayToFile(const TArray<FBlueprintParameters>& BlueprintParametersArray, const FString& FileName)
|
||||
{
|
||||
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
|
||||
// Convert the array to an FString in JSON format
|
||||
FString JsonContent = FBlueprintParametersArrayToJson(BlueprintParametersArray);
|
||||
|
||||
// Save the JSON to a file
|
||||
if (FFileHelper::SaveStringToFile(JsonContent, *FilePath))
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("JSON file successfully saved at: %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to save JSON file at: %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
bool ABlueprintActorFactory::JsonToFBlueprintParameters(const TSharedPtr<FJsonObject> JsonObject, FBlueprintParameters& OutBlueprintParams)
|
||||
{
|
||||
if (!JsonObject.IsValid()) return false;
|
||||
|
||||
JsonObject->TryGetStringField(TEXT("Name"), OutBlueprintParams.Name);
|
||||
JsonObject->TryGetStringField(TEXT("Path"), OutBlueprintParams.Path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ABlueprintActorFactory::JsonToFBlueprintParametersArray(const FString& JsonString, TArray<FBlueprintParameters>& OutBlueprintParamsArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> RootObject;
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonString);
|
||||
|
||||
if (!FJsonSerializer::Deserialize(Reader, RootObject) || !RootObject.IsValid())
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to parse JSON."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the "Blueprints" array from the JSON root object
|
||||
const TArray<TSharedPtr<FJsonValue>>* BlueprintsArray;
|
||||
if (RootObject->TryGetArrayField(TEXT("Blueprints"), BlueprintsArray))
|
||||
{
|
||||
OutBlueprintParamsArray.Empty();
|
||||
for (const TSharedPtr<FJsonValue>& BlueprintValue : *BlueprintsArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> BlueprintObject = BlueprintValue->AsObject();
|
||||
if (BlueprintObject.IsValid())
|
||||
{
|
||||
FBlueprintParameters BlueprintParams;
|
||||
if (JsonToFBlueprintParameters(BlueprintObject, BlueprintParams))
|
||||
{
|
||||
OutBlueprintParamsArray.Add(BlueprintParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ABlueprintActorFactory::LoadBlueprintParametersArrayFromFile(const FString& FileName, TArray<FBlueprintParameters>& OutBlueprintParamsArray)
|
||||
{
|
||||
FString JsonString;
|
||||
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
|
||||
FString JsonContent;
|
||||
|
||||
// Load the JSON file content into an FString
|
||||
if (FFileHelper::LoadFileToString(JsonContent, *FilePath))
|
||||
{
|
||||
// Parse the JSON and populate the TArray<FBlueprintParameters>
|
||||
if (JsonToFBlueprintParametersArray(JsonContent, OutBlueprintParamsArray))
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Blueprint parameters loaded successfully from %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to parse Blueprint parameters from %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to load file: %s"), *FilePath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorSpawnResult.h"
|
||||
#include "Carla/Actor/CarlaActorFactory.h"
|
||||
#include "Carla/Actor/BlueprintParameters.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include <util/ue-header-guard-end.h>
|
||||
|
||||
#include "BlueprintActorFactory.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class CARLA_API ABlueprintActorFactory : public ACarlaActorFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/// Retrieve the definitions of the static mesh actor
|
||||
virtual TArray<FActorDefinition> GetDefinitions() override;
|
||||
|
||||
virtual FActorSpawnResult SpawnActor(
|
||||
const FTransform &SpawnAtTransform,
|
||||
const FActorDescription &ActorDescription) override;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category = "BlueprintActorFactory")
|
||||
static void SaveBlueprintParametersArrayToFile(const TArray<FBlueprintParameters> &BlueprintParamsArray, const FString &FileName);
|
||||
UFUNCTION(BlueprintCallable, Category = "BlueprintActorFactory")
|
||||
static void LoadBlueprintParametersArrayFromFile(const FString &FileName, TArray<FBlueprintParameters> &OutBlueprintParamsArray);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "BlueprintActorFactory")
|
||||
bool PostProcessBlueprint(AActor* SpawnedActor, const FActorDescription& BlueprintParams);
|
||||
|
||||
private:
|
||||
static TSharedPtr<FJsonObject> FBlueprintParametersToJsonObject(const FBlueprintParameters& BlueprintParams);
|
||||
static FString FBlueprintParametersArrayToJson(const TArray<FBlueprintParameters>& BlueprintParamsArray);
|
||||
static bool JsonToFBlueprintParameters(const TSharedPtr<FJsonObject> JsonObject, FBlueprintParameters& OutBlueprintParams);
|
||||
static bool JsonToFBlueprintParametersArray(const FString& JsonString, TArray<FBlueprintParameters>& OutBlueprintParamsArray);
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditAnywhere)
|
||||
TArray<FActorDefinition> Definitions;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<FBlueprintParameters> BlueprintsParams;
|
||||
};
|
|
@ -0,0 +1,229 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
|
||||
#include "Carla/Actor/Factory/PropActorFactory.h"
|
||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||
#include "Carla/Actor/ActorDefinition.h"
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include <util/ue-header-guard-end.h>
|
||||
|
||||
TArray<FActorDefinition> APropActorFactory::GetDefinitions()
|
||||
{
|
||||
LoadPropParametersArrayFromFile("PropParameters.json", PropsParams);
|
||||
|
||||
UActorBlueprintFunctionLibrary::MakePropDefinitions(PropsParams, Definitions);
|
||||
return Definitions;
|
||||
}
|
||||
|
||||
FActorSpawnResult APropActorFactory::SpawnActor(
|
||||
const FTransform &SpawnAtTransform,
|
||||
const FActorDescription &ActorDescription)
|
||||
{
|
||||
FActorSpawnResult SpawnResult;
|
||||
if(!IsValid(ActorDescription.Class))
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Actor Description Class is null."));
|
||||
SpawnResult.Status = EActorSpawnResultStatus::InvalidDescription;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(ActorDescription.Class, SpawnAtTransform);
|
||||
SpawnResult.Actor = SpawnedActor;
|
||||
|
||||
if(SpawnedActor == nullptr)
|
||||
{
|
||||
SpawnResult.Status = EActorSpawnResultStatus::Collision;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
if(PostProcessProp(SpawnedActor, ActorDescription))
|
||||
{
|
||||
SpawnResult.Status = EActorSpawnResultStatus::Success;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
SpawnResult.Status = EActorSpawnResultStatus::UnknownError;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
TSharedPtr<FJsonObject> APropActorFactory::FPropParametersToJsonObject(const FPropParameters& PropParams)
|
||||
{
|
||||
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||
|
||||
JsonObject->SetStringField(TEXT("Name"), PropParams.Name);
|
||||
JsonObject->SetStringField(TEXT("Mesh"), PropParams.Mesh->GetPathName());
|
||||
|
||||
FString PropSizeString;
|
||||
switch(PropParams.Size)
|
||||
{
|
||||
case EPropSize::Tiny:
|
||||
PropSizeString = FString("Tiny");
|
||||
break;
|
||||
case EPropSize::Small:
|
||||
PropSizeString = FString("Small");
|
||||
break;
|
||||
case EPropSize::Medium:
|
||||
PropSizeString = FString("Medium");
|
||||
break;
|
||||
case EPropSize::Big:
|
||||
PropSizeString = FString("Big");
|
||||
break;
|
||||
case EPropSize::Huge:
|
||||
PropSizeString = FString("Huge");
|
||||
break;
|
||||
default:
|
||||
PropSizeString = FString("INVALID");
|
||||
break;
|
||||
}
|
||||
JsonObject->SetStringField(TEXT("Size"), PropSizeString);
|
||||
return JsonObject;
|
||||
}
|
||||
|
||||
FString APropActorFactory::FPropParametersArrayToJson(const TArray<FPropParameters>& PropParamsArray)
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> JsonArray;
|
||||
|
||||
for (const FPropParameters& PropParams : PropParamsArray)
|
||||
{
|
||||
// Convert each FPropParameters to a JSON object
|
||||
TSharedPtr<FJsonObject> JsonObject = FPropParametersToJsonObject(PropParams);
|
||||
JsonArray.Add(MakeShareable(new FJsonValueObject(JsonObject)));
|
||||
}
|
||||
|
||||
// Convert the array of JSON objects into a single JSON object
|
||||
TSharedRef<FJsonObject> RootObject = MakeShareable(new FJsonObject);
|
||||
RootObject->SetArrayField(TEXT("Props"), JsonArray);
|
||||
|
||||
// Serialize the JSON object into an FString
|
||||
FString OutputString;
|
||||
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
|
||||
FJsonSerializer::Serialize(RootObject, Writer);
|
||||
|
||||
return OutputString;
|
||||
}
|
||||
|
||||
void APropActorFactory::SavePropParametersArrayToFile(const TArray<FPropParameters>& PropParametersArray, const FString& FileName)
|
||||
{
|
||||
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
|
||||
// Convert the array to an FString in JSON format
|
||||
FString JsonContent = FPropParametersArrayToJson(PropParametersArray);
|
||||
|
||||
// Save the JSON to a file
|
||||
if (FFileHelper::SaveStringToFile(JsonContent, *FilePath))
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("JSON file successfully saved at: %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to save JSON file at: %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
bool APropActorFactory::JsonToFPropParameters(const TSharedPtr<FJsonObject> JsonObject, FPropParameters& OutPropParams)
|
||||
{
|
||||
if (!JsonObject.IsValid()) return false;
|
||||
|
||||
JsonObject->TryGetStringField(TEXT("Name"), OutPropParams.Name);
|
||||
|
||||
// Convert "Mesh" string back to a FMesh reference
|
||||
FString MeshPath;
|
||||
JsonObject->TryGetStringField(TEXT("Mesh"), MeshPath);
|
||||
OutPropParams.Mesh = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, *(MeshPath)));
|
||||
|
||||
FString PropSizeString;
|
||||
JsonObject->TryGetStringField(TEXT("Size"), PropSizeString);
|
||||
|
||||
if(PropSizeString == FString("Tiny")){
|
||||
OutPropParams.Size = EPropSize::Tiny;
|
||||
}
|
||||
else if(PropSizeString == FString("Small"))
|
||||
{
|
||||
OutPropParams.Size = EPropSize::Small;
|
||||
}
|
||||
else if(PropSizeString == FString("Medium"))
|
||||
{
|
||||
OutPropParams.Size = EPropSize::Medium;
|
||||
}
|
||||
else if(PropSizeString == FString("Big"))
|
||||
{
|
||||
OutPropParams.Size = EPropSize::Big;
|
||||
}
|
||||
else if(PropSizeString == FString("Huge"))
|
||||
{
|
||||
OutPropParams.Size = EPropSize::Huge;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutPropParams.Size = EPropSize::INVALID;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APropActorFactory::JsonToFPropParametersArray(const FString& JsonString, TArray<FPropParameters>& OutPropParamsArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> RootObject;
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonString);
|
||||
|
||||
if (!FJsonSerializer::Deserialize(Reader, RootObject) || !RootObject.IsValid())
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to parse JSON."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the "Props" array from the JSON root object
|
||||
const TArray<TSharedPtr<FJsonValue>>* PropsArray;
|
||||
if (RootObject->TryGetArrayField(TEXT("Props"), PropsArray))
|
||||
{
|
||||
OutPropParamsArray.Empty();
|
||||
for (const TSharedPtr<FJsonValue>& PropValue : *PropsArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> PropObject = PropValue->AsObject();
|
||||
if (PropObject.IsValid())
|
||||
{
|
||||
FPropParameters PropParams;
|
||||
if (JsonToFPropParameters(PropObject, PropParams))
|
||||
{
|
||||
OutPropParamsArray.Add(PropParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void APropActorFactory::LoadPropParametersArrayFromFile(const FString& FileName, TArray<FPropParameters>& OutPropParamsArray)
|
||||
{
|
||||
FString JsonString;
|
||||
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
|
||||
FString JsonContent;
|
||||
|
||||
// Load the JSON file content into an FString
|
||||
if (FFileHelper::LoadFileToString(JsonContent, *FilePath))
|
||||
{
|
||||
// Parse the JSON and populate the TArray<FPropParameters>
|
||||
if (JsonToFPropParametersArray(JsonContent, OutPropParamsArray))
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Prop parameters loaded successfully from %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to parse Prop parameters from %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to load file: %s"), *FilePath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorSpawnResult.h"
|
||||
#include "Carla/Actor/CarlaActorFactory.h"
|
||||
#include "Carla/Actor/PropParameters.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include <util/ue-header-guard-end.h>
|
||||
|
||||
#include "PropActorFactory.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class CARLA_API APropActorFactory : public ACarlaActorFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/// Retrieve the definitions of the static mesh actor
|
||||
virtual TArray<FActorDefinition> GetDefinitions() override;
|
||||
|
||||
virtual FActorSpawnResult SpawnActor(
|
||||
const FTransform &SpawnAtTransform,
|
||||
const FActorDescription &ActorDescription) override;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category = "PropActorFactory")
|
||||
static void SavePropParametersArrayToFile(const TArray<FPropParameters> &PropParamsArray, const FString &FileName);
|
||||
UFUNCTION(BlueprintCallable, Category = "PropActorFactory")
|
||||
static void LoadPropParametersArrayFromFile(const FString &FileName, TArray<FPropParameters> &OutPropParamsArray);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "PropActorFactory")
|
||||
bool PostProcessProp(AActor* SpawnedActor, const FActorDescription& PropParams);
|
||||
|
||||
private:
|
||||
static TSharedPtr<FJsonObject> FPropParametersToJsonObject(const FPropParameters& PropParams);
|
||||
static FString FPropParametersArrayToJson(const TArray<FPropParameters>& PropParamsArray);
|
||||
static bool JsonToFPropParameters(const TSharedPtr<FJsonObject> JsonObject, FPropParameters& OutPropParams);
|
||||
static bool JsonToFPropParametersArray(const FString& JsonString, TArray<FPropParameters>& OutPropParamsArray);
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditAnywhere)
|
||||
TArray<FActorDefinition> Definitions;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<FPropParameters> PropsParams;
|
||||
};
|
|
@ -242,8 +242,12 @@ void AVehicleActorFactory::LoadVehicleParametersArrayFromFile(const FString& Fil
|
|||
UE_LOG(LogCarla, Error, TEXT("Failed to parse vehicle parameters from %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(FileName == "VehicleParameters.json")
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to load file: %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Warning, TEXT("Additional file not found: %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ protected:
|
|||
|
||||
UPROPERTY(EditAnywhere)
|
||||
TArray<FActorDefinition> Definitions;
|
||||
UPROPERTY(EditAnywhere)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<FVehicleParameters> VehiclesParams;
|
||||
UPROPERTY(EditAnywhere)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<FVehicleParameters> MineVehiclesParams;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
|
||||
#include "Carla/Actor/Factory/WalkerActorFactory.h"
|
||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||
#include "Carla/Actor/ActorDefinition.h"
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
#include "Carla/Walker/WalkerBase.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include <util/ue-header-guard-end.h>
|
||||
|
||||
TArray<FActorDefinition> AWalkerActorFactory::GetDefinitions()
|
||||
{
|
||||
LoadWalkerParametersArrayFromFile("WalkerParameters.json", WalkersParams);
|
||||
|
||||
UActorBlueprintFunctionLibrary::MakePedestrianDefinitions(WalkersParams, Definitions);
|
||||
return Definitions;
|
||||
}
|
||||
|
||||
FActorSpawnResult AWalkerActorFactory::SpawnActor(
|
||||
const FTransform &SpawnAtTransform,
|
||||
const FActorDescription &ActorDescription)
|
||||
{
|
||||
FActorSpawnResult SpawnResult;
|
||||
if(!IsValid(ActorDescription.Class))
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Actor Description Class is null."));
|
||||
SpawnResult.Status = EActorSpawnResultStatus::InvalidDescription;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(ActorDescription.Class, SpawnAtTransform);
|
||||
SpawnResult.Actor = SpawnedActor;
|
||||
|
||||
if(SpawnedActor == nullptr)
|
||||
{
|
||||
SpawnResult.Status = EActorSpawnResultStatus::Collision;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
if(PostProcessWalker(SpawnedActor, ActorDescription))
|
||||
{
|
||||
SpawnResult.Status = EActorSpawnResultStatus::Success;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
SpawnResult.Status = EActorSpawnResultStatus::UnknownError;
|
||||
return SpawnResult;
|
||||
}
|
||||
|
||||
TSharedPtr<FJsonObject> AWalkerActorFactory::FWalkerParametersToJsonObject(const FPedestrianParameters& WalkerParams)
|
||||
{
|
||||
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||
JsonObject->SetStringField(TEXT("Id"), WalkerParams.Id);
|
||||
JsonObject->SetStringField(TEXT("Class"), WalkerParams.Class ? WalkerParams.Class->GetPathName() : "");
|
||||
|
||||
FString GenderString;
|
||||
switch(WalkerParams.Gender)
|
||||
{
|
||||
case EPedestrianGender::Other:
|
||||
GenderString = FString("Other");
|
||||
break;
|
||||
case EPedestrianGender::Female:
|
||||
GenderString = FString("Female");
|
||||
break;
|
||||
case EPedestrianGender::Male:
|
||||
GenderString = FString("Male");
|
||||
break;
|
||||
default:
|
||||
GenderString = FString("INVALID");
|
||||
break;
|
||||
}
|
||||
JsonObject->SetStringField(TEXT("Gender"), GenderString);
|
||||
|
||||
FString AgeString;
|
||||
switch(WalkerParams.Age)
|
||||
{
|
||||
case EPedestrianAge::Child:
|
||||
AgeString = FString("Child");
|
||||
break;
|
||||
case EPedestrianAge::Teenager:
|
||||
AgeString = FString("Teenager");
|
||||
break;
|
||||
case EPedestrianAge::Adult:
|
||||
AgeString = FString("Adult");
|
||||
break;
|
||||
case EPedestrianAge::Elderly:
|
||||
AgeString = FString("Elderly");
|
||||
break;
|
||||
default:
|
||||
AgeString = FString("INVALID");
|
||||
break;
|
||||
}
|
||||
JsonObject->SetStringField(TEXT("Age"), AgeString);
|
||||
|
||||
//JsonObject->SetNumberField(TEXT("Speed"), InSpeed);
|
||||
TArray<TSharedPtr<FJsonValue>> SpeedArray;
|
||||
for (const float& Speed : WalkerParams.Speed)
|
||||
{
|
||||
TSharedPtr<FJsonObject> SpeedObject = MakeShareable(new FJsonObject);
|
||||
SpeedObject->SetNumberField(TEXT("Speed"), Speed);
|
||||
SpeedArray.Add(MakeShareable(new FJsonValueObject(SpeedObject)));
|
||||
}
|
||||
JsonObject->SetArrayField(TEXT("Speeds"), SpeedArray);
|
||||
|
||||
JsonObject->SetNumberField(TEXT("Generation"), WalkerParams.Generation);
|
||||
|
||||
return JsonObject;
|
||||
}
|
||||
|
||||
FString AWalkerActorFactory::FWalkerParametersArrayToJson(const TArray<FPedestrianParameters>& WalkerParamsArray)
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> JsonArray;
|
||||
|
||||
for (const FPedestrianParameters& WalkerParams : WalkerParamsArray)
|
||||
{
|
||||
// Convert each FPedestrianParameters to a JSON object
|
||||
TSharedPtr<FJsonObject> JsonObject = FWalkerParametersToJsonObject(WalkerParams);
|
||||
JsonArray.Add(MakeShareable(new FJsonValueObject(JsonObject)));
|
||||
}
|
||||
|
||||
// Convert the array of JSON objects into a single JSON object
|
||||
TSharedRef<FJsonObject> RootObject = MakeShareable(new FJsonObject);
|
||||
RootObject->SetArrayField(TEXT("Walkers"), JsonArray);
|
||||
|
||||
// Serialize the JSON object into an FString
|
||||
FString OutputString;
|
||||
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
|
||||
FJsonSerializer::Serialize(RootObject, Writer);
|
||||
|
||||
return OutputString;
|
||||
}
|
||||
|
||||
void AWalkerActorFactory::SaveWalkerParametersArrayToFile(const TArray<FPedestrianParameters>& WalkerParametersArray, const FString& FileName)
|
||||
{
|
||||
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
|
||||
// Convert the array to an FString in JSON format
|
||||
FString JsonContent = FWalkerParametersArrayToJson(WalkerParametersArray);
|
||||
|
||||
// Save the JSON to a file
|
||||
if (FFileHelper::SaveStringToFile(JsonContent, *FilePath))
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("JSON file successfully saved at: %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to save JSON file at: %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
bool AWalkerActorFactory::JsonToFWalkerParameters(const TSharedPtr<FJsonObject> JsonObject, FPedestrianParameters& OutWalkerParams)
|
||||
{
|
||||
if (!JsonObject.IsValid()) return false;
|
||||
|
||||
JsonObject->TryGetStringField(TEXT("Id"), OutWalkerParams.Id);
|
||||
|
||||
FString ClassPath;
|
||||
JsonObject->TryGetStringField(TEXT("Class"), ClassPath); // Custom conversion required if needed
|
||||
OutWalkerParams.Class = StaticLoadClass(AWalkerBase::StaticClass(), nullptr, *ClassPath);
|
||||
|
||||
FString GenderString;
|
||||
JsonObject->TryGetStringField(TEXT("Gender"), GenderString);
|
||||
|
||||
if(GenderString == FString("Other")){
|
||||
OutWalkerParams.Gender = EPedestrianGender::Other;
|
||||
}
|
||||
else if(GenderString == FString("Female"))
|
||||
{
|
||||
OutWalkerParams.Gender = EPedestrianGender::Female;
|
||||
}
|
||||
else if(GenderString == FString("Male"))
|
||||
{
|
||||
OutWalkerParams.Gender = EPedestrianGender::Male;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutWalkerParams.Gender = EPedestrianGender::INVALID;
|
||||
}
|
||||
|
||||
FString AgeString;
|
||||
JsonObject->TryGetStringField(TEXT("Age"), AgeString);
|
||||
|
||||
if(AgeString == FString("Child")){
|
||||
OutWalkerParams.Age = EPedestrianAge::Child;
|
||||
}
|
||||
else if(AgeString == FString("Teenager"))
|
||||
{
|
||||
OutWalkerParams.Age = EPedestrianAge::Teenager;
|
||||
}
|
||||
else if(AgeString == FString("Adult"))
|
||||
{
|
||||
OutWalkerParams.Age = EPedestrianAge::Adult;
|
||||
}
|
||||
else if(AgeString == FString("Elderly"))
|
||||
{
|
||||
OutWalkerParams.Age = EPedestrianAge::Elderly;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutWalkerParams.Age = EPedestrianAge::INVALID;
|
||||
}
|
||||
|
||||
// Parse Speeds
|
||||
const TArray<TSharedPtr<FJsonValue>>* SpeedsArray;
|
||||
if (JsonObject->TryGetArrayField(TEXT("Speeds"), SpeedsArray))
|
||||
{
|
||||
OutWalkerParams.Speed.Empty();
|
||||
for (const TSharedPtr<FJsonValue>& SpeedValue : *SpeedsArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> SpeedObject = SpeedValue->AsObject();
|
||||
if (SpeedObject.IsValid())
|
||||
{
|
||||
float Speed;
|
||||
Speed = SpeedObject->GetNumberField(TEXT("Speed"));
|
||||
OutWalkerParams.Speed.Add(Speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject->TryGetNumberField(TEXT("Generation"), OutWalkerParams.Generation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AWalkerActorFactory::JsonToFWalkerParametersArray(const FString& JsonString, TArray<FPedestrianParameters>& OutWalkerParamsArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> RootObject;
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonString);
|
||||
|
||||
if (!FJsonSerializer::Deserialize(Reader, RootObject) || !RootObject.IsValid())
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to parse JSON."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the "Walkers" array from the JSON root object
|
||||
const TArray<TSharedPtr<FJsonValue>>* WalkersArray;
|
||||
if (RootObject->TryGetArrayField(TEXT("Walkers"), WalkersArray))
|
||||
{
|
||||
OutWalkerParamsArray.Empty();
|
||||
for (const TSharedPtr<FJsonValue>& WalkerValue : *WalkersArray)
|
||||
{
|
||||
TSharedPtr<FJsonObject> WalkerObject = WalkerValue->AsObject();
|
||||
if (WalkerObject.IsValid())
|
||||
{
|
||||
FPedestrianParameters WalkerParams;
|
||||
if (JsonToFWalkerParameters(WalkerObject, WalkerParams))
|
||||
{
|
||||
OutWalkerParamsArray.Add(WalkerParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AWalkerActorFactory::LoadWalkerParametersArrayFromFile(const FString& FileName, TArray<FPedestrianParameters>& OutWalkerParamsArray)
|
||||
{
|
||||
FString JsonString;
|
||||
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
|
||||
FString JsonContent;
|
||||
|
||||
// Load the JSON file content into an FString
|
||||
if (FFileHelper::LoadFileToString(JsonContent, *FilePath))
|
||||
{
|
||||
// Parse the JSON and populate the TArray<FPedestrianParameters>
|
||||
if (JsonToFWalkerParametersArray(JsonContent, OutWalkerParamsArray))
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Walker parameters loaded successfully from %s"), *FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to parse Walker parameters from %s"), *FilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to load file: %s"), *FilePath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorSpawnResult.h"
|
||||
#include "Carla/Actor/CarlaActorFactory.h"
|
||||
#include "Carla/Actor/PedestrianParameters.h"
|
||||
|
||||
#include <util/ue-header-guard-begin.h>
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include <util/ue-header-guard-end.h>
|
||||
|
||||
#include "WalkerActorFactory.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class CARLA_API AWalkerActorFactory : public ACarlaActorFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/// Retrieve the definitions of the static mesh actor
|
||||
virtual TArray<FActorDefinition> GetDefinitions() override;
|
||||
|
||||
virtual FActorSpawnResult SpawnActor(
|
||||
const FTransform &SpawnAtTransform,
|
||||
const FActorDescription &ActorDescription) override;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category = "WalkerActorFactory")
|
||||
static void SaveWalkerParametersArrayToFile(const TArray<FPedestrianParameters> &WalkerParamsArray, const FString &FileName);
|
||||
UFUNCTION(BlueprintCallable, Category = "WalkerActorFactory")
|
||||
static void LoadWalkerParametersArrayFromFile(const FString &FileName, TArray<FPedestrianParameters> &OutWalkerParamsArray);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "WalkerActorFactory")
|
||||
bool PostProcessWalker(AActor* SpawnedActor, const FActorDescription& WalkerParams);
|
||||
|
||||
private:
|
||||
static TSharedPtr<FJsonObject> FWalkerParametersToJsonObject(const FPedestrianParameters& WalkerParams);
|
||||
static FString FWalkerParametersArrayToJson(const TArray<FPedestrianParameters>& WalkerParamsArray);
|
||||
static bool JsonToFWalkerParameters(const TSharedPtr<FJsonObject> JsonObject, FPedestrianParameters& OutWalkerParams);
|
||||
static bool JsonToFWalkerParametersArray(const FString& JsonString, TArray<FPedestrianParameters>& OutWalkerParamsArray);
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditAnywhere)
|
||||
TArray<FActorDefinition> Definitions;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<FPedestrianParameters> WalkersParams;
|
||||
};
|
Loading…
Reference in New Issue