The Unreal Engine 5 client¶
ValdradaUE is Valdrada built as a downloadable Unreal Engine 5 application. Like CARLA, it is started from a launcher and driven from Python; nothing has to be compiled. It runs as two processes. The headless core (a bundled Node runtime) holds the city model and the simulation (traffic, pedestrians, signals, trains) and serves the Python API on port 2000. The renderer, an Unreal Engine 5 application, connects to the core on the same port, streams the city's cells round the cameras the core names, draws the core's state at every tick and returns the camera images, which the core hands to the Python client. Scripts written for the three.js build run unchanged against it: the API and the wire protocol (protocol.md) are the same, and only the renderer differs. How the renderer and the core talk is specified in render-protocol.md.
For building the application and its content from source, see Building the Unreal Engine 5 client.
System requirements¶
| Component | Requirement |
|---|---|
| Operating system | Linux x86-64 (tested on Ubuntu 22.04, kernel 6.8). Release 0.5.1 ships the Linux build only; on Windows 10/11 x64 the client is built from source as the build guide describes |
| GPU | A GPU with hardware ray tracing and 64-bit atomics for Nanite and Lumen: NVIDIA RTX (Turing or newer) or AMD Radeon RX 6000 or newer. Tested on NVIDIA RTX 6000 Ada (48 GB), where that run used 15.3 GB of GPU memory |
| Driver | Linux: the NVIDIA proprietary driver with its Vulkan ICD (tested with 580.159.03). Windows: a current vendor driver with Direct3D 12 |
| Memory | 16 GB or more: in a run at 1280 × 720 with two places loaded, the renderer held 13.1 GB and the core 0.8 GB |
| Disk | Linux: 52.3 GB installed (the renderer's content 32.8 GB, the kit tables 15.5 GB, the core with the city's tiles 3.7 GB); the download is kept until the install has finished, and the script asks for 88 GB free |
| Python | 3.8 or later for the valdrada package; numpy is optional and used by most examples |
| Network | The download, 35.4 GB in 32 files for Linux; afterwards none, unless the core and the renderer run on different machines |
The core alone (--core-only) needs no GPU: it simulates, answers map queries and moves actors, and answers sensor
requests with the error needs_renderer until a renderer is attached.
Download and verify¶
A release consists of a manifest, ValdradaUE-<version>-<platform>.json, and the files it lists, published as assets
of the GitHub release and mirrored in the Hugging Face dataset
mehmetkeremturkcan/valdrada-ue. fetch_valdrada_ue.py, published with them, downloads every file, resumes
interrupted downloads, checks each file against the SHA256 of the manifest, joins files that were published in parts
and unpacks the archives. It needs Python 3.8 or later and nothing else.
curl -LO https://github.com/mkturkcan/valdrada/releases/latest/download/fetch_valdrada_ue.py
python3 fetch_valdrada_ue.py # the latest release for this system, into ./ValdradaUE-<version>-<platform>
python3 fetch_valdrada_ue.py --version 0.5.1 --dest ~/ValdradaUE
python3 fetch_valdrada_ue.py --mirror huggingface # from the Hugging Face copy
On Windows, once a Windows build is published (release 0.5.1 has none; build it as the build guide describes), in PowerShell:
Invoke-WebRequest https://github.com/mkturkcan/valdrada/releases/latest/download/fetch_valdrada_ue.py -OutFile fetch_valdrada_ue.py
python fetch_valdrada_ue.py
The script checks the free disk space first. Files that fail their check are downloaded again on the next run; nothing
that fails a check is installed. Files downloaded by hand (into one folder, all of those the manifest names) are
checked and installed with --from-dir <folder>; sha256sum -c ValdradaUE-<version>-<platform>-SHA256SUMS.txt checks
them without installing. After installing, python3 fetch_valdrada_ue.py --verify --dest <folder> checks the content
files again.
| File | Contents |
|---|---|
ValdradaUE-<v>-<platform>.json |
the manifest: every file, its size and SHA256, where it is installed |
ValdradaUE-<v>-<platform>-base.tar.gz (Windows: .zip) |
the launcher, the Python package and examples, the licences, and the renderer application without its content |
ValdradaUE-<v>-<platform>-core.tar.xz (Windows: .zip) |
the headless core with its Node runtime and the compiled city's tiles |
ValdradaUE-<v>-<platform>-pakchunk<N>-<Platform>.*, ...-global.* |
the renderer's cooked content: Unreal IoStore containers in partitions of at most 1,900 MiB |
ValdradaUE-<v>-tables.tar.xz |
the kit tables the renderer assembles the buildings' parts from (shared by both platforms) |
ValdradaUE-<v>-<platform>-SHA256SUMS.txt |
the checksums, for checking by hand |
The installed folder:
| Path | Contents |
|---|---|
ValdradaUE.sh, ValdradaUE.bat |
the launcher |
core/ |
the core: node/ (Node.js 24.19.0) and app/ (the simulation, the API server and the city's tiles) |
renderer/ |
the Unreal Engine application; its content in renderer/ValdradaUE/Content/Paks/, the city manifest and the kit tables in renderer/ValdradaUE/Data/ |
PythonAPI/ |
the valdrada package and the examples |
logs/ |
the last run's core.log, the renderer's console output renderer.out, and renderer.log from a renderer built with logging (the Development package) |
Run¶
The launcher starts the core, waits until its world is ready, starts the renderer connected to it, and stops both when
either exits, on Ctrl+C or on SIGTERM. Measured on Linux with an RTX 6000 Ada: the core is ready in 4 to 9 s and the
renderer attached 8 s after the start; the cells round W 120th St and Amsterdam Ave were loaded 58.5 s later, and a tick
with an RGB and a depth camera at 1280 × 720 then took 0.25 s. A place far from the last one takes longer: Times Square
was still loading when world.wait_until_loaded() returned at its default limit of 180 s.
| Option | Default | |
|---|---|---|
--port N |
2000 | the API port; the renderer connects to the same port |
--host ADDR |
127.0.0.1 | the address the core listens on (0.0.0.0 to accept other machines) |
--res WxH |
1280x720 | the window and the default RGB camera size |
--quality Q |
high | low, medium, high or cinematic: the renderer's tier and the core's crowd detail |
--offscreen |
off | render without a window (servers, containers) |
--fullscreen |
off | a full screen window |
--gpu N |
the GPU the renderer uses (0 is the first) | |
--time T |
day | day, golden, dusk or night |
--start-lat, --start-lon |
40.80955, -73.95905 | where the city streams in first (W 120th St and Amsterdam Ave) |
--seed N |
1 | the simulation's random seed |
--pedestrians P |
photoreal | procedural for the built-in pedestrian variants |
--core-only |
start only the core | |
--renderer-only |
start only the renderer; --core-host ADDR names the core |
|
--log-dir DIR |
logs/ |
where the logs go |
-- <arguments> |
passed to Unreal unchanged |
The core and the renderer can run on different machines: ./ValdradaUE.sh --core-only --host 0.0.0.0 on one, and
./ValdradaUE.sh --renderer-only --core-host <address> on the other; Python clients connect to the core.
Connect from Python¶
import valdrada
client = valdrada.Client("localhost", 2000)
world = client.get_world()
m = world.get_map()
here = m.geolocation_to_location(40.80955, -73.95905)
world.wait_until_loaded() # the core's cells and the renderer's
lib = world.get_blueprint_library()
car = world.spawn_actor(lib.find("vehicle.taxi2"), m.get_spawn_points(center=here, radius=100)[0])
car.set_autopilot(True)
cam = world.spawn_actor(lib.find("sensor.camera.rgb"), valdrada.Transform(valdrada.Location(-6, 0, 3), valdrada.Rotation(pitch=-12)), attach_to=car)
cam.listen(lambda image: image.save_to_disk(f"_out/{image.frame:06d}.png"))
for _ in range(200):
world.tick()
The examples of the three.js build (quickstart.py, intersection_120_amsterdam.py, generate_traffic.py,
benchmark.py, the tutorials) run as they are, within the sensor outputs listed below. Getting
started and the Python API reference apply unchanged.
world.wait_until_loaded() returns once the core's cells are in and the renderer reports nothing pending.
Differences from the three.js build¶
The simulation, the actors, the map queries and the API are the core's and therefore identical. What differs is what the renderer draws and which sensor outputs it serves.
| three.js build | Unreal Engine 5 build (this release) | |
|---|---|---|
| RGB camera | yes | yes: Lumen, Nanite, virtual shadow maps, hardware ray tracing |
| Depth camera | yes | yes |
| Semantic segmentation | yes | yes, except the ground: roads, sidewalks and kerbs are one mesh and return the unlabelled class |
| Instance segmentation, boxes and poses | yes | not yet: the request is answered with unsupported_output |
| City | the five boroughs, streamed as 512 m tiles | the five boroughs: 1 km blocks of 128 m cells near the cameras, far chunks of 1 to 8 km beyond |
| Vehicles | the modelled fleet | the fleet's meshes for all 23 kinds, drawn rigid: wheels do not turn and lamps are not lit |
| Pedestrians | photoreal or procedural bodies | capsule stand-ins |
| Trains | the modelled sets | boxes of the cars' size |
| Time of day | day, golden, dusk, night | the same four; at night windows and lamp heads glow, but street lamps cast no light |
| Rain | drawn | not drawn |
| Platforms | Windows x64 (Electron), Linux | Linux x86-64; Windows x64 when built as in the build guide |
Problems¶
| Problem | Fix |
|---|---|
port 2000 is in use |
Another server runs: stop it, or start with --port 2001 and connect to that port |
| The renderer exits at once on Linux | Install the NVIDIA driver's Vulkan component (vulkaninfo lists the GPU); see logs/renderer.out and logs/renderer.log |
Sensors answer needs_renderer |
The renderer is not connected: logs/core.log names each renderer that attaches; see the renderer's logs, or start without --core-only |
Sensors answer unsupported_output |
The output is not served by this renderer yet (see the table above) |
| A download keeps failing its check | Run the script again: it resumes and fetches failed files anew; --mirror huggingface uses the other copy |
Licensing¶
The renderer in renderer/ is built with Unreal Engine and is distributed in object code under the Unreal Engine End
User License Agreement (https://www.unrealengine.com/eula); UNREAL_ENGINE_NOTICE.md in the package holds the notice
the agreement asks for. The repository's code, including the launcher, the core and the renderer's source, is MIT
licensed; the compiled city and the models keep the licences listed in LICENSING.md.