0.1.3 packaging and setup fixes from what 0.1.x actually exposed. - New Tools/ue_common.py: make_writable() clears the read-only bit an LFS .umap checks out with (save_map() otherwise returns False silently and the staged actor is lost) and require_saved() makes that failure visible. ue_hero_facade_import and ue_import_north_buildings now call it; the map builders already did. Verified from a forced 0o444 map: chmod logged, save_map True, exit 0. - Docs/build.md: pipeline table now lists the seven site FBXs plus frontage, north, hero and map steps and the shared FBX preset; packaging archive corrected to Builds/GigLineQA; packaged-log location and -qaselftest usage documented; new 'Traps that cost real time in 0.1.x' table (read-only save, hero --out is the FBX, MPFB add-on path, shot actor quitting under QA, null-RHI trace trap). - Docs/setup.md: fresh-checkout build marked verified 2026-11-08 and the blocker closed; new optional-keys section for OPENROUTER_API_KEY and MAPBOX_ACCESS_TOKEN (gitignored .env, not needed by build/tests/release). - Docs/Architecture 07 + architecture.md: build-output path corrected, marked outside the repository. - 5 new tests for ue_common (54 total).
9.4 KiB
Build
Fresh-checkout build, content-pipeline and packaging procedure for the walkable demo. Begun 2026-11-07 from a blank build and extended through the 0.1.x patches; the release checks that exercise it are in release-checks.md.
Constraints
- Engine installation is external to the repository. Record its path and exact version in toolchain.md.
- Build output (
Binaries/,Intermediate/,Saved/,DerivedDataCache/) is never committed. - Large content is LFS-tracked, so a fresh clone needs
git lfs install && git lfs pullbefore any build.
Engine
Pinned install: Unreal Engine 5.8.4 (CL 58902052, promoted build) at /run/media/system/DATA/Engines/UE_5.8.4. The engine bundles no Linux clang; the system clang (23.1.4, Fedora 45) is the game-code toolchain. Game targets must use BuildSettingsVersion.V7 to share the installed editor's build environment.
Fresh-checkout build
git clone <remote> gig-line && cd gig-line
git lfs install && git lfs pull
Tools/check-lfs.sh # must pass before any content build
# Compile the project's editor target (first build also proves the toolchain)
cd /run/media/system/DATA/Engines/UE_5.8.4
Engine/Build/BatchFiles/Linux/Build.sh GigLineEditor Linux Development \
-project="$PWD/../../Documents/06-games/gig-line/Game/GigLine/GigLine.uproject" \
-WaitMutex
# Expected tail: "Result: Succeeded"; module binary lands in
# Game/GigLine/Binaries/Linux/libUnrealEditor-GigLine.so
# Open in the editor (GUI, Vulkan)
./Engine/Binaries/Linux/UnrealEditor \
/run/media/system/DATA/Documents/06-games/gig-line/Game/GigLine/GigLine.uproject
Adapt the -project= path to the actual checkout location.
Package a Linux build
cd /run/media/system/DATA/Engines/UE_5.8.4
Engine/Build/BatchFiles/RunUAT.sh BuildCookRun \
-project="/run/media/system/DATA/Documents/06-games/gig-line/Game/GigLine/GigLine.uproject" \
-noP4 -platform=Linux -clientconfig=Development \
-cook -build -stage -pak \
-archive -archivedirectory="/run/media/system/DATA/Builds/GigLineQA" \
-unattended
# Expected: "AutomationTool exiting with ExitCode=0 (Success)" and "EXIT=0", ~90 s
# Launch test (plain, no -map): /run/media/system/DATA/Builds/GigLineQA/Linux/GigLine.sh
Launch test must open the DemoMap. A plain ./GigLine.sh should load /Game/Hollywood/DemoMap (set via DefaultEngine.ini GameMapsSettings). If it instead opens /Engine/Maps/Templates/OpenWorld, the game shows an empty non-interactive "stuck" scene — check that GameDefaultMap is in DefaultEngine.ini, not DefaultGame.ini. Confirm the loaded map in the engine log: .../Linux/GigLine/Saved/Logs/GigLine.log (LoadMap: /Game/Hollywood/DemoMap). The archive directory is deliberately outside the repository; never archive into the checkout.
Headless content checks
Both content-acceptance tests run headless and are the template for all asset import verification:
# Static-mesh scale test (Blender export -> Unreal import -> measure)
# Blender: Tools/scale_test_export.py, Unreal: Tools/ue_scale_test_import.py
# MPFB character (generate -> rig -> bake -> export -> skeletal import)
# Blender: Tools/mpfb_character_export.py, Unreal: Tools/ue_character_import.py
# Unreal side of any test:
./Engine/Binaries/Linux/UnrealEditor-Cmd \
/run/media/system/DATA/Documents/06-games/gig-line/Game/GigLine/GigLine.uproject \
-run=pythonscript -script=<repo>/Tools/<script>.py -nullrhi -unattended -nopause -stdout
# Note: 5.8 swallows Python print() in the commandlet; scripts write result files to /tmp.
Content pipeline (current)
The hero block and the demo level are built by a fixed sequence. Each step writes a result file under /tmp/gigline/; read it, because the commandlet's own stdout can be swallowed.
| Step | Tool | Output |
|---|---|---|
| OSM blockout | Art/blender/blockout/blosm_blockout.py |
Art/blender/blockout/blockout-*.blend |
| Terrain | Art/blender/terrain/terrain_from_dem.py |
Art/blender/terrain/terrain-*.blend |
| Street | Art/blender/street/street_mesh.py |
Art/blender/street/street-*.blend |
| Site assembly | Art/blender/site/site_assembly.py |
Art/blender/site/site-*.blend |
| Site export | Art/blender/site/export_site_fbx.py |
seven FBXs, one per mesh (terrain, road, both sidewalks, both kerbs, crossing) |
| Hero façade | Tools/hero_facade_build.py |
Art/blender/hero/hero-facade-*.blend + JSON part report |
| Block frontage | Tools/export_block_frontage.py |
six frontage FBXs from the blockout |
| North buildings | Tools/export_north_buildings.py |
TCL and Tussaud's FBXs from the blockout |
| Site import | Tools/ue_import_site.py |
/Game/Hollywood/Site/* |
| Frontage import | Tools/ue_import_block_frontage.py |
/Game/Hollywood/Frontage/* |
| North import | Tools/ue_import_north_buildings.py |
/Game/Hollywood/North/* |
| Hero import | Tools/ue_hero_facade_import.py |
/Game/Hollywood/ElCapitan/SM_HeroFacade |
| Demo map | Tools/ue_build_demo_map.py |
/Game/Hollywood/DemoMap |
| Review shots | Tools/ue_build_review_map.py + Tools/render_screenshots.sh |
Screenshots/ |
Every Blender exporter calls Tools/fbx_export_preset.py (ue_metric_v1 / ue_character_v1) instead of repeating the FBX argument block — one place for the scale conversion, the axis mapping and mesh_smooth_type="FACE" (without which every Unreal import warns about missing smoothing groups and round geometry arrives faceted).
Two rules that the pipeline enforces rather than documents:
- One conversion. Metres to Unreal centimetres happens only in
Geo/tools/osm_common.py::to_unreal_local. Sidecars (<asset>.geo.json) record the result andGeo/tools/asset_metadata.py auditre-derives it. - Collision is decided at import, not later: terrain, road and sidewalks are complex-as-simple; kerbs and props stay simple. A simple hull over a kerbed street ramps straight across the kerb.
Known engine quirks (2026-11-07)
- One handled
PSOPrecacheensure fires at packaged-build exit only; not blocking. - Interchange 5.8 does not create material/texture assets for skeletal FBX imports —
Tools/ue_character_import.pyfinishes that chain explicitly. - Android Turnkey status errors and datarouter DNS warnings in logs are benign.
Packaged Linux build
Current QA archive: /run/media/system/DATA/Builds/GigLineQA. A plain ./GigLine.sh opens /Game/Hollywood/DemoMap; controls are in controls.md and shown in-game bottom-right. The packaged log is written relative to the wrapper's working directory, i.e. <archive>/Linux/GigLine/Saved/Logs/GigLine.log — not into the repository.
Behaviour check without a human at the keyboard:
cd /run/media/system/DATA/Builds/GigLineQA/Linux
./GigLine.sh -windowed -ResX=1280 -ResY=720 -nosplash -qaselftest
# then read <archive>/Linux/GigLine/Saved/Logs/GigLine.log for "GigLine QA:" lines
-qaselftest walks for 2 s, resets, pauses/unpauses, sweeps a 16-row seam transect, fires a ground-referenced 21 m wall probe along the street, fires 40 m façade-occlusion traces sideways from the road centre wherever a building is staged, and writes a frame-time series to Saved/Profiling/. Every phase logs ... PASS/FAIL and the run ends with RESULT.
Traps that cost real time in 0.1.x
| Symptom | Cause | Fix |
|---|---|---|
| A builder reports success but the asset is unchanged | .blend/.umap are LFS-tracked and check out read-only; Blender and Unreal fail the save quietly |
chmod u+w <file> first — ue_build_*/ue_hero_facade_import and every Blender builder need it |
File format is not supported when reopening a .blend |
hero_facade_build.py --out writes the FBX; putting the .blend path there overwrites it with FBX bytes |
--out /tmp/…fbx --save-blend Art/…blend --report Art/…json |
Add-on not loaded: "bl_ext.blender_org.mpfb" |
mpfb_character_export.py needs the MPFB add-on visible to Blender |
export BLENDER_USER_SCRIPTS (see the invocation in ../Art/blender/README.md) |
| The packaged run exits after a couple of seconds during QA | GigLineShotActor runs its screenshot list and quits (bQuitWhenDone) |
it skips its rounds when -qaselftest is on the command line — keep that guard |
Headless -nullrhi traces report no hits for everything |
the null RHI has no physics scene | verify traces in the packaged run (-qaselftest), never in a commandlet |
| Import logs "No smoothing group information" for every mesh | mesh_smooth_type="OFF" in the FBX export |
use Tools/fbx_export_preset.py (FACE) |
PIE input test (compare editor vs packaged input intake)
Use to isolate whether the "no controls respond" bug is the packaged standalone's input intake or the Enhanced Input wiring generally.
Tools/run_pie.shopens the editor on/Game/Hollywood/DemoMap. Press the green Play (PIE) button and walk / mouse-look.- Interpretation:
- PIE works -> the Enhanced Input wiring is fine and the standalone packaged build's SDL input intake is the environment-dependent bug.
- PIE fails too -> the Enhanced Input setup itself is broken; rebuild the input config / character from scratch.
- The DemoMap is PIE-ready as committed:
GlobalDefaultGameMode+GameDefaultMap=/Game/Hollywood/DemoMap, and the map stages a PlayerStart at(-13336,-1150,600)on the cut sidewalk with the walkableAGigLineCharacter.