35 const FString &JsonText,
39 TSharedPtr<FJsonObject> Root;
40 TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(JsonText);
41 if (!FJsonSerializer::Deserialize(Reader, Root) || !Root.IsValid())
43 OutError = FString::Printf(TEXT(
"manifest is not valid JSON: %s"), *Reader->GetErrorMessage());
47 if (!Root->TryGetStringField(TEXT(
"name"), Out.
Name) || Out.
Name.IsEmpty())
49 OutError = TEXT(
"manifest has no \"name\"");
54 OutError = FString::Printf(
55 TEXT(
"manifest \"name\" '%s' is not a valid pack name (letters, digits, '_' and '-' only)"),
60 Root->TryGetStringField(TEXT(
"version"), Out.
Version);
61 Root->TryGetStringField(TEXT(
"carla_version"), Out.
CarlaVersion);
62 Root->TryGetStringField(TEXT(
"base_release"), Out.
BaseRelease);
63 Root->TryGetStringField(TEXT(
"platform"), Out.
Platform);
65 const TSharedPtr<FJsonObject> *Engine =
nullptr;
66 if (Root->TryGetObjectField(TEXT(
"engine"), Engine) && Engine !=
nullptr && Engine->IsValid())
68 (*Engine)->TryGetStringField(TEXT(
"version"), Out.
EngineVersion);
69 (*Engine)->TryGetStringField(TEXT(
"commit"), Out.
EngineCommit);
73 const TArray<TSharedPtr<FJsonValue>> *MapsArray =
nullptr;
74 if (Root->TryGetArrayField(TEXT(
"maps"), MapsArray) && MapsArray !=
nullptr)
76 for (
const TSharedPtr<FJsonValue> &Value : *MapsArray)
78 const TSharedPtr<FJsonObject> MapObject = Value.IsValid() ? Value->AsObject() :
nullptr;
79 if (!MapObject.IsValid())
81 OutError = TEXT(
"manifest \"maps\" entries must be objects");
85 MapObject->TryGetStringField(TEXT(
"name"), Map.
Name);
86 MapObject->TryGetStringField(TEXT(
"package"), Map.
Package);
87 MapObject->TryGetStringField(TEXT(
"xodr"), Map.
Xodr);
88 MapObject->TryGetBoolField(TEXT(
"world_partition"), Map.
bWorldPartition);
89 if (Map.
Name.IsEmpty())
91 OutError = TEXT(
"manifest \"maps\" entry without \"name\"");
97 Map.
Package = FString::Printf(TEXT(
"/%s/Maps/%s"), *Out.
Name, *Map.
Name);
102 const FString ExpectedRoot = FString::Printf(TEXT(
"/%s/"), *Out.
Name);
103 if (!Map.
Package.StartsWith(ExpectedRoot) && !Map.
Package.StartsWith(TEXT(
"/Game/")))
105 OutError = FString::Printf(
106 TEXT(
"map '%s' package '%s' is neither under the pack mount point '%s' nor a project map (/Game/...)"),
110 Out.
Maps.Add(MoveTemp(Map));
115 const TArray<TSharedPtr<FJsonValue>> *CatalogsArray =
nullptr;
116 if (Root->TryGetArrayField(TEXT(
"catalogs"), CatalogsArray) && CatalogsArray !=
nullptr)
118 for (
const TSharedPtr<FJsonValue> &Value : *CatalogsArray)
121 if (Value.IsValid() && Value->TryGetString(Catalog) && !Catalog.IsEmpty())
129 const TSharedPtr<FJsonObject> *FilesObject =
nullptr;
130 if (Root->TryGetObjectField(TEXT(
"files"), FilesObject) && FilesObject !=
nullptr && FilesObject->IsValid())
132 for (
const auto &Pair : (*FilesObject)->Values)
135 if (Pair.Value.IsValid() && Pair.Value->TryGetString(Digest))
137 Out.
Files.Add(FString(Pair.Key.ToView()), Digest);
146 const FString &InManifestPath,
150 const FString FullPath = FPaths::ConvertRelativePathToFull(InManifestPath);
152 if (!FFileHelper::LoadFileToString(JsonText, *FullPath))
154 OutError = FString::Printf(TEXT(
"cannot read manifest '%s'"), *FullPath);
157 if (!
Parse(JsonText, Out, OutError))
159 OutError = FString::Printf(TEXT(
"%s: %s"), *FullPath, *OutError);
163 Out.
PackDir = FPaths::GetPath(FullPath);
TArray< FString > Catalogs
static bool LoadFromFile(const FString &InManifestPath, FCarlaContentPackManifest &OutManifest, FString &OutError)
Read and parse <ManifestPath>. Fills ManifestPath/PackDir.
FString ManifestPath
Absolute path of the manifest file this was parsed from.
static bool Parse(const FString &JsonText, FCarlaContentPackManifest &OutManifest, FString &OutError)
Parse a manifest from a JSON string. OutError explains a false return.
FString PackDir
Absolute path of the pack directory (parent of the manifest).
TArray< FCarlaContentPackMap > Maps
static bool IsValidPackName(const FString &InName)
Name must be usable as a plugin name and mount point ("/<Name>/").
TArray< FString > GetMapNames() const
TMap< FString, FString > Files
One map declared by a content pack manifest.
FString Package
Long package name of the level, e.g. "/NewPack/Maps/NewTown".
FString Xodr
OpenDRIVE file relative to the pack Content dir, e.g. "Maps/OpenDrive/NewTown.xodr".
FString Name
Map name as exposed by get_available_maps / load_world.