CARLA
Loading...
Searching...
No Matches
Unreal/CarlaUnreal/Plugins/Carla/Source/Carla/OpenDrive/OpenDrive.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8#include "Carla.h"
12
13#include <util/ue-header-guard-begin.h>
14#include "Engine/Engine.h"
15#include "GenericPlatform/GenericPlatformProcess.h"
16#include "Misc/FileHelper.h"
17#include "HAL/FileManagerGeneric.h"
18#include <util/ue-header-guard-end.h>
19
21
22FString UOpenDrive::GetSavedXODRPath(const FString &MapName)
23{
24 const FString Directory = UOpenDrive_SavedXODRDirectory.IsEmpty() ?
25 FPaths::ProjectSavedDir() / TEXT("OpenDrive") : UOpenDrive_SavedXODRDirectory;
26 return FPaths::ConvertRelativePathToFull(Directory / (MapName + TEXT(".xodr")));
27}
28
29void UOpenDrive::SetSavedXODRDirectory(const FString &Directory)
30{
32}
33
34FString UOpenDrive::FindPathToXODRFile(const FString &InMapName){
35
36 FString MapName = InMapName;
37
38#if WITH_EDITOR
39 {
40 FString CorrectedMapName = MapName;
41 constexpr auto PIEPrefix = TEXT("UEDPIE_0_");
42 CorrectedMapName.RemoveFromStart(PIEPrefix);
43 MapName = CorrectedMapName;
44 }
45#endif // WITH_EDITOR
46
47 FString XODRFileName = MapName + TEXT(".xodr");
48
49 auto &FileManager = IFileManager::Get();
50
51 // Generated OpenDRIVE worlds write their xodr to Saved/ (the content dir
52 // is pak-backed in a packaged build); that copy is the current one.
53 const FString SavedFilePath = GetSavedXODRPath(MapName);
54 if (FileManager.FileExists(*SavedFilePath))
55 {
56 return SavedFilePath;
57 }
58
59 const FString DefaultFilePath =
60 FPaths::ProjectContentDir() +
61 TEXT("Carla/Maps/OpenDrive/") +
62 XODRFileName;
63
64 if (FileManager.FileExists(*DefaultFilePath))
65 {
66 return DefaultFilePath;
67 }
68
69 // The manifest owns the sidecar path. DigitalTwin packs isolate each map's
70 // XODR and map_logic.json in a subdirectory so phase files cannot collide.
72 {
73 for (const FCarlaContentPack &Pack : ContentPacks->GetPacks())
74 {
75 if (!Pack.bMounted) continue;
76 for (const FCarlaContentPackMap &Map : Pack.Manifest.Maps)
77 {
78 if (Map.Name.Equals(MapName, ESearchCase::IgnoreCase) && !Map.Xodr.IsEmpty())
79 {
80 const FString PackFilePath = FPaths::ConvertRelativePathToFull(Pack.ContentDir / Map.Xodr);
81 if (FPaths::IsUnderDirectory(PackFilePath, Pack.ContentDir) && FileManager.FileExists(*PackFilePath))
82 {
83 return PackFilePath;
84 }
85 }
86 }
87 }
88 // Compatibility with older packs without a registered sidecar path.
89 for (const FString &PackContentDir : ContentPacks->GetPackContentDirs())
90 {
91 const FString PackFilePath = PackContentDir / TEXT("Maps/OpenDrive") / XODRFileName;
92 if (FileManager.FileExists(*PackFilePath))
93 {
94 return PackFilePath;
95 }
96 }
97 }
98
99 TArray<FString> FilesFound;
100 FileManager.FindFilesRecursive(
101 FilesFound,
102 *FPaths::ProjectContentDir(),
103 *XODRFileName,
104 true,
105 false,
106 false);
107
108 if (FilesFound.Num() > 0)
109 {
110 return FilesFound[0u];
111 }
112
113 FString PluginPath = FPaths::ProjectDir() + TEXT("Plugins/") + MapName + TEXT("/Content/Maps/OpenDrive/") + XODRFileName;
114
115 if (FileManager.FileExists(*PluginPath))
116 {
117 return PluginPath;
118 }
119
120 FString PluginsDir = FPaths::ProjectDir() + TEXT("Plugins/");
121
122 TArray<FString> PluginFilesFound;
123 FileManager.FindFilesRecursive(
124 PluginFilesFound,
125 *PluginsDir,
126 *XODRFileName,
127 true,
128 false,
129 false);
130
131 if (PluginFilesFound.Num() > 0)
132 {
133 return PluginFilesFound[0u];
134 }
135
136 return FString{};
137}
138
139FString UOpenDrive::GetXODR(const UWorld *World)
140{
141 auto MapName = World->GetMapName();
142
143 #if WITH_EDITOR
144 {
145 FString CorrectedMapName = MapName;
146 constexpr auto PIEPrefix = TEXT("UEDPIE_0_");
147 CorrectedMapName.RemoveFromStart(PIEPrefix);
148 MapName = CorrectedMapName;
149 }
150 #endif // WITH_EDITOR
151
153 auto MapDir = GameMode->GetFullMapPath();
154 const auto FolderDir = MapDir + "/OpenDrive/";
155 const auto FileName = MapDir.EndsWith(MapName) ? "*" : MapName;
156
157 TArray<FString> Files;
158
159 // A generated OpenDRIVE world keeps its current xodr in Saved/; a stale
160 // OpenDriveMap.xodr may still be cooked into the content dir.
161 const FString SavedFilePath = GetSavedXODRPath(MapName);
162 if (IFileManager::Get().FileExists(*SavedFilePath))
163 {
164 Files.Add(SavedFilePath);
165 }
166
167 if (!Files.Num())
168 {
169 IFileManager::Get().FindFilesRecursive(Files, *FolderDir, *FString(FileName + ".xodr"), true, false, false);
170 }
171
172 if (!Files.Num())
173 {
174 FString PluginFolder = FPaths::ProjectDir() + TEXT("Plugins/") + MapName + TEXT("/Content/Maps/OpenDrive/");
175 IFileManager::Get().FindFilesRecursive(Files, *PluginFolder, *FString(FileName + ".xodr"), true, false, false);
176 }
177
178 if (!Files.Num())
179 {
180 // Content packs and any other root FindPathToXODRFile knows about.
181 const FString FoundPath = FindPathToXODRFile(MapName);
182 if (!FoundPath.IsEmpty())
183 {
184 Files.Add(FoundPath);
185 }
186 }
187
188 FString Content;
189
190 if (!Files.Num())
191 {
192 UE_LOG(LogCarla, Error, TEXT("No OpenDrive file found for map '%s'"), *MapName);
193 }
194 else if (FFileHelper::LoadFileToString(Content, *Files[0]))
195 {
196 UE_LOG(LogCarla, Log, TEXT("Loaded OpenDrive file '%s'"), *Files[0]);
197 }
198 else
199 {
200 UE_LOG(LogCarla, Error, TEXT("Failed to load OpenDrive file '%s'"), *Files[0]);
201 }
202
203 return Content;
204}
205
206FString UOpenDrive::LoadXODR(const FString &MapName)
207{
208 const auto FilePath = FindPathToXODRFile(MapName);
209
210 FString Content;
211
212 if (FilePath.IsEmpty())
213 {
214 UE_LOG(LogCarla, Error, TEXT("Failed to find OpenDrive file for map '%s'"), *MapName);
215 }
216 else if (FFileHelper::LoadFileToString(Content, *FilePath))
217 {
218 UE_LOG(LogCarla, Log, TEXT("Loaded OpenDrive file '%s'"), *FilePath);
219 }
220 else
221 {
222 UE_LOG(LogCarla, Error, TEXT("Failed to load OpenDrive file '%s'"), *FilePath);
223 }
224
225 return Content;
226}
227
228FString UOpenDrive::LoadXODRFullPath(const FString &FullPath)
229{
230 FString Content;
231
232 if (FullPath.IsEmpty())
233 {
234 UE_LOG(LogCarla, Error, TEXT("Failed to find OpenDrive file for map '%s'"), *FullPath);
235 }
236 else if (FFileHelper::LoadFileToString(Content, *FullPath))
237 {
238 UE_LOG(LogCarla, Log, TEXT("Loaded OpenDrive file '%s'"), *FullPath);
239 }
240 else
241 {
242 UE_LOG(LogCarla, Error, TEXT("Failed to load OpenDrive file '%s'"), *FullPath);
243 }
244
245 return Content;
246}
247
248FString UOpenDrive::GetXODRByPath(FString XODRPath, FString MapName){
249
250 // When playing in editor the map name gets an extra prefix, here we
251 // remove it.
252 #if WITH_EDITOR
253 {
254 FString CorrectedMapName = MapName;
255 constexpr auto PIEPrefix = TEXT("UEDPIE_0_");
256 CorrectedMapName.RemoveFromStart(PIEPrefix);
257 MapName = CorrectedMapName;
258 }
259 #endif // WITH_EDITOR
260
261 FString FileName = XODRPath.EndsWith(MapName) ? "*" : MapName;
262 FString FolderDir = XODRPath;
263 FolderDir.RemoveFromEnd(MapName + ".xodr");
264
265 // Find all the xodr and bin files from the map
266 TArray<FString> Files;
267 IFileManager::Get().FindFilesRecursive(Files, *FolderDir, *FString(FileName + ".xodr"), true, false, false);
268
269 FString Content;
270
271 if (!Files.Num())
272 {
273 UE_LOG(LogTemp, Error, TEXT("Failed to find OpenDrive file for map '%s'"), *MapName);
274 }
275 else if (FFileHelper::LoadFileToString(Content, *Files[0]))
276 {
277 UE_LOG(LogTemp, Log, TEXT("Loaded OpenDrive file '%s'"), *Files[0]);
278 }
279
280 return Content;
281}
282
284{
285 UOpenDriveMap *Map = nullptr;
286 auto XODRContent = LoadXODR(MapName);
287 if (!XODRContent.IsEmpty())
288 {
289 Map = NewObject<UOpenDriveMap>();
290 Map->Load(XODRContent);
291 }
292 return Map;
293}
294
296{
297#if WITH_EDITOR
298
299 if (WorldContextObject == nullptr)
300 return nullptr;
301
302 auto World = GEngine->GetWorldFromContextObject(
303 WorldContextObject,
304 EGetWorldErrorMode::LogAndReturnNull);
305
306 if (World == nullptr)
307 return nullptr;
308
309 return LoadOpenDriveMap(World->GetMapName());
310
311#else
312
313 return nullptr;
314
315#endif
316}
Base class for the CARLA Game Mode.
const FString GetFullMapPath() const
Mounts CARLA content packs (content-only Unreal plugins cooked as DLC against a base release,...
static UCarlaContentPackManager * Get()
static ACarlaGameModeBase * GetGameMode(const UObject *WorldContextObject)
Helper class for exposing CARLA OpenDrive API to blueprints.
bool Load(const FString &XODRContent)
Load this map with an OpenDrive (XODR) file.
static UOpenDriveMap * LoadCurrentOpenDriveMap(const UObject *WorldContextObject)
Load OpenDriveMap associated to the currently loaded map.
static FString GetSavedXODRPath(const FString &MapName)
Where a generated OpenDRIVE world stores its xodr: <ProjectSavedDir>/OpenDrive/<MapName>....
static FString FindPathToXODRFile(const FString &InMapName)
static FString GetXODR(const UWorld *World)
Return the OpenDrive XML associated to MapName, or empty if the file is not found.
static void SetSavedXODRDirectory(const FString &Directory)
Multi-GPU secondary: a folder of this process for the generated worlds the primary sends,...
static UOpenDriveMap * LoadOpenDriveMap(const FString &MapName)
Load OpenDriveMap associated to the given MapName.
static FString GetXODRByPath(FString XODRPath, FString MapName)
Return the OpenDrive XML associated to MapName, or empty if the file is not found.
One map declared by a content pack manifest.
A content pack known to the manager (discovered or mounted explicitly).