CARLA
Loading...
Searching...
No Matches
Carla.cpp
Go to the documentation of this file.
1// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
2
3#include "Carla.h"
7
8#include <util/ue-header-guard-begin.h>
9#include "Developer/Settings/Public/ISettingsModule.h"
10#include "Developer/Settings/Public/ISettingsSection.h"
11#include "Developer/Settings/Public/ISettingsContainer.h"
12#include "Interfaces/IPluginManager.h"
13#include "Misc/PackageName.h"
14#include "HAL/FileManager.h"
15#include "ShaderCore.h"
16#include <util/ue-header-guard-end.h>
17
18#define LOCTEXT_NAMESPACE "FCarlaModule"
19
21DEFINE_LOG_CATEGORY(LogCarlaServer);
22
24{
31#if WITH_EDITOR
32 RegisterLightDefaultsEditorTab();
33 RegisterLightDefaultsMapOpenedHook();
34#endif
35}
36
38{
39 // One-file-per-actor packages are named by the engine as
40 // /Game/__ExternalActors__/<path of the level under /Game>
41 // i.e. the __ExternalActors__ tree belongs at the mount root (Content/).
42 // CARLA content ships instead as a self-contained bundle that is cloned into
43 // a subfolder of Content (Content/Carla by default, but any name), carrying
44 // its own copy of the tree:
45 // Content/<Root>/__ExternalActors__/<path of the level under /Game>
46 // Those files are therefore named /Game/<Root>/__ExternalActors__/... and do
47 // not satisfy the references stored inside the levels, so every actor of a
48 // World Partition map is unresolvable: empty World Partition, no cells.
49 //
50 // Rather than moving content around, map the names the levels actually ask
51 // for onto the directories the bundles actually ship. Mount lookup picks the
52 // most specific root (FPackageName uses a prefix tree), so these nested
53 // mounts win over "/Game/" without disturbing anything else.
54 const FString ContentDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir());
55
56 // Handles both external actors and external objects (actor-owned sub-objects
57 // such as data layers use the same scheme with a different folder).
58 const TCHAR* ExternalFolderNames[] = { TEXT("__ExternalActors__"), TEXT("__ExternalObjects__") };
59
60 TArray<FString> ContentRoots;
61 IFileManager::Get().FindFiles(ContentRoots, *(ContentDir / TEXT("*")), false, true);
62
63 for (const FString& Root : ContentRoots)
64 {
65 for (const TCHAR* FolderName : ExternalFolderNames)
66 {
67 const FString BundleFolder = ContentDir / Root / FolderName;
68 if (!FPaths::DirectoryExists(BundleFolder))
69 {
70 continue;
71 }
72
73 // The bundle mirrors the level's package path underneath, e.g.
74 // Content/Carla/__ExternalActors__/Carla/Maps/Town12/Town12. Mount each
75 // first-level entry separately so two bundles (Content/Carla and, say,
76 // Content/TestingMap) can coexist under the same /Game/__External*__/
77 // namespace without colliding.
78 TArray<FString> Inner;
79 IFileManager::Get().FindFiles(Inner, *(BundleFolder / TEXT("*")), false, true);
80 for (const FString& InnerName : Inner)
81 {
82 const FString RootPath = FString::Printf(
83 TEXT("/Game/%s/%s/"), FolderName, *InnerName);
84 const FString ContentPath = BundleFolder / InnerName / TEXT("");
85
86 // Registering the same pair twice (editor hot-reload re-runs
87 // StartupModule) would duplicate the mount, so drop any previous one.
88 FPackageName::UnRegisterMountPoint(RootPath, ContentPath);
89 FPackageName::RegisterMountPoint(RootPath, ContentPath);
90 UE_LOG(LogCarla, Log, TEXT("Mounted external package root %s -> %s"),
91 *RootPath, *ContentPath);
92 }
93 }
94 }
95}
96
98{
99#if WITH_EDITOR
100 // Content packs are authored under Plugins/Packs/<Pack>/ with
101 // "ExplicitlyLoaded": true, which the stock plugin manager leaves
102 // unmounted. The interactive editor needs the pack content visible for
103 // authoring, so mount them here. Commandlets (the cooker) are left alone:
104 // the DLC cook enables the pack explicitly through the packer, and a base
105 // cook must not see pack content at all. Game processes use
106 // UCarlaContentPackManager instead.
107 if (!GIsEditor || IsRunningCommandlet())
108 {
109 return;
110 }
111 const FString PacksDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectPluginsDir() / TEXT("Packs"));
112 TArray<FString> PackDirs;
113 IFileManager::Get().FindFiles(PackDirs, *(PacksDir / TEXT("*")), false, true);
114 PackDirs.Sort();
115 IPluginManager& PluginManager = IPluginManager::Get();
116 for (const FString& PackName : PackDirs)
117 {
118 const FString PluginFile = PacksDir / PackName / (PackName + TEXT(".uplugin"));
119 if (!FPaths::FileExists(PluginFile))
120 {
121 continue;
122 }
123 TSharedPtr<IPlugin> Plugin = PluginManager.FindPlugin(PackName);
124 if (!Plugin.IsValid())
125 {
126 FText FailReason;
127 if (!PluginManager.AddToPluginsList(PluginFile, &FailReason))
128 {
129 UE_LOG(LogCarla, Warning, TEXT("Content pack plugin '%s' not registered: %s"),
130 *PluginFile, *FailReason.ToString());
131 continue;
132 }
133 Plugin = PluginManager.FindPlugin(PackName);
134 }
135 if (!Plugin.IsValid() || Plugin->IsMounted())
136 {
137 continue;
138 }
139 if (!Plugin->GetDescriptor().bExplicitlyLoaded)
140 {
141 // Regular plugin: the plugin manager enables it by its own rules.
142 continue;
143 }
144 if (PluginManager.MountExplicitlyLoadedPlugin(PackName))
145 {
146 UE_LOG(LogCarla, Log, TEXT("Content pack plugin '%s' mounted for the editor/cooker (%s)"),
147 *PackName, *PluginFile);
148 }
149 else
150 {
151 UE_LOG(LogCarla, Warning, TEXT("Content pack plugin '%s' could not be mounted (%s)"),
152 *PackName, *PluginFile);
153 }
154 }
155#endif // WITH_EDITOR
156}
157
159{
160 // The shader virtual path is process-global. Re-running StartupModule
161 // (editor Live Coding / hot-reload) must not register it twice, as
162 // AddShaderSourceDirectoryMapping asserts the path is not already mapped.
163 if (AllShaderSourceDirectoryMappings().Contains(TEXT("/Plugin/Carla")))
164 return;
165
166 const TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(TEXT("Carla"));
167 if (!Plugin.IsValid())
168 {
169 UE_LOG(LogCarla, Error,
170 TEXT("AddShaderSearchPaths: Carla plugin not found; shaders will be unavailable."));
171 return;
172 }
173
174 const FString ShadersDirectoryPath = FPaths::ConvertRelativePathToFull(
175 FPaths::Combine(Plugin->GetBaseDir(), TEXT("Shaders")));
176 if (!FPaths::DirectoryExists(ShadersDirectoryPath))
177 {
178 UE_LOG(LogCarla, Error,
179 TEXT("AddShaderSearchPaths: shader directory '%s' does not exist; shaders will be unavailable."),
180 *ShadersDirectoryPath);
181 return;
182 }
183
184 UE_LOG(LogCarla, Log, TEXT("Carla shader directory: %s"), *ShadersDirectoryPath);
185 AddShaderSourceDirectoryMapping(TEXT("/Plugin/Carla"), ShadersDirectoryPath);
186}
187
189{
190 #if defined(WITH_CHRONO) && PLATFORM_WINDOWS
191 const FString BaseDir = FPaths::Combine(*FPaths::ProjectPluginsDir(), TEXT("Carla"));
192 const FString DllDir = FPaths::Combine(*BaseDir, TEXT("CarlaDependencies"), TEXT("dll"));
193 FString ChronoEngineDll = FPaths::Combine(*DllDir, TEXT("ChronoEngine.dll"));
194 FString ChronoVehicleDll = FPaths::Combine(*DllDir, TEXT("ChronoEngine_vehicle.dll"));
195 FString ChronoModelsDll = FPaths::Combine(*DllDir, TEXT("ChronoModels_vehicle.dll"));
196 FString ChronoRobotDll = FPaths::Combine(*DllDir, TEXT("ChronoModels_robot.dll"));
197 UE_LOG(LogCarla, Log, TEXT("Loading Dlls from: %s"), *DllDir);
198 auto ChronoEngineHandle = FPlatformProcess::GetDllHandle(*ChronoEngineDll);
199 if (!ChronoEngineHandle)
200 {
201 UE_LOG(LogCarla, Warning, TEXT("Error: ChronoEngine.dll could not be loaded"));
202 }
203 auto ChronoVehicleHandle = FPlatformProcess::GetDllHandle(*ChronoVehicleDll);
204 if (!ChronoVehicleHandle)
205 {
206 UE_LOG(LogCarla, Warning, TEXT("Error: ChronoEngine_vehicle.dll could not be loaded"));
207 }
208 auto ChronoModelsHandle = FPlatformProcess::GetDllHandle(*ChronoModelsDll);
209 if (!ChronoModelsHandle)
210 {
211 UE_LOG(LogCarla, Warning, TEXT("Error: ChronoModels_vehicle.dll could not be loaded"));
212 }
213 auto ChronoRobotHandle = FPlatformProcess::GetDllHandle(*ChronoRobotDll);
214 if (!ChronoRobotHandle)
215 {
216 UE_LOG(LogCarla, Warning, TEXT("Error: ChronoModels_robot.dll could not be loaded"));
217 }
218 #endif
219}
220
222{
224#if WITH_EDITOR
225 UnregisterLightDefaultsMapOpenedHook();
226 UnregisterLightDefaultsEditorTab();
227#endif
228 if (UObjectInitialized())
229 {
231 }
232}
233
235{
236 // Registering some settings is just a matter of exposing the default UObject of
237 // your desired class, add here all those settings you want to expose
238 // to your LDs or artists.
239
240 if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
241 {
242 // Create the new category
243 ISettingsContainerPtr SettingsContainer = SettingsModule->GetContainer("Project");
244
245 SettingsContainer->DescribeCategory("CARLASettings",
246 LOCTEXT("RuntimeWDCategoryName", "CARLA Settings"),
247 LOCTEXT("RuntimeWDCategoryDescription", "CARLA plugin settings"));
248
249 // Register the settings
250 ISettingsSectionPtr SettingsSection = SettingsModule->RegisterSettings("Project", "CARLASettings", "General",
251 LOCTEXT("RuntimeGeneralSettingsName", "General"),
252 LOCTEXT("RuntimeGeneralSettingsDescription", "General configuration for the CARLA plugin"),
253 GetMutableDefault<UCarlaSettings>()
254 );
255
256 // Register the save handler to your settings, you might want to use it to
257 // validate those or just act to settings changes.
258 if (SettingsSection.IsValid())
259 {
260 SettingsSection->OnModified().BindRaw(this, &FCarlaModule::HandleSettingsSaved);
261 }
262 }
263}
264
266{
267 // Ensure to unregister all of your registered settings here, hot-reload would
268 // otherwise yield unexpected results.
269
270 if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
271 {
272 SettingsModule->UnregisterSettings("Project", "CustomSettings", "General");
273 }
274}
275
277{
278 UCarlaSettings* Settings = GetMutableDefault<UCarlaSettings>();
279 bool ResaveSettings = false;
280
281 // Put any validation code in here and resave the settings in case an invalid
282 // value has been entered
283
284 if (ResaveSettings)
285 {
286 Settings->SaveConfig();
287 }
288
289 return true;
290}
291
292#undef LOCTEXT_NAMESPACE
293
295
296// =============================================================================
297// -- Implement carla throw_exception ------------------------------------------
298// =============================================================================
299
300#ifdef LIBCARLA_NO_EXCEPTIONS
302#include <carla/Exception.h>
304
305#include <exception>
306namespace carla {
307
308 void throw_exception(const std::exception &e) {
309 UE_LOG(LogCarla, Fatal, TEXT("Exception thrown: %s"), UTF8_TO_TCHAR(e.what()));
310 // It should never reach this part.
311 std::terminate();
312 }
313
314} // namespace carla
315#endif
IMPLEMENT_MODULE(FCarlaDeviceProfileSelectorModule, CarlaDeviceProfileSelector)
DEFINE_LOG_CATEGORY(LogCarla)
void RegisterSettings()
Definition Carla.cpp:234
void UnregisterSettings()
Definition Carla.cpp:265
void MountExternalPackageRoots()
Definition Carla.cpp:37
void AddShaderSearchPaths()
Definition Carla.cpp:158
virtual void ShutdownModule() override
Definition Carla.cpp:221
void LoadChronoDll()
Definition Carla.cpp:188
void MountEditorContentPacks()
Definition Carla.cpp:97
virtual void StartupModule() override
IModuleInterface implementation.
Definition Carla.cpp:23
bool HandleSettingsSaved()
Definition Carla.cpp:276
Global settings for CARLA.
static void UnregisterRuntimeBuildingDefaultsHooks()
This file contains definitions of common data structures used in traffic manager.
void throw_exception(const ExceptionT &e)
Templated on the static type so the thrown object keeps its dynamic type: taking a const std::excepti...
Definition Exception.h:44