Skip to content
Back to skills

Import Carla Ue58 Map

ASecurity

Gets a custom map into CARLA on UE 5.8 — the four distinct routes and which one to pick — via Util/Tools/Import.py for FBX+OpenDRIVE assets into a source build, CARLA_MAPS_TO_COOK to ship a map inside a package, or client.generate_opendrive_world() for an OpenDRIVE-only map at runtime with no build at all. Covers where imported assets land, why an imported map cannot be loaded from a package by name, and the four capabilities the UE4 skill has that ue58 lacks — standalone asset packages, thei...

  • 14,461 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 6, 2026
ai-agentspythongoshellbashdockerapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 6, 2026

npx -y skills add carla-simulator/carla --skill import-carla-ue58-map --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Import Carla Ue58 Map?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Import Carla Ue58 Map
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/carla-simulator-import-carla-ue58-map-carla/badge)](https://www.skillsdirectory.com/skills/carla-simulator-import-carla-ue58-map-carla)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: import-carla-ue58-map
description: Gets a custom map into CARLA on UE 5.8 — the four distinct routes and which one to pick — via Util/Tools/Import.py for FBX+OpenDRIVE assets into a source build, CARLA_MAPS_TO_COOK to ship a map inside a package, or client.generate_opendrive_world() for an OpenDRIVE-only map at runtime with no build at all. Covers where imported assets land, why an imported map cannot be loaded from a package by name, and the four capabilities the UE4 skill has that ue58 lacks — standalone asset packages, their installer, semantic-material tagging, and a pedestrian navmesh that is generated but silently skipped. Use when the user asks to "import a map", "add a custom map", "load my .xodr", "package my own town", or "create a standalone map package".
license: MIT
compatibility: Linux with a built ue58-dev tree; the editor commandlets need CARLA_UNREAL_ENGINE_PATH and an importable `carla` client. The OpenDRIVE-only route needs only a running server. VERIFIED end to end on ue58-dev HEAD 718efd7cc, engine 5.8.0 - Route B was run with a real RoadRunner pair (31.7 MB FBX + 515 KB OpenDRIVE 1.4), producing a map that loads on a server with 24 spawn points, 80 topology edges, 80 crosswalks and 36 landmarks, and on which a vehicle spawns and resolves to a lane. Route A (cook scope) and Route C (runtime OpenDRIVE) were verified earlier. The pedestrian nav mesh is NOT produced - see the gap below.
metadata:
  group: ue58
  prerequisites: scripts/check_env.sh
  reference: references/maps.md
---

# Get a map into CARLA on UE 5.8

> **Paths.** `scripts/…` and `references/…` below are relative to the
> directory holding this SKILL.md. Your working directory is the user's
> project, not that directory, so prefix them with its absolute path or the
> command is not found.

Four different things get called "adding a map", and picking the wrong one wastes
hours. They are not variations of one procedure:

| Route | What you need | Build step | Result |
|---|---|---|---|
| **A. Cook into a package** | the map already in `Content` | `package` target, 1–2 h | map ships inside the `.pak` |
| **B. Import into a source build** | `.fbx` + `.xodr` | editor commandlets, minutes | map in `Content`, usable in the editor |
| **C. OpenDRIVE at runtime** | just a `.xodr` | **none** | procedural road mesh, no scenery |
| **D. Standalone asset package** | — | — | **does not exist on ue58-dev** |

Route D is the UE4 `make package ARGS="--packages=Name"` flow, and it is gone in
both directions — nothing builds such a package and nothing installs one. The docs
that described it (`tuto_A_create_standalone.md`, `tuto_M_add_map_package.md`) are
**absent from this tree**: `Docs/maps_tutorials.md` and
`Docs/custom_assets_tutorials.md` link to 10 files that do not exist. Do not plan
around it — the section below lists this and the three other UE4 capabilities with
no ue58 equivalent.

## What the UE4 skill does that this one cannot

Read this before promising a user anything the UE4 flow could do. Four
capabilities of [[import-carla-map]] have **no equivalent on ue58-dev**, all
verified against both trees:

| UE4 capability | UE4 mechanism | ue58 state |
|---|---|---|
| Build a standalone, distributable asset package | `Util/BuildTools/Package.sh --packages=Name1,Name2` | **gone** — no `Package.sh`; the only targets are whole-server (`package`, `packageShipping`, `packageDebug`, `packageDebugGame`, `packageDevelopment`, `packageTest`, `Unreal/CMakeLists.txt:546-551`), scoped only by `CARLA_MAPS_TO_COOK` |
| Install such a package into an existing release | `Util/ImportAssets.sh`, shipped at the release root | **gone** — a built ue58 package root holds only `CHANGELOG LICENSE Linux PythonAPI README Tools VERSION` |
| Tag materials so imported geometry is segmented | `-run=GenerateTaggedMaterialsRegistry -PackageNames=…`, run by `Package.sh` per package | **gone** — the commandlet exists in 2 UE4 plugin files and **0** here, so `semantic_tags` comes back empty on imported assets ([[import-carla-ue58-prop]] hits the same wall) |
| Generate the pedestrian navmesh on import | `Util/DockerUtils/dist/` ships `RecastBuilder`; `build.sh` runs `FBX2OBJ` then `RecastBuilder` | **silently does nothing** — see below |

### The navmesh gap is silent, and it is the one that bites

`Import.py:487 build_binary_for_navigation` shells out to
`Util/DockerUtils/dist/build.sh`, whose every step is guarded:

```bash
if [ -f "FBX2OBJ" ]; then …
if [ -f "RecastBuilder" ]; then …
```

UE4 ships `RecastBuilder` in that folder. ue58's `dist/` contains only
`addOBJ.py`, `build.bat`, `build.sh`, `get_xodr_crosswalks.py`. CMake *does* build
RecastBuilder — to `Build/<preset>/_deps/recastnavigation-build/RecastBuilder/` and
into packages as `Tools/RecastBuilder` — but **nothing copies it into `dist/`**, and
no CMake target references `DockerUtils` at all. `FBX2OBJ` has its own
`Util/DockerUtils/fbx/CMakeLists.txt` that the main build never adds, and no binary
exists under `Build/`. So the import runs, exits 0, writes no `.bin`, and walkers
cannot navigate the new map — with no warning anywhere.

Work around it by putting both binaries where `build.sh` looks:

```bash
cp "$(find "${CARLA_UE58_ROOT}/Build" -name RecastBuilder -type f | head -1)" \
   "${CARLA_UE58_ROOT}/Util/DockerUtils/dist/"
# FBX2OBJ must be built first: it is a standalone CMake project needing the FBX SDK
# cmake -S Util/DockerUtils/fbx -B /tmp/fbx2obj && cmake --build /tmp/fbx2obj
```

**Route C is unaffected.** `CarlaEpisode.cpp:45 BuildRecastBuilderFile()` prefers
`<RootDir>/Tools/RecastBuilder` and falls back to the compiled-in
`RECASTBUILDER_PATH`, so a runtime OpenDRIVE world gets its navmesh properly.

### What is NOT missing

`Util/Tools/Import.py` is UE4's `Util/BuildTools/Import.py` with paths renamed —
the whole diff is **24 lines** (`UE4_ROOT`→`CARLA_UNREAL_ENGINE_PATH`,
`UE4Editor`→`UnrealEditor`, `CarlaUE4`→`CarlaUnreal`, `is not`→`!=`, two imports).
Every function is identical, and the three commandlets it needs —
`PrepareAssetsForCooking`, `MoveAssets`, `LoadAssetMaterials` — are all present.
That is why Route B works at all.

The `.Package.json` format also lingers without its pipeline: `Import.py:276
generate_package_file` still writes one, and `Content/Carla/Config` still holds
`Town06_Opt.Package.json` and friends, but nothing on ue58 cooks or loads them.

## Instructions

```
Progress:
- [ ] Step 1: Check prerequisites (bash scripts/check_env.sh)
- [ ] Step 2: Pick a route (A / B / C) — see the decision below
- [ ] Step 3: Run it
- [ ] Step 4: Verify the map actually loads
```

### Step 2: Which route

**Only have a `.xodr`, and want roads to drive on?** Route C. No build, seconds,
works against any running server. You get a procedurally generated road mesh and
nothing else — no buildings, no props, no scenery.

**Have `.fbx` geometry and want it in the editor?** Route B, then Route A if you
also need it in a package.

**Map already in `Content` and you want it shipped?** Route A alone.

### Route C — OpenDRIVE only, no build

```bash
source scripts/env.sh
bash scripts/import_map.sh opendrive /path/to/MyTown.xodr
```

which is `client.generate_opendrive_world(xodr_string, params)`. Tunable through
`carla.OpendriveGenerationParameters`: `vertex_distance`, `max_road_length`,
`wall_height`, `additional_width`, `smooth_junctions`,
`enable_mesh_visibility`.

This is the fastest way to test a road network, and the only route that needs no
engine at all. It is also the only one where the map is **not** persisted: it
lives for the session.

### Route B — import FBX + OpenDRIVE into a source build

Lay the assets out under `Import/`:

```
Import/
├── MyTown.fbx          # geometry; name must match the .xodr
├── MyTown.xodr         # road network
└── MyPackage.json      # OPTIONAL - generated if absent
```

then:

```bash
source scripts/env.sh
bash scripts/import_map.sh plan   --package MyPackage    # what will happen, no changes
bash scripts/import_map.sh import --package MyPackage
```

**Do not use `Util/Tools/Import.sh`.** It is broken on this branch:
`Util/Tools/Environment.sh` never sets `CARLA_BUILD_TOOLS_FOLDER`, so its last
line runs `python3 /Import.py`:

```
$ bash Util/Tools/Import.sh --help
parse-options: unrecognized option '--help'
/usr/bin/python3: can't open file '/Import.py': [Errno 2] No such file or directory
$ echo $?
2
```

(`--help` is also missing from its `getopt` list, which is the first line of that
output. The exit code is 2 because `Environment.sh` runs `set -e`; measure it
directly, not through a pipeline, or you will read the exit code of the last
command in the pipe.) Call `Util/Tools/Import.py` directly, which is what this
skill's script does.

What the pipeline does, in order:

1. scans `Import/` for package `.json` files; generates one if none exist,
2. writes `importsetting.json` for the `ImportAssets` commandlet,
3. runs the editor commandlets: `ImportAssets` → `LoadAssetMaterials` →
   `PrepareAssetsForCooking` → `MoveAssets`,
4. **tries** to build the navigation mesh with `RecastBuilder` from
   `Util/DockerUtils/dist` — and silently does nothing, because ue58 ships
   neither `RecastBuilder` nor `FBX2OBJ` there and `build.sh` guards both steps
   with `if [ -f ... ]`. `plan` prints the copy/build commands that fix it,
5. builds the Traffic Manager cache via `carla.Map(...).cook_in_memory_map()` —
   which is why `Import.py` needs an importable `carla` client,
6. writes the package descriptor.

**A measured run**, with a real RoadRunner export (`TestMap.fbx` 31.7 MB binary
FBX + `TestMap.xodr` 515 KB, OpenDRIVE 1.4, RoadRunner 2019.2):

```
Import.py exited 0, ~55 s, four commandlets in sequence
  Content/TestMapPkg/Maps/TestMap/TestMap.umap
  Content/TestMapPkg/Maps/TestMap/OpenDrive/TestMap.xodr
  Content/TestMapPkg/Maps/TestMap/TM/TestMap.bin
  Content/TestMapPkg/Config/TestMapPkg.Package.json   ("maps": 1, "props": 0)
  Content/TestMapPkg/Static/{Road,RoadLine,SideWalk,Terrain}
server: get_available_maps() lists TestMap (30 maps); load_world("TestMap") ->
  24 spawn points, 80 topology edges, 80 crosswalks, 36 landmarks;
  a vehicle spawns and resolves to road 2 / lane -1
NO Nav/TestMap.bin — walkers cannot navigate it (the step-4 gap above)
```

Two log errors are expected noise on a clean run: `LogAutomatedImport: Error:
Invalid Destination Path ()` appears twice, from the empty props list in the
generated descriptor, and does not affect the map. `FBXImport: Warning: No
smoothing group information` reflects the exporter's settings, not the import.

Where things land — **this is the part that decides whether Route A will work
afterwards**:

```
Content/<Package>/Maps/<MapName>              the .umap        -> /Game/<Package>/Maps/<MapName>
Content/<Package>/Maps/<MapName>/TM/<Map>.bin Traffic Manager cache
Content/<Package>/Config/<Package>.Package.json   descriptor
```

### Route A — cook a map into a package

```bash
cd ../build-carla-ue58
MAPS="Town10HD_Opt,MyTown" bash scripts/build.sh configure
cd ../package-carla-ue58 && bash scripts/package.sh build
```

`MAPS=` takes town names and expands them to `+`-separated package paths. For a
map outside `/Game/Carla/Maps` pass the full package path:

```bash
MAPS="/Game/Carla/Maps/Town10HD_Opt,/Game/MyPackage/Maps/MyTown" \
    bash ../build-carla-ue58/scripts/build.sh configure
```

**A cooked imported map still may not load by name.** `UCarlaStatics::FindMapPath`
first does a filesystem `FindFilesRecursive("*.umap")`, which finds nothing inside
a `.pak`, then falls back to exactly one package path:

```cpp
const FString ProjectMapPackage = FString::Printf(TEXT("/Game/Carla/Maps/%s"), *MapName);
if (FPackageName::DoesPackageExist(ProjectMapPackage)) return ProjectMapPackage;
```

So from a package, `load_world("X")` resolves **only** if the map sits at
`/Game/Carla/Maps/X`. An imported map at `/Game/MyPackage/Maps/MyTown` does not,
and neither does a nested large map at `/Game/Carla/Maps/Town12/Town12` —
measured: `load_world('Town12')` raises `std::exception` from a package while
`load_world('Town_C')` works.

**Consequence:** to be loadable from a package, an imported map must end up under
`/Game/Carla/Maps/<Name>`. In the editor it works from anywhere, because the
filesystem search succeeds there.

### Step 4: Verify

```bash
bash scripts/import_map.sh verify --map MyTown
```

Checks `Content` for the `.umap`, the `.xodr`, the TM cache and the nav mesh,
reports the package path the map will have, whether that path is loadable from a
package, and — if a server is up — whether it appears in `get_available_maps()`
and loads.

## Examples

**Example 1: "I have a .xodr, show me the road network"**

Route C: `bash scripts/import_map.sh opendrive MyTown.xodr` against a running
server. Seconds, no build. Roads only.

**Example 2: "import my town with buildings"**

Route B into `Import/`, then open the editor
([[run-carla-ue58-server]] `editor`) and check it there first — the editor finds
maps anywhere in `Content`, so this isolates import problems from packaging ones.

**Example 3: "ship my imported map in a package"**

Route B, then move/import it so it lands under `/Game/Carla/Maps/<Name>`, then
Route A with `MAPS="...,<Name>"`. Verify with
[[package-carla-ue58]] `inspect` that its `.xodr`/`TM` staged — per-map
subdirectories are **not** in `DirectoriesToAlwaysStageAsUFS`, which is the same
gap that leaves Town12/Town13 without road data.

**Example 4: "make a standalone map package to give someone"**

Not available on ue58-dev (Route D). Options: ship the whole package, or give them
the `.xodr` and let them use Route C.

## Troubleshooting

**Problem: `python3: can't open file '/Import.py'`**
Cause: `Util/Tools/Import.sh` — `CARLA_BUILD_TOOLS_FOLDER` is unset in
`Environment.sh`, and the script still exits 0.
Solution: run `Util/Tools/Import.py` directly.

**Problem: `ModuleNotFoundError: No module named 'carla'` from Import.py**
Cause: it imports `carla` at module scope for the TM cache
(`carla.Map(...).cook_in_memory_map()`).
Solution: install the wheel — [[build-carla-ue58]] `pythonapi`.

**Problem: the import runs but the map is not in the editor**
Cause: the commandlets failed while `Import.py` continued — it uses
`subprocess.call` for the POSIX path and does not check the return code.
Solution: read the commandlet output; `plan` prints the exact commands so you can
run one by hand.

**Problem: `KeyError: 'xodr'` or nav/TM steps skipped**
Cause: the generated package JSON has no `xodr`/`source` for the map, so
`build_binary_for_navigation` `continue`s and no nav mesh is produced.
Solution: name the `.xodr` exactly like the `.fbx`, or write the package `.json`
by hand.

**Problem: imported map works in the editor, `load_world` fails from a package**
Cause: the pak fallback only checks `/Game/Carla/Maps/<Name>`.
Solution: get the map to that path, or use the editor / `-game` mode.

**Problem: imported map loads but has no traffic and walkers cannot spawn**
Cause: missing TM cache or navigation mesh. Town_C ships without either, so this
is not unique to imported maps.
Solution: `verify` reports both; re-run the import with a matching `.xodr`.

**Problem: instance segmentation tags are wrong for imported assets**
Cause: the `GenerateTaggedMaterialsRegistry` commandlet that UE4's packaging ran
across packages does not exist in this tree.
Solution: no in-tree equivalent; tag materials manually.

## Outputs

Route A: a map cooked into `Build/<preset>/Package/...`. Route B: assets under
`Content/<Package>/` plus a `.Package.json` descriptor, a TM cache and a nav mesh.
Route C: a world that exists only for the session. `plan` and `verify` are
read-only.

The route taxonomy, the exact import output paths, map-discovery code paths and the
staging implications are in [references/maps.md](references/maps.md).

Files in this skill

  • SKILL.md15.7 KB
  • references/maps.md12.3 KB
  • scripts/check_env.sh7.9 KB
  • scripts/env.sh5 KB
  • scripts/import_map.sh11.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…