CARLA
Loading...
Searching...
No Matches
ContentPackManager.h
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
7#pragma once
8
10
11#include <util/ue-header-guard-begin.h>
12#include "CoreMinimal.h"
13#include "Subsystems/EngineSubsystem.h"
14#include <util/ue-header-guard-end.h>
15
16#include "ContentPackManager.generated.h"
17
18/// A content pack known to the manager (discovered or mounted explicitly).
19struct CARLA_API FCarlaContentPack
20{
22
23 /// Absolute pack directory (contains carla-pack.json and <Name>.uplugin).
24 FString PackDir;
25
26 /// Absolute path of <PackDir>/<Name>.uplugin.
27 FString PluginFile;
28
29 /// Absolute path of the plugin content dir (<PackDir>/Content), the
30 /// filesystem side of the "/<Name>/" mount point. Non-asset files staged
31 /// in the pack (xodr, nav .bin, Config/*.json) are read from here.
32 FString ContentDir;
33
34 /// Pak files mounted for this pack (cooked builds only).
35 TArray<FString> MountedPaks;
36
37 bool bMounted = false;
38
39 /// True when the plugin was mounted by the engine at startup (a pack
40 /// dropped under Plugins/ with a .upluginmanifest): the manager only
41 /// registers its manifest and catalogs and never unmounts it.
42 bool bEngineMounted = false;
43
44 const FString &GetName() const { return Manifest.Name; }
45};
46
48
49/// Mounts CARLA content packs (content-only Unreal plugins cooked as DLC
50/// against a base release, wrapped with a carla-pack.json manifest) into the
51/// running process, editor or cooked game alike.
52///
53/// Implemented as a UEngineSubsystem: it outlives game instances and worlds,
54/// so packs survive load_world, and it exists before the first map loads.
55/// Auto-discovery runs from Initialize() in game processes (packaged binary
56/// or editor -game); FCarlaEngine::NotifyInitGame calls Discover() again as
57/// a no-op safety net so the RPC server never starts before the packs are in.
58/// The full editor and commandlets (the cooker) do not auto-mount packs.
59UCLASS()
61{
62 GENERATED_BODY()
63
64public:
65
66 static UCarlaContentPackManager *Get();
67
68 virtual void Initialize(FSubsystemCollectionBase &Collection) override;
69
70 virtual void Deinitialize() override;
71
72 /// Mount every pack found in <ProjectDir>/Packs/*/carla-pack.json, the
73 /// directories listed in -carla-packs=<dir>[;<dir>] and $CARLA_PACKS, and
74 /// adopt every plugin the engine already mounted at startup that carries a
75 /// carla-pack.json next to its .uplugin (drop-in under Plugins/).
76 /// Idempotent; failures are logged, not fatal.
77 void Discover();
78
79 /// Mount a pack. Path is the pack directory or its carla-pack.json.
80 /// On failure OutError names the reason and the pack list is unchanged
81 /// (unless the pack was already known, in which case it stays unmounted).
82 bool Mount(const FString &Path, FString &OutError, const FCarlaContentPack **OutPack = nullptr);
83
84 /// Unmount a pack by name. Refused while a world of the pack is loaded or
85 /// any object under "/<Name>/" survives a garbage collection.
86 bool Unmount(const FString &Name, FString &OutError);
87
88 const TArray<FCarlaContentPack> &GetPacks() const { return Packs; }
89
90 const FCarlaContentPack *FindPack(const FString &Name) const;
91
92 /// Long package name of a map declared by a mounted pack, or empty.
93 FString FindMapPackage(const FString &MapName) const;
94
95 /// Map names declared by all mounted packs.
96 TArray<FString> GetPackMapNames() const;
97
98 /// Content dirs of all mounted packs, in mount order.
99 TArray<FString> GetPackContentDirs() const;
100
101 /// <ContentDir>/Config/<RelativeName> of every mounted pack where the file
102 /// exists, in mount order (later packs override earlier ones by id).
103 static TArray<FString> FindPackCatalogFiles(const FString &RelativeName);
104
105 /// Merge catalog entries: an entry whose key already exists replaces it in
106 /// place (later files override by id), new keys are appended.
107 template <typename T, typename KeyFn>
108 static void MergeCatalog(TArray<T> &Into, const TArray<T> &From, KeyFn Key)
109 {
110 for (const T &Entry : From)
111 {
112 const FString EntryKey = Key(Entry);
113 const int32 Existing = Into.IndexOfByPredicate([&](const T &Other)
114 {
115 return Key(Other).Equals(EntryKey, ESearchCase::IgnoreCase);
116 });
117 if (Existing != INDEX_NONE)
118 {
119 Into[Existing] = Entry;
120 }
121 else
122 {
123 Into.Add(Entry);
124 }
125 }
126 }
127
128 /// Base release stamp of this binary (<ProjectDir>/BaseRelease), empty in
129 /// editor/dev builds.
130 static FString GetBaseReleaseStamp();
131
132 FCarlaContentPackEvent OnPackMounted;
133
134 FCarlaContentPackEvent OnPackUnmounted;
135
136private:
137
138 bool CheckCompatibility(const FCarlaContentPackManifest &Manifest, FString &OutError) const;
139
140 bool MountPaks(FCarlaContentPack &Pack, FString &OutError);
141
142 void UnmountPaks(FCarlaContentPack &Pack);
143
144 bool MountPlugin(FCarlaContentPack &Pack, FString &OutError);
145
146 void RegisterAssetRegistry(FCarlaContentPack &Pack);
147
148 /// The pack map or one of its levels is loaded in some world (no GC).
149 bool IsPackInUse(const FCarlaContentPack &Pack, FString &OutReason) const;
150
151 /// Objects under "/<Pack>/" survive a garbage collection (GC only runs
152 /// when something from the pack was loaded at all).
153 bool ArePackObjectsAlive(const FCarlaContentPack &Pack, FString &OutReason);
154
155 TArray<FString> GetDiscoveryDirs() const;
156
157 TArray<FCarlaContentPack> Packs;
158
159 bool bDiscovered = false;
160};
DECLARE_MULTICAST_DELEGATE_OneParam(FCarlaContentPackEvent, const FCarlaContentPack &)
Mounts CARLA content packs (content-only Unreal plugins cooked as DLC against a base release,...
const TArray< FCarlaContentPack > & GetPacks() const
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...
TArray< FCarlaContentPack > Packs
FCarlaContentPackEvent OnPackMounted
FCarlaContentPackEvent OnPackUnmounted
Parsed carla-pack.json.
A content pack known to the manager (discovered or mounted explicitly).
FString ContentDir
Absolute path of the plugin content dir (<PackDir>/Content), the filesystem side of the "/<Name>/" mo...
FString PluginFile
Absolute path of <PackDir>/<Name>.uplugin.
const FString & GetName() const
FString PackDir
Absolute pack directory (contains carla-pack.json and <Name>.uplugin).
FCarlaContentPackManifest Manifest
TArray< FString > MountedPaks
Pak files mounted for this pack (cooked builds only).