69 const FTransform &SpawnAtTransform,
75 UE_LOG(LogCarla, Error, TEXT(
"Actor Description Class is null."));
76 SpawnResult.
Status = EActorSpawnResultStatus::InvalidDescription;
80 FActorSpawnParameters SpawnParameters;
81 SpawnParameters.SpawnCollisionHandlingOverride =
82 ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
84 AStaticMeshActor* StaticMeshActor = GetWorld()->SpawnActor<AStaticMeshActor>(
85 ActorDescription.
Class, SpawnAtTransform, SpawnParameters);
87 SpawnResult.
Actor = StaticMeshActor;
89 if(StaticMeshActor ==
nullptr)
91 SpawnResult.
Status = EActorSpawnResultStatus::Collision;
95 UStaticMeshComponent* StaticMeshComponent = Cast<UStaticMeshComponent>(
96 StaticMeshActor->GetRootComponent());
98 if (!StaticMeshComponent)
100 UE_LOG(LogCarla, Error, TEXT(
"Prop spawn failed: StaticMeshComponent is null for actor %s"),
101 *ActorDescription.
Id);
102 StaticMeshActor->Destroy();
103 SpawnResult.
Status = EActorSpawnResultStatus::UnknownError;
107 if (!ActorDescription.
Variations.Contains(
"mesh_path"))
109 UE_LOG(LogCarla, Error, TEXT(
"Prop spawn failed: No mesh_path variation found for actor %s"),
110 *ActorDescription.
Id);
111 StaticMeshActor->Destroy();
112 SpawnResult.
Status = EActorSpawnResultStatus::InvalidDescription;
117 ActorDescription.
Variations[
"mesh_path"],
"");
119 if (MeshPath.IsEmpty())
121 UE_LOG(LogCarla, Error, TEXT(
"Prop spawn failed: mesh_path is empty for actor %s"),
122 *ActorDescription.
Id);
123 StaticMeshActor->Destroy();
124 SpawnResult.
Status = EActorSpawnResultStatus::InvalidDescription;
128 UStaticMesh* Mesh =
nullptr;
131 Mesh = Cached->Get();
135 UE_LOG(LogCarla, Warning,
136 TEXT(
"PropActorFactory: mesh cache miss for '%s' (actor %s); falling back to synchronous LoadObject."),
137 *MeshPath, *ActorDescription.
Id);
138 Mesh = LoadObject<UStaticMesh>(
nullptr, *MeshPath);
147 UE_LOG(LogCarla, Error, TEXT(
"Prop spawn failed: Failed to load mesh '%s' for actor %s"),
148 *MeshPath, *ActorDescription.
Id);
149 StaticMeshActor->Destroy();
150 SpawnResult.
Status = EActorSpawnResultStatus::UnknownError;
154 StaticMeshComponent->SetMobility(EComponentMobility::Movable);
155 if (!StaticMeshComponent->SetStaticMesh(Mesh))
157 UE_LOG(LogCarla, Error, TEXT(
"Prop spawn failed: Failed to set mesh '%s' for actor %s"),
158 *MeshPath, *ActorDescription.
Id);
159 StaticMeshActor->Destroy();
160 SpawnResult.
Status = EActorSpawnResultStatus::UnknownError;
165 SpawnResult.
Status = EActorSpawnResultStatus::Success;
186 TSharedPtr<FJsonObject> JsonObject = MakeShareable(
new FJsonObject);
188 JsonObject->SetStringField(TEXT(
"Name"), PropParams.
Name);
189 JsonObject->SetStringField(TEXT(
"Mesh"), PropParams.
Mesh.ToSoftObjectPath().ToString());
191 FString PropSizeString;
192 switch(PropParams.
Size)
194 case EPropSize::Tiny:
195 PropSizeString = FString(
"Tiny");
197 case EPropSize::Small:
198 PropSizeString = FString(
"Small");
200 case EPropSize::Medium:
201 PropSizeString = FString(
"Medium");
204 PropSizeString = FString(
"Big");
206 case EPropSize::Huge:
207 PropSizeString = FString(
"Huge");
210 PropSizeString = FString(
"INVALID");
213 JsonObject->SetStringField(TEXT(
"Size"), PropSizeString);
215 JsonObject->SetStringField(TEXT(
"BaseType"), PropParams.
BaseType);
216 JsonObject->SetStringField(TEXT(
"SubType"), PropParams.
SubType);
222 TArray<TSharedPtr<FJsonValue>> JsonArray;
228 JsonArray.Add(MakeShareable(
new FJsonValueObject(JsonObject)));
232 TSharedRef<FJsonObject> RootObject = MakeShareable(
new FJsonObject);
233 RootObject->SetArrayField(TEXT(
"Props"), JsonArray);
236 FString OutputString;
237 TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
238 FJsonSerializer::Serialize(RootObject, Writer);
245 FString FilePath = FPaths::ProjectContentDir() + TEXT(
"Carla/Config/") + FileName;
250 if (FFileHelper::SaveStringToFile(JsonContent, *FilePath))
252 UE_LOG(LogCarla, Log, TEXT(
"JSON file successfully saved at: %s"), *FilePath);
256 UE_LOG(LogCarla, Error, TEXT(
"Failed to save JSON file at: %s"), *FilePath);
262 if (!JsonObject.IsValid())
return false;
264 JsonObject->TryGetStringField(TEXT(
"Name"), OutPropParams.
Name);
270 JsonObject->TryGetStringField(TEXT(
"Mesh"), MeshPath);
271 OutPropParams.
Mesh = TSoftObjectPtr<UStaticMesh>(FSoftObjectPath(MeshPath));
273 FString PropSizeString;
274 JsonObject->TryGetStringField(TEXT(
"Size"), PropSizeString);
278 JsonObject->TryGetStringField(TEXT(
"BaseType"), OutPropParams.
BaseType);
279 JsonObject->TryGetStringField(TEXT(
"SubType"), OutPropParams.
SubType);
281 if(PropSizeString == FString(
"Tiny")){
282 OutPropParams.
Size = EPropSize::Tiny;
284 else if(PropSizeString == FString(
"Small"))
286 OutPropParams.
Size = EPropSize::Small;
288 else if(PropSizeString == FString(
"Medium"))
290 OutPropParams.
Size = EPropSize::Medium;
292 else if(PropSizeString == FString(
"Big"))
294 OutPropParams.
Size = EPropSize::Big;
296 else if(PropSizeString == FString(
"Huge"))
298 OutPropParams.
Size = EPropSize::Huge;
302 OutPropParams.
Size = EPropSize::INVALID;
310 TSharedPtr<FJsonObject> RootObject;
311 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonString);
313 if (!FJsonSerializer::Deserialize(Reader, RootObject) || !RootObject.IsValid())
315 UE_LOG(LogCarla, Error, TEXT(
"Failed to parse JSON."));
320 const TArray<TSharedPtr<FJsonValue>>* PropsArray;
321 if (RootObject->TryGetArrayField(TEXT(
"Props"), PropsArray))
323 OutPropParamsArray.Empty();
324 for (
const TSharedPtr<FJsonValue>& PropValue : *PropsArray)
326 TSharedPtr<FJsonObject> PropObject = PropValue->AsObject();
327 if (PropObject.IsValid())
332 OutPropParamsArray.Add(PropParams);
346 FString FilePath = FPaths::IsRelative(FileName)
347 ? FPaths::ProjectContentDir() + TEXT(
"Carla/Config/") + FileName
352 if (FFileHelper::LoadFileToString(JsonContent, *FilePath))
357 UE_LOG(LogCarla, Log, TEXT(
"Prop parameters loaded successfully from %s"), *FilePath);
361 UE_LOG(LogCarla, Error, TEXT(
"Failed to parse Prop parameters from %s"), *FilePath);
366 UE_LOG(LogCarla, Error, TEXT(
"Failed to load file: %s"), *FilePath);
static void MergeCatalog(TArray< T > &Into, const TArray< T > &From, KeyFn Key)
Merge catalog entries: an entry whose key already exists replaces it in place (later files override b...
static TArray< FString > FindPackCatalogFiles(const FString &RelativeName)
<ContentDir>/Config/<RelativeName> of every mounted pack where the file exists, in mount order (later...