diff --git a/AGENTS.md b/AGENTS.md index 473577b..3aa4450 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -101,7 +101,7 @@ Any change that affects the game's appearance — meshes, materials, lighting, l 1. Run `Tools/render_screenshots.sh` (rebuilds `Game/GigLine/Content/Test/ReviewMap.umap` from current content, runs the game on it, captures the fixed camera list, copies the PNGs into `Screenshots/`). 2. Update `Screenshots/README.md`: one row per screenshot with what it shows and an approval state; describe any new shots or scene changes in the same change. 3. The PNGs **are committed** so reviewers see exactly what the build rendered (`.gitignore` does not exclude them). Keep them in sync with this README: drop retired shots in the same change. -4. Wait for the user's approval before treating a visual change as done; record approval by ticking the table in `Screenshots/README.md`. +4. Wait for the user's approval before treating a visual change as done; record approval by ticking the entry in `Screenshots/README.md`. New content that needs a different camera angle gets a new entry in the shot list in `Tools/ue_build_review_map.py`. diff --git a/Game/GigLine/Content/Hollywood/DemoMap.umap b/Game/GigLine/Content/Hollywood/DemoMap.umap index 5230027..97dc8de 100644 --- a/Game/GigLine/Content/Hollywood/DemoMap.umap +++ b/Game/GigLine/Content/Hollywood/DemoMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68526b7095cfca222b500ff6968eb687ad1771cb31d0a58cbb7dace518968210 -size 32372 +oid sha256:2a2b7a61aa8b3c86c3944849107aa00d3ab6fa0d35056d50b02a65acbd4854a1 +size 33816 diff --git a/Game/GigLine/Content/Test/ReviewMap.umap b/Game/GigLine/Content/Test/ReviewMap.umap index 816d9a2..8db2af7 100644 --- a/Game/GigLine/Content/Test/ReviewMap.umap +++ b/Game/GigLine/Content/Test/ReviewMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:208a1670a337ad19c75ee4b58bfd997dc6018f770ea9edaf85680f6bf723f10c -size 32736 +oid sha256:4d399b3e1b28616e58f445fca8a7de82e9bf1df7c4308500473fc0c63d6d597d +size 28613 diff --git a/MEMORY.md b/MEMORY.md index 525addd..76159ab 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -164,3 +164,9 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO. - **`*.blend` and `*.umap` are LFS-lockable in `.gitattributes`** — Git LFS checks them out read-only (444). `bpy.ops.wm.save_as_mainfile` then fails ("path is not writable") and `EditorLoadingAndSavingUtils.save_map` silently returns False. All Blender builders now chmod u+w before saving and treat a failed save as fatal; the UE map builders chmod the .umap first. A failed save used to leave downstream steps building from stale files — that produced a degenerate-mesh FBX (all-same vertex indices from an index-arithmetic bug) that cost an hour to trace. - **FBX SDK refuses to triangulate the crown-twisted crossing quads** ("unable to triangulate mesh ... will be omitted") — emit triangles from the builder, and make sure per-stripe vertex indices advance (`len(verts)` must be captured before the loop, not per-corner). - Demo-map coordinate note: UE Y is south-positive; the facade at Y −1450 and the player start at Y −3500 are on opposite sides of the road (Y −1382..+1047) — arrangement is correct; the Sidewalk_North/South mesh names are swapped relative to their physical sides (documented in export_site_fbx.py). + +## 2026-11-07 — ReviewMap corruption: deprecated level calls + save-order bug + +- **`EditorLevelLibrary.load_level`/`new_level` are deprecated no-ops in `-nullrhi` commandlets** (they return without switching worlds, so staged actors land in whatever world is current and get saved over the wrong map). Use the `LevelEditorSubsystem`: `unreal.get_editor_subsystem(unreal.LevelEditorSubsystem).load_level(path)` actually switches. Symptom was ReviewMap containing Demo actors + `ShotSequencer`. +- **Map-save ordering bug in `Tools/ue_build_review_map.py`**: the script saved ReviewMap *after* the DemoMap section, but the switch back to ReviewMap fails silently because the map only exists in memory at that point — so the final `save_map` wrote the demo world over ReviewMap. Fix: save ReviewMap first, then stage the demo cameras, and never switch back. Both maps verified by probe (ReviewMap lists Review actors; DemoMap lists Demo actors). +- Rebuilt ReviewMap after the fixes: character, both cubes (A grounded, B floating at 2 m), pawn, NPC prefab, hero facade all present; user re-approved the shots. README cube naming corrected (README had A/B swapped vs the script). diff --git a/Screenshots/README.md b/Screenshots/README.md index 82d5528..a022080 100644 --- a/Screenshots/README.md +++ b/Screenshots/README.md @@ -20,14 +20,15 @@ and exits — about a minute. The camera list lives in ## Scene conventions - **Floor**: 160 m square, top face at Z 0. The character measures Z 0..83 cm. -- **Cubes**: `Cube_ScaleTest_A` floats at Z 2 m, `Cube_ScaleTest_B` rests on the - floor; both are exactly 1 m — the scale reference. +- **Cubes**: `Cube_ScaleTest_A` rests on the floor, `Cube_ScaleTest_B` floats at + Z 2 m; both are exactly 1 m — the scale reference. - **Lighting**: one warm key light plus sky fill (review rig, not the `0.1.0` daytime look). Beyond the floor is open: the horizon is a black band. ## Review-map shots -All ☑ approved 2026-11-07 unless noted. `review-npc-prefab` is new (☐ pending). +All ☑ approved 2026-11-07 (re-rendered with the character and cubes restored; +user visual check passed). > Naming: shots use their stable `Tools/ue_build_review_map.py` camera name (no > index prefix), so adding or reordering cameras never renumbers files or @@ -54,7 +55,7 @@ Rendered from `/Game/Hollywood/DemoMap`, the walkable level. Click an image for | --- | --- | --- | --- | | `demo/review-demo-spawn-view.png` | [spawn view](demo/review-demo-spawn-view.png) | ☑ | Spawn view: north sidewalk, the hero façade across the road | | `demo/review-demo-street-level.png` | [street level](demo/review-demo-street-level.png) | ☑ | Street level: portals, flights, banners, colonnade | -| `demo/review-demo-crossing.png` | [crossing](demo/review-demo-crossing.png) | needs review | The designated mid-block crossing (s=130 m): zebra markings on the road, kerbs flushed to ramps. Camera on the north sidewalk looking south-west. Note: the road renders near-black in shadow — the fixed-daytime-lighting item, not the markings | +| `demo/review-demo-crossing.png` | [crossing](demo/review-demo-crossing.png) | ☑ | The designated mid-block crossing (s=130 m): zebra markings on the road, kerbs flushed to ramps. Camera on the north sidewalk looking south-west. Note: the road renders near-black in shadow — the fixed-daytime-lighting item, not the markings | | `demo/review-demo-north-buildings.png` | [north buildings](demo/review-demo-north-buildings.png) | ☑ | North-side background buildings (TCL, Tussaud's) across the Blvd | ## What to look for diff --git a/Screenshots/demo/review-demo-crossing.png b/Screenshots/demo/review-demo-crossing.png index 408995a..041f7ed 100644 --- a/Screenshots/demo/review-demo-crossing.png +++ b/Screenshots/demo/review-demo-crossing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7791340703cf239fa953504f2b38ce6a96ec131e35e622078acb51d0957e763 -size 1292359 +oid sha256:b6bd66678c132a8fa09004f2f2e3d160b1c99122e1d1365932d7e31ed0933199 +size 1628670 diff --git a/Screenshots/demo/review-demo-north-buildings.png b/Screenshots/demo/review-demo-north-buildings.png index b39fbc2..137a99a 100644 --- a/Screenshots/demo/review-demo-north-buildings.png +++ b/Screenshots/demo/review-demo-north-buildings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95f580993db879516ee1f4f243b6cd00abad523d10cf23b1cb1a39324365de05 -size 1775921 +oid sha256:5eaa60227e5f6e307e1bf878b33d3f52634e0121dcaa6af73afd7fff5728499b +size 2304425 diff --git a/Screenshots/demo/review-demo-spawn-view.png b/Screenshots/demo/review-demo-spawn-view.png index c965b34..9132d32 100644 --- a/Screenshots/demo/review-demo-spawn-view.png +++ b/Screenshots/demo/review-demo-spawn-view.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:788f71de1bf5080c738da6d94170e3d5a577823cd33aa5a10dd892f39b41518f -size 2585447 +oid sha256:a312b5ee86cd5c9fef8b686d2aae429199f88caae7276d6fb714d1d73fed996a +size 2571043 diff --git a/Screenshots/demo/review-demo-street-level.png b/Screenshots/demo/review-demo-street-level.png index 67951c1..86a9834 100644 --- a/Screenshots/demo/review-demo-street-level.png +++ b/Screenshots/demo/review-demo-street-level.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:292f503ebbd786d87c44ad2a98ef5458bef582134c59c34ae5cfd24331268ba6 -size 1932918 +oid sha256:2675eb353573003961c8d81ba24c2bbbe1f1052c11c4ee38cd786cab7115b686 +size 1975605 diff --git a/Screenshots/review-character.png b/Screenshots/review-character.png index dfb05f8..b550695 100644 --- a/Screenshots/review-character.png +++ b/Screenshots/review-character.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f7e7731e6228ba7954947545a02066e415989a8bf2aab96c4113891a78221d7 -size 2202483 +oid sha256:ea60ed98f688bab482160386d851b39a10868c64bf1371b3628427cc25a3de97 +size 2498425 diff --git a/Screenshots/review-ground-contact.png b/Screenshots/review-ground-contact.png index 516451f..2c74a02 100644 --- a/Screenshots/review-ground-contact.png +++ b/Screenshots/review-ground-contact.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c20c78e6c9a109dea7e0aafd0ec9cfe799ca5cf5961398c3a369481ac675af2 -size 1705468 +oid sha256:03b47847338f6d840e1e2dd370fce585c599cd72db0cf1393b82cc91964619c0 +size 1778455 diff --git a/Screenshots/review-hero-facade-front.png b/Screenshots/review-hero-facade-front.png index e267105..564b65c 100644 --- a/Screenshots/review-hero-facade-front.png +++ b/Screenshots/review-hero-facade-front.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3369c4eccf8902a9e84056b0fe419735b29983d08ae26ba112374cf601c15df0 -size 2304244 +oid sha256:fabcc154b139f35e0c6910f87a042c6cc51b9e263993cbfb49a15fa3817736d3 +size 2052242 diff --git a/Screenshots/review-hero-facade-oblique.png b/Screenshots/review-hero-facade-oblique.png index 3a7cee3..07d778c 100644 --- a/Screenshots/review-hero-facade-oblique.png +++ b/Screenshots/review-hero-facade-oblique.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a77f2f03eee7a351713937387cdb2dafe590e607f3960c18c31d600d2f9c7d47 -size 2404004 +oid sha256:20a85e17ab952b5f8de52556bbe9bf7b4dfb03c7e430a371eafa625b0874b4d7 +size 1917582 diff --git a/Screenshots/review-hero-portals.png b/Screenshots/review-hero-portals.png index 5db95d1..69194a1 100644 --- a/Screenshots/review-hero-portals.png +++ b/Screenshots/review-hero-portals.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c65c6f974a5ef490a0da4a36fd8d237211d3efa0540040eb0ef3bca4a7d137 -size 1794383 +oid sha256:8fa065612a714476d37f5cc4bb28182b30dc9b10cfcfd37cc04257d177b41f33 +size 1774919 diff --git a/Screenshots/review-npc-prefab.png b/Screenshots/review-npc-prefab.png index 42230dd..b10ff0f 100644 --- a/Screenshots/review-npc-prefab.png +++ b/Screenshots/review-npc-prefab.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a52cf51af9cfb70e788c0e6d81cb33737380bc8c3adb4f72a9c8c2ef9aa74f5 -size 1660515 +oid sha256:c1522a746881f69e8fb2e327610ad9fd7d98e673c200ea8d781daab1f23317cc +size 1721860 diff --git a/Screenshots/review-overview.png b/Screenshots/review-overview.png index 9a2acc1..d518bc4 100644 --- a/Screenshots/review-overview.png +++ b/Screenshots/review-overview.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:068f9cd7209a02f9e6e1f6c6babfefa43507992600eb7086fbea9792367bb379 -size 2127805 +oid sha256:78b318299a7633fb267c961ecfd61f5fe7a0a3278d28103b634d21f47bc01c49 +size 2580045 diff --git a/Screenshots/review-player-placement.png b/Screenshots/review-player-placement.png index a256838..f39f1df 100644 --- a/Screenshots/review-player-placement.png +++ b/Screenshots/review-player-placement.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b766e74af88547fe201766bc118bbea70b478e9f7ff9f9ac4251343bd39fb8e -size 1847345 +oid sha256:605fc1ee8ef167a57d119ef83e741ab1e6d8fbba923bfe5aa162f0dda1069830 +size 1969709 diff --git a/Screenshots/review-scale-cubes.png b/Screenshots/review-scale-cubes.png index f6cf6ae..8fc47eb 100644 --- a/Screenshots/review-scale-cubes.png +++ b/Screenshots/review-scale-cubes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0c2a93e30216c76e7db5ad28ce9b0e580cfcd8c269b1494cdc65b6ce57b788a -size 2066648 +oid sha256:26c64adad9f64789c85882a224d402ae4e8ca20eb73736731925972275fc560d +size 1906660 diff --git a/Screenshots/review-shadow-compare.png b/Screenshots/review-shadow-compare.png index cb38caa..2d975fa 100644 --- a/Screenshots/review-shadow-compare.png +++ b/Screenshots/review-shadow-compare.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e708d4d8b765ec270b57af26a1134ccd7fcc34d55123634599a316d8dc9d4327 -size 2052859 +oid sha256:bab0f21cc8a6c90889e0003510b7df68f6f23d16e69e9ba08faec40deef77c8b +size 1735259 diff --git a/TODO.md b/TODO.md index 6d25537..9b78b7c 100644 --- a/TODO.md +++ b/TODO.md @@ -75,7 +75,7 @@ The MPFB character asset is planned as the NPC template (see `ROADMAP.md`). Keep - [x] Give the MPFB character asset a standing idle pose so review and NPC shots show a person, not an A-pose bind. Done: `Tools/mpfb_character_export.py --pose idle` folds the A/T-bind arms down to a relaxed standing rest pose (baked via `pose.armature_apply` before export; `upperarm01.L` rest z −0.71 → −1.91 rad), re-exported, re-imported (138 bones), rendered in `review-01-character`. - [x] Bake a second skin tone or clothing layer, so the character does not read as a grey mannequin in shots. Done: the v2-skin bake came out **black** and slow at 1024², so we synthesize a warm skin-tone diffuse directly (`Tools/mpfb_character_export.py` `make_diffuse`, with a darker shorts-suggestive bottom band) via a stdlib/numpy PNG writer. Character reads warm, not grey. Screenshot approved (`Screenshots/review-01-character`). -- [x] Keep the character as a reusable NPC prefab: a visible body, a collision capsule, and a head-height check that the camera does not clip at 1.60 m — for when NPCs/pedestrians are wired in (`0.2.0+`), not the `0.1.0` player. Done 2026-11-07: `AGigLineNPCPerson` (C++), ACharacter with capsule half-height 83 cm / total 1.66 m (head at ~1.66 m, so a 1.60 m camera does not clip), the MPFB human on the built-in mesh as the visible body, `AutoPossessAI` for pedestrians; confirmed spawned feet-on-Z-0 and rendered in `Screenshots/review-npc-prefab` (☐ pending approval). +- [x] Keep the character as a reusable NPC prefab: a visible body, a collision capsule, and a head-height check that the camera does not clip at 1.60 m — for when NPCs/pedestrians are wired in (`0.2.0+`), not the `0.1.0` player. Done 2026-11-07: `AGigLineNPCPerson` (C++), ACharacter with capsule half-height 83 cm / total 1.66 m (head at ~1.66 m, so a 1.60 m camera does not clip), the MPFB human on the built-in mesh as the visible body, `AutoPossessAI` for pedestrians; confirmed spawned feet-on-Z-0 and rendered in `Screenshots/review-npc-prefab` (☑ approved 2026-11-07). - [x] Screenshots use stable camera names (no index prefix), so inserting a shot no longer renumbers/ orphans files; `AGigLineShotActor` + `Screenshots/README.md` updated. ### Asset production @@ -93,8 +93,8 @@ The MPFB character asset is planned as the NPC template (see `ROADMAP.md`). Keep - [x] First-person movement, mouse look, and Enhanced Input bindings. Implemented 2026-11-07: `AGigLineCharacter` (C++, 1.75 m capsule, 1.60 m eye camera, 4 m/s walk, mouse look in deg/s, jump) as the default pawn, with five actions and an 11-entry context in `/Game/Input` built by `Tools/ue_create_input_assets.py`. **Not yet confirmed interactively** — launch PIE on `Test/ReviewMap` and walk. Screenshot review pending (`Screenshots/README.md`). - [~] Collision, reset, and pause functionality. Reset (**R**) and pause (**Escape**, a real game pause that releases the cursor) are implemented in `AGigLineCharacter` with `/Game/Input/IA_Reset` and `IA_Pause`. Collision now exists — terrain, road and sidewalks import as complex-as-simple, so a simple hull cannot ramp over the kerbs. **Not verified by hand**: walk, reset and pause need a human at the keyboard. No pause menu widget yet, only the pause itself. -- [-] Build the walkable demo level: terrain, street, and hero facade assembled into one map with a start point on the north sidewalk, so the demo is something a player can walk rather than a review staging. **Built 2026-11-07** by `Tools/ue_build_demo_map.py` → `/Game/Hollywood/DemoMap`: sun/sky, `Hero_Facade`, six site meshes imported with collision (`Terrain_DEM`, `Road_Hollywood`, both sidewalks and both kerbs), and a `Demo_PlayerStart` on the north sidewalk 20 m back from the frontage. Demo views in `Screenshots/demo/` are ☐ pending review. -- [x] Walkable sidewalks and a designated street crossing. Crossing chosen: mid-block signalised crossing, OSM way 385648319, at 130 m along the block (`Geo/verification/2026-11-06-street-profile.md`). Done 2026-11-07: continental zebra markings (0.5 m bars / 0.5 m gaps, 3 m band) at all three signalised crossings, no collision on the paint; kerbs were already flushed at the crossings. Enablers found on the way: the street surfaces were 100 % down-facing (invisible in engine) — winding flipped; the terrain buried the street — 10.7 m corridor cut around the centreline (sidewalks cover the transition, walk-check 0 holes); LFS-lockable `.blend`/`.umap` check out read-only — builders now chmod before saving and fail loudly. Screenshot review pending (`Screenshots/demo/review-demo-crossing`); the corridor renders near-black in shadow — that is the still-open **Fixed daytime lighting** item, not the crossing. +- [-] Build the walkable demo level: terrain, street, and hero facade assembled into one map with a start point on the north sidewalk, so the demo is something a player can walk rather than a review staging. **Built 2026-11-07** by `Tools/ue_build_demo_map.py` → `/Game/Hollywood/DemoMap`: sun/sky, `Hero_Facade`, six site meshes imported with collision (`Terrain_DEM`, `Road_Hollywood`, both sidewalks and both kerbs), and a `Demo_PlayerStart` on the north sidewalk 20 m back from the frontage. Demo views in `Screenshots/demo/` re-rendered and ☑ approved 2026-11-07. +- [x] Walkable sidewalks and a designated street crossing. Crossing chosen: mid-block signalised crossing, OSM way 385648319, at 130 m along the block (`Geo/verification/2026-11-06-street-profile.md`). Done 2026-11-07: continental zebra markings (0.5 m bars / 0.5 m gaps, 3 m band) at all three signalised crossings, no collision on the paint; kerbs were already flushed at the crossings. Enablers found on the way: the street surfaces were 100 % down-facing (invisible in engine) — winding flipped; the terrain buried the street — 10.7 m corridor cut around the centreline (sidewalks cover the transition, walk-check 0 holes); LFS-lockable `.blend`/`.umap` check out read-only — builders now chmod before saving and fail loudly. Screenshot ☑ approved 2026-11-07 (`Screenshots/demo/review-demo-crossing`); the corridor renders near-black in shadow — that is the still-open **Fixed daytime lighting** item, not the crossing. - [ ] Fixed daytime lighting and basic ambience. - [ ] Geographic attribution display ("© OpenStreetMap contributors" + license link). diff --git a/Tools/ue_build_demo_map.py b/Tools/ue_build_demo_map.py index 8e6a6a7..a79107d 100644 --- a/Tools/ue_build_demo_map.py +++ b/Tools/ue_build_demo_map.py @@ -24,6 +24,16 @@ RESULT = "/tmp/gigline/demo-map.txt" lines = [] +# EditorLevelLibrary.load_level/new_level are deprecated no-ops in -nullrhi +# commandlets (they return without switching worlds, so staged actors land in +# whatever world is current and get saved over the wrong map). The +# LevelEditorSubsystem actually switches. +LES = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem) + + +def switch_level(path): + return LES.load_level(path) + def log(msg): lines.append(str(msg)) unreal.log(str(msg)) @@ -53,11 +63,11 @@ def clear(prefixes=()): def build(): # --- level ------------------------------------------------------------ if unreal.EditorAssetLibrary.does_asset_exist(MAP): - if not unreal.EditorLevelLibrary.load_level(MAP): + if not switch_level(MAP): log(f"could not load {MAP}") return else: - if not unreal.EditorLevelLibrary.new_level(MAP): + if not switch_level(MAP): log(f"could not create {MAP}") return diff --git a/Tools/ue_build_review_map.py b/Tools/ue_build_review_map.py index 950175f..bd48a94 100644 --- a/Tools/ue_build_review_map.py +++ b/Tools/ue_build_review_map.py @@ -21,6 +21,16 @@ MAP_PATH = "/Game/Test/ReviewMap" lines = [] +# EditorLevelLibrary.load_level/new_level are deprecated no-ops in -nullrhi +# commandlets (they return without switching worlds, so staged actors land in +# whatever world is current and get saved over the wrong map). The +# LevelEditorSubsystem actually switches. +LES = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem) + + +def switch_level(path): + return LES.load_level(path) + def log(msg): lines.append(str(msg)) @@ -211,13 +221,33 @@ try: # oblique from the north-west, reading the colonnade in depth ("hero-facade-oblique", unreal.Vector(hero_x - 2200, -3400, 620), unreal.Vector(hero_x + 300, hero_y, 700)), ] + # --- review shot cameras + save ------------------------------------------- + # Order matters: the review scene is staged in the default (unsaved) world. + # Save it as ReviewMap BEFORE touching DemoMap — switching back to a map + # that only exists in memory fails silently, and the final save would then + # write the demo world over ReviewMap (this exact corruption happened once). + shots = spawn(unreal.GigLineShotActor, unreal.Vector(0, 0, 300), "ShotSequencer") + if shots: + shots.set_editor_property("shot_locations", [c[1] for c in cams]) + shots.set_editor_property( + "shot_rotations", + [unreal.MathLibrary.find_look_at_rotation(c[1], c[2]) for c in cams]) + shots.set_editor_property("shot_names", [c[0] for c in cams]) + shots.set_editor_property("quit_when_done", True) + log(f"staged: ShotSequencer with {len(cams)} cameras: {', '.join(c[0] for c in cams)}") + + ensure_writable(MAP_PATH) + saved = unreal.EditorLoadingAndSavingUtils.save_map( + unreal.EditorLevelLibrary.get_editor_world(), MAP_PATH) + log(f"save_map {MAP_PATH}: {saved}") + # --- demo map views: what the player actually sees ---------------------- demo = unreal.EditorAssetLibrary.load_asset("/Game/Hollywood/DemoMap") if demo and unreal.EditorAssetLibrary.does_asset_exist("/Game/Hollywood/DemoMap"): # The demo map has terrain, street, sidewalks and the facade; the review - # floor does not. Load it, stage the shot cameras, save, then restore the - # review map so the rest of the run is unaffected. - unreal.EditorLevelLibrary.load_level("/Game/Hollywood/DemoMap") + # floor does not. Load it, stage the shot cameras, save. No switch back: + # the review map is already saved, and the run ends here. + switch_level("/Game/Hollywood/DemoMap") for actor in unreal.EditorLevelLibrary.get_all_level_actors(): if actor.get_actor_label() == "ShotSequencer": unreal.EditorLevelLibrary.destroy_actor(actor) @@ -247,34 +277,10 @@ try: saved = unreal.EditorLoadingAndSavingUtils.save_map( unreal.EditorLevelLibrary.get_editor_world(), "/Game/Hollywood/DemoMap") log(f"demo map staged: {len(demo_shots)} cameras, save {saved}") - unreal.EditorLevelLibrary.load_level("/Game/Test/ReviewMap") - for actor in unreal.EditorLevelLibrary.get_all_level_actors(): - if actor.get_actor_label() == "ShotSequencer": - unreal.EditorLevelLibrary.destroy_actor(actor) else: log("MISSING: /Game/Hollywood/DemoMap (run Tools/ue_build_demo_map.py)") - - shots = spawn(unreal.GigLineShotActor, unreal.Vector(0, 0, 300), "ShotSequencer") - if shots: - shots.set_editor_property("shot_locations", [c[1] for c in cams]) - shots.set_editor_property( - "shot_rotations", - [unreal.MathLibrary.find_look_at_rotation(c[1], c[2]) for c in cams]) - shots.set_editor_property("shot_names", [c[0] for c in cams]) - shots.set_editor_property("quit_when_done", True) - log(f"staged: ShotSequencer with {len(cams)} cameras: {', '.join(c[0] for c in cams)}") except Exception as exc: # noqa log(f"staging failed: {exc!r}") -# --- save -------------------------------------------------------------------- - -try: - ensure_writable(MAP_PATH) - world = unreal.EditorLevelLibrary.get_editor_world() - saved = unreal.EditorLoadingAndSavingUtils.save_map(world, MAP_PATH) - log(f"save_map {MAP_PATH}: {saved}") -except Exception as exc: # noqa - log(f"save_map failed: {exc!r}") - with open(RESULT, "w") as f: f.write("\n".join(lines) + "\n")