Aaron/programaticvehiclefactory (#8340)

* Add Vehicle Factory to be loaded in c++

* Read properly the object class path
This commit is contained in:
Blyron 2024-11-05 16:26:36 +01:00 committed by GitHub
parent 218b1d46f1
commit c37d00d671
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 293 additions and 0 deletions

View File

@ -0,0 +1,241 @@
// Copyright (c) 2024 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/VehicleActorFactory.h"
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
#include "Carla/Actor/ActorDefinition.h"
#include "Carla/Game/CarlaEpisode.h"
#include "Json.h"
#include "JsonUtilities.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
TArray<FActorDefinition> AVehicleActorFactory::GetDefinitions()
{
LoadVehicleParametersArrayFromFile("VehicleParameters.json", VehiclesParams);
UActorBlueprintFunctionLibrary::MakeVehicleDefinitions(VehiclesParams, Definitions);
return Definitions;
}
FActorSpawnResult AVehicleActorFactory::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( PostProcessVehicle(SpawnedActor, ActorDescription) ){
SpawnResult.Status = EActorSpawnResultStatus::Success;
return SpawnResult;
}
SpawnResult.Status = EActorSpawnResultStatus::UnknownError;
return SpawnResult;
}
TSharedPtr<FJsonObject> AVehicleActorFactory::FVehicleParametersToJsonObject(const FVehicleParameters& VehicleParams)
{
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
JsonObject->SetStringField(TEXT("Make"), VehicleParams.Make);
JsonObject->SetStringField(TEXT("Model"), VehicleParams.Model);
JsonObject->SetStringField(TEXT("Class"), VehicleParams.Class ? VehicleParams.Class->GetPathName() : "");
JsonObject->SetNumberField(TEXT("NumberOfWheels"), VehicleParams.NumberOfWheels);
JsonObject->SetNumberField(TEXT("Generation"), VehicleParams.Generation);
JsonObject->SetStringField(TEXT("ObjectType"), VehicleParams.ObjectType);
JsonObject->SetStringField(TEXT("BaseType"), VehicleParams.BaseType);
JsonObject->SetStringField(TEXT("SpecialType"), VehicleParams.SpecialType);
JsonObject->SetBoolField(TEXT("HasDynamicDoors"), VehicleParams.HasDynamicDoors);
JsonObject->SetBoolField(TEXT("HasLights"), VehicleParams.HasLights);
// Serialize RecommendedColors
TArray<TSharedPtr<FJsonValue>> ColorsArray;
for (const FColor& Color : VehicleParams.RecommendedColors)
{
TSharedPtr<FJsonObject> ColorObject = MakeShareable(new FJsonObject);
ColorObject->SetNumberField(TEXT("R"), Color.R);
ColorObject->SetNumberField(TEXT("G"), Color.G);
ColorObject->SetNumberField(TEXT("B"), Color.B);
ColorObject->SetNumberField(TEXT("A"), Color.A);
ColorsArray.Add(MakeShareable(new FJsonValueObject(ColorObject)));
}
JsonObject->SetArrayField(TEXT("RecommendedColors"), ColorsArray);
// Serialize SupportedDrivers
TArray<TSharedPtr<FJsonValue>> DriversArray;
for (int32 DriverID : VehicleParams.SupportedDrivers)
{
DriversArray.Add(MakeShareable(new FJsonValueNumber(DriverID)));
}
JsonObject->SetArrayField(TEXT("SupportedDrivers"), DriversArray);
return JsonObject;
}
FString AVehicleActorFactory::FVehicleParametersArrayToJson(const TArray<FVehicleParameters>& VehicleParamsArray)
{
TArray<TSharedPtr<FJsonValue>> JsonArray;
for (const FVehicleParameters& VehicleParams : VehicleParamsArray)
{
// Convert each FVehicleParameters to a JSON object
TSharedPtr<FJsonObject> JsonObject = FVehicleParametersToJsonObject(VehicleParams);
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("Vehicles"), JsonArray);
// Serialize the JSON object into an FString
FString OutputString;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(RootObject, Writer);
return OutputString;
}
void AVehicleActorFactory::SaveVehicleParametersArrayToFile(const TArray<FVehicleParameters>& VehicleParamsArray, const FString& FileName)
{
FString FilePath = FPaths::ProjectContentDir() + TEXT("Carla/Config/") + FileName;
// Convert the array to an FString in JSON format
FString JsonContent = FVehicleParametersArrayToJson(VehicleParamsArray);
// 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 AVehicleActorFactory::JsonToFVehicleParameters(const TSharedPtr<FJsonObject> JsonObject, FVehicleParameters& OutVehicleParams)
{
if (!JsonObject.IsValid()) return false;
JsonObject->TryGetStringField(TEXT("Make"), OutVehicleParams.Make);
JsonObject->TryGetStringField(TEXT("Model"), OutVehicleParams.Model);
// Convert "Class" string back to a class reference if necessary
FString ClassPath;
JsonObject->TryGetStringField(TEXT("Class"), ClassPath); // Custom conversion required if needed
OutVehicleParams.Class = StaticLoadClass(ACarlaWheeledVehicle::StaticClass(), nullptr, *ClassPath);
JsonObject->TryGetNumberField(TEXT("NumberOfWheels"), OutVehicleParams.NumberOfWheels);
JsonObject->TryGetNumberField(TEXT("Generation"), OutVehicleParams.Generation);
JsonObject->TryGetStringField(TEXT("ObjectType"), OutVehicleParams.ObjectType);
JsonObject->TryGetStringField(TEXT("BaseType"), OutVehicleParams.BaseType);
JsonObject->TryGetStringField(TEXT("SpecialType"), OutVehicleParams.SpecialType);
JsonObject->TryGetBoolField(TEXT("HasDynamicDoors"), OutVehicleParams.HasDynamicDoors);
JsonObject->TryGetBoolField(TEXT("HasLights"), OutVehicleParams.HasLights);
// Parse RecommendedColors
const TArray<TSharedPtr<FJsonValue>>* ColorsArray;
if (JsonObject->TryGetArrayField(TEXT("RecommendedColors"), ColorsArray))
{
OutVehicleParams.RecommendedColors.Empty();
for (const TSharedPtr<FJsonValue>& ColorValue : *ColorsArray)
{
TSharedPtr<FJsonObject> ColorObject = ColorValue->AsObject();
if (ColorObject.IsValid())
{
FColor Color;
Color.R = ColorObject->GetIntegerField(TEXT("R"));
Color.G = ColorObject->GetIntegerField(TEXT("G"));
Color.B = ColorObject->GetIntegerField(TEXT("B"));
Color.A = ColorObject->GetIntegerField(TEXT("A"));
OutVehicleParams.RecommendedColors.Add(Color);
}
}
}
// Parse SupportedDrivers
const TArray<TSharedPtr<FJsonValue>>* DriversArray;
if (JsonObject->TryGetArrayField(TEXT("SupportedDrivers"), DriversArray))
{
OutVehicleParams.SupportedDrivers.Empty();
for (const TSharedPtr<FJsonValue>& DriverValue : *DriversArray)
{
OutVehicleParams.SupportedDrivers.Add(DriverValue->AsNumber());
}
}
return true;
}
bool AVehicleActorFactory::JsonToFVehicleParametersArray(const FString& JsonString, TArray<FVehicleParameters>& OutVehicleParamsArray)
{
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 "Vehicles" array from the JSON root object
const TArray<TSharedPtr<FJsonValue>>* VehiclesArray;
if (RootObject->TryGetArrayField(TEXT("Vehicles"), VehiclesArray))
{
OutVehicleParamsArray.Empty();
for (const TSharedPtr<FJsonValue>& VehicleValue : *VehiclesArray)
{
TSharedPtr<FJsonObject> VehicleObject = VehicleValue->AsObject();
if (VehicleObject.IsValid())
{
FVehicleParameters VehicleParams;
if (JsonToFVehicleParameters(VehicleObject, VehicleParams))
{
OutVehicleParamsArray.Add(VehicleParams);
}
}
}
}
return true;
}
void AVehicleActorFactory::LoadVehicleParametersArrayFromFile(const FString& FileName, TArray<FVehicleParameters>& OutVehicleParamsArray)
{
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<FVehicleParameters>
if (JsonToFVehicleParametersArray(JsonContent, OutVehicleParamsArray))
{
UE_LOG(LogCarla, Log, TEXT("Vehicle parameters loaded successfully from %s"), *FilePath);
}
else
{
UE_LOG(LogCarla, Error, TEXT("Failed to parse vehicle parameters from %s"), *FilePath);
}
}
else
{
UE_LOG(LogCarla, Error, TEXT("Failed to load file: %s"), *FilePath);
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) 2024 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/VehicleParameters.h"
#include "Json.h"
#include "JsonUtilities.h"
#include "VehicleActorFactory.generated.h"
/// Factory in charge of spawning static meshes. This factory is able to spawn
/// any mesh in content.
UCLASS()
class CARLA_API AVehicleActorFactory : 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 = "VehicleActorFactory")
static void SaveVehicleParametersArrayToFile(const TArray<FVehicleParameters>& VehicleParamsArray, const FString& FileName);
UFUNCTION(BlueprintCallable, Category = "VehicleActorFactory")
static void LoadVehicleParametersArrayFromFile(const FString& FileName, TArray<FVehicleParameters>& OutVehicleParamsArray);
UFUNCTION(BlueprintImplementableEvent, Category = "VehicleActorFactory")
bool PostProcessVehicle(AActor* SpawnedActor, const FActorDescription& VehicleParams);
private:
static TSharedPtr<FJsonObject> FVehicleParametersToJsonObject(const FVehicleParameters& VehicleParams);
static FString FVehicleParametersArrayToJson(const TArray<FVehicleParameters>& VehicleParamsArray);
static bool JsonToFVehicleParameters(const TSharedPtr<FJsonObject> JsonObject, FVehicleParameters& OutVehicleParams);
static bool JsonToFVehicleParametersArray(const FString& JsonString, TArray<FVehicleParameters>& OutVehicleParamsArray);
protected:
UPROPERTY(EditAnywhere)
TArray<FActorDefinition> Definitions;
UPROPERTY(EditAnywhere)
TArray<FVehicleParameters> VehiclesParams;
};